-
-
Notifications
You must be signed in to change notification settings - Fork 158
/
Copy pathMessagingGroupDefinition.cs
173 lines (145 loc) · 7.55 KB
/
MessagingGroupDefinition.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Middleware;
using JsonApiDotNetCore.Resources;
using JsonApiDotNetCore.Resources.Annotations;
using JsonApiDotNetCoreTests.IntegrationTests.Microservices.Messages;
using Microsoft.EntityFrameworkCore;
namespace JsonApiDotNetCoreTests.IntegrationTests.Microservices;
public abstract class MessagingGroupDefinition(
IResourceGraph resourceGraph, DbSet<DomainUser> userSet, DbSet<DomainGroup> groupSet, ResourceDefinitionHitCounter hitCounter)
: HitCountingResourceDefinition<DomainGroup, Guid>(resourceGraph, hitCounter)
{
private readonly DbSet<DomainUser> _userSet = userSet;
private readonly DbSet<DomainGroup> _groupSet = groupSet;
private readonly List<OutgoingMessage> _pendingMessages = [];
private string? _beforeGroupName;
protected override ResourceDefinitionExtensibilityPoints ExtensibilityPointsToTrack => ResourceDefinitionExtensibilityPoints.Writing;
public override async Task OnPrepareWriteAsync(DomainGroup group, WriteOperationKind writeOperation, CancellationToken cancellationToken)
{
await base.OnPrepareWriteAsync(group, writeOperation, cancellationToken);
if (writeOperation == WriteOperationKind.CreateResource)
{
group.Id = Guid.NewGuid();
}
else if (writeOperation == WriteOperationKind.UpdateResource)
{
_beforeGroupName = group.Name;
}
}
public override async Task OnSetToManyRelationshipAsync(DomainGroup group, HasManyAttribute hasManyRelationship, ISet<IIdentifiable> rightResourceIds,
WriteOperationKind writeOperation, CancellationToken cancellationToken)
{
await base.OnSetToManyRelationshipAsync(group, hasManyRelationship, rightResourceIds, writeOperation, cancellationToken);
if (hasManyRelationship.Property.Name == nameof(DomainGroup.Users))
{
HashSet<Guid> rightUserIds = rightResourceIds.Select(resource => (Guid)resource.GetTypedId()).ToHashSet();
List<DomainUser> beforeUsers = await _userSet.Include(user => user.Group).Where(user => rightUserIds.Contains(user.Id))
.ToListAsync(cancellationToken);
foreach (DomainUser beforeUser in beforeUsers)
{
IMessageContent? content = null;
if (beforeUser.Group == null)
{
content = new UserAddedToGroupContent(beforeUser.Id, group.Id);
}
else if (beforeUser.Group != null && beforeUser.Group.Id != group.Id)
{
content = new UserMovedToGroupContent(beforeUser.Id, beforeUser.Group.Id, group.Id);
}
if (content != null)
{
var message = OutgoingMessage.CreateFromContent(content);
_pendingMessages.Add(message);
}
}
foreach (DomainUser userToRemoveFromGroup in group.Users.Where(user => !rightUserIds.Contains(user.Id)))
{
var content = new UserRemovedFromGroupContent(userToRemoveFromGroup.Id, group.Id);
var message = OutgoingMessage.CreateFromContent(content);
_pendingMessages.Add(message);
}
}
}
public override async Task OnAddToRelationshipAsync(DomainGroup group, HasManyAttribute hasManyRelationship, ISet<IIdentifiable> rightResourceIds,
CancellationToken cancellationToken)
{
await base.OnAddToRelationshipAsync(group, hasManyRelationship, rightResourceIds, cancellationToken);
if (hasManyRelationship.Property.Name == nameof(DomainGroup.Users))
{
HashSet<Guid> rightUserIds = rightResourceIds.Select(resource => (Guid)resource.GetTypedId()).ToHashSet();
List<DomainUser> beforeUsers = await _userSet.Include(user => user.Group).Where(user => rightUserIds.Contains(user.Id))
.ToListAsync(cancellationToken);
foreach (DomainUser beforeUser in beforeUsers)
{
IMessageContent? content = null;
if (beforeUser.Group == null)
{
content = new UserAddedToGroupContent(beforeUser.Id, group.Id);
}
else if (beforeUser.Group != null && beforeUser.Group.Id != group.Id)
{
content = new UserMovedToGroupContent(beforeUser.Id, beforeUser.Group.Id, group.Id);
}
if (content != null)
{
var message = OutgoingMessage.CreateFromContent(content);
_pendingMessages.Add(message);
}
}
}
}
public override async Task OnRemoveFromRelationshipAsync(DomainGroup group, HasManyAttribute hasManyRelationship, ISet<IIdentifiable> rightResourceIds,
CancellationToken cancellationToken)
{
await base.OnRemoveFromRelationshipAsync(group, hasManyRelationship, rightResourceIds, cancellationToken);
if (hasManyRelationship.Property.Name == nameof(DomainGroup.Users))
{
HashSet<Guid> rightUserIds = rightResourceIds.Select(resource => (Guid)resource.GetTypedId()).ToHashSet();
foreach (DomainUser userToRemoveFromGroup in group.Users.Where(user => rightUserIds.Contains(user.Id)))
{
var content = new UserRemovedFromGroupContent(userToRemoveFromGroup.Id, group.Id);
var message = OutgoingMessage.CreateFromContent(content);
_pendingMessages.Add(message);
}
}
}
protected async Task FinishWriteAsync(DomainGroup group, WriteOperationKind writeOperation, CancellationToken cancellationToken)
{
if (writeOperation == WriteOperationKind.CreateResource)
{
var message = OutgoingMessage.CreateFromContent(new GroupCreatedContent(group.Id, group.Name));
await FlushMessageAsync(message, cancellationToken);
}
else if (writeOperation == WriteOperationKind.UpdateResource)
{
if (_beforeGroupName != group.Name)
{
var message = OutgoingMessage.CreateFromContent(new GroupRenamedContent(group.Id, _beforeGroupName!, group.Name));
await FlushMessageAsync(message, cancellationToken);
}
}
else if (writeOperation == WriteOperationKind.DeleteResource)
{
DomainGroup? groupToDelete = await GetGroupToDeleteAsync(group.Id, cancellationToken);
if (groupToDelete != null)
{
foreach (DomainUser user in groupToDelete.Users)
{
var removeMessage = OutgoingMessage.CreateFromContent(new UserRemovedFromGroupContent(user.Id, group.Id));
await FlushMessageAsync(removeMessage, cancellationToken);
}
}
var deleteMessage = OutgoingMessage.CreateFromContent(new GroupDeletedContent(group.Id));
await FlushMessageAsync(deleteMessage, cancellationToken);
}
foreach (OutgoingMessage nextMessage in _pendingMessages)
{
await FlushMessageAsync(nextMessage, cancellationToken);
}
}
protected abstract Task FlushMessageAsync(OutgoingMessage message, CancellationToken cancellationToken);
protected virtual async Task<DomainGroup?> GetGroupToDeleteAsync(Guid groupId, CancellationToken cancellationToken)
{
return await _groupSet.Include(group => group.Users).FirstOrDefaultAsync(group => group.Id == groupId, cancellationToken);
}
}