@messenger-box/platform-server 10.0.3-alpha.50 → 10.0.3-alpha.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/containers/containers.js.map +1 -1
- package/lib/graphql/resolvers/channel-member.d.ts +2 -1
- package/lib/graphql/resolvers/channel-member.js +13 -3
- package/lib/graphql/resolvers/channel-member.js.map +1 -1
- package/lib/graphql/resolvers/channel.d.ts +2 -1
- package/lib/graphql/resolvers/channel.js +260 -126
- package/lib/graphql/resolvers/channel.js.map +1 -1
- package/lib/graphql/resolvers/extended-token-account.d.ts +2 -1
- package/lib/graphql/resolvers/extended-token-account.js +90 -23
- package/lib/graphql/resolvers/extended-token-account.js.map +1 -1
- package/lib/graphql/resolvers/post-thread.js +285 -179
- package/lib/graphql/resolvers/post-thread.js.map +1 -1
- package/lib/graphql/resolvers/post.js +669 -242
- package/lib/graphql/resolvers/post.js.map +1 -1
- package/lib/graphql/resolvers/reaction.d.ts +2 -1
- package/lib/graphql/resolvers/reaction.js +96 -14
- package/lib/graphql/resolvers/reaction.js.map +1 -1
- package/lib/graphql/schema/channel.graphql +331 -39
- package/lib/graphql/schema/channel.graphql.js +1 -1
- package/lib/graphql/schema/post-thread.graphql +157 -21
- package/lib/graphql/schema/post-thread.graphql.js +1 -1
- package/lib/graphql/schema/post.graphql +265 -40
- package/lib/graphql/schema/post.graphql.js +1 -1
- package/lib/graphql/schema/reaction.graphql +71 -13
- package/lib/graphql/schema/reaction.graphql.js +1 -1
- package/lib/graphql/schema/users.graphql +76 -13
- package/lib/graphql/schema/users.graphql.js +1 -1
- package/lib/plugins/channel-moleculer-service.d.ts +21 -1
- package/lib/plugins/channel-moleculer-service.js +417 -115
- package/lib/plugins/channel-moleculer-service.js.map +1 -1
- package/lib/plugins/extended-token-account-moleculer-service.d.ts +25 -1
- package/lib/plugins/extended-token-account-moleculer-service.js +348 -22
- package/lib/plugins/extended-token-account-moleculer-service.js.map +1 -1
- package/lib/plugins/messenger-notification-moleculer-service.d.ts +26 -3
- package/lib/plugins/messenger-notification-moleculer-service.js +403 -57
- package/lib/plugins/messenger-notification-moleculer-service.js.map +1 -1
- package/lib/plugins/post-moleculer-service.d.ts +84 -20
- package/lib/plugins/post-moleculer-service.js +891 -259
- package/lib/plugins/post-moleculer-service.js.map +1 -1
- package/lib/plugins/post-thread-moleculer-service.d.ts +33 -1
- package/lib/plugins/post-thread-moleculer-service.js +320 -13
- package/lib/plugins/post-thread-moleculer-service.js.map +1 -1
- package/lib/services/channel-service.d.ts +185 -33
- package/lib/services/channel-service.js +767 -282
- package/lib/services/channel-service.js.map +1 -1
- package/lib/services/extended-token-account-service.d.ts +127 -14
- package/lib/services/extended-token-account-service.js +459 -52
- package/lib/services/extended-token-account-service.js.map +1 -1
- package/lib/services/messenger-notification-service.d.ts +106 -13
- package/lib/services/messenger-notification-service.js +824 -442
- package/lib/services/messenger-notification-service.js.map +1 -1
- package/lib/services/post-service.d.ts +176 -16
- package/lib/services/post-service.js +553 -119
- package/lib/services/post-service.js.map +1 -1
- package/lib/services/post-thread-service.d.ts +114 -6
- package/lib/services/post-thread-service.js +397 -18
- package/lib/services/post-thread-service.js.map +1 -1
- package/lib/services/proxy-services/channel-microservice.d.ts +4 -3
- package/lib/services/proxy-services/channel-microservice.js +12 -9
- package/lib/services/proxy-services/channel-microservice.js.map +1 -1
- package/lib/services/proxy-services/messenger-notification-microservice.d.ts +128 -8
- package/lib/services/proxy-services/messenger-notification-microservice.js +324 -29
- package/lib/services/proxy-services/messenger-notification-microservice.js.map +1 -1
- package/lib/services/proxy-services/post-microservice.d.ts +186 -13
- package/lib/services/proxy-services/post-microservice.js +543 -59
- package/lib/services/proxy-services/post-microservice.js.map +1 -1
- package/lib/services/proxy-services/post-thread-microservice.d.ts +134 -4
- package/lib/services/proxy-services/post-thread-microservice.js +387 -10
- package/lib/services/proxy-services/post-thread-microservice.js.map +1 -1
- package/lib/services/proxy-services/reaction-microservice.d.ts +161 -3
- package/lib/services/proxy-services/reaction-microservice.js +474 -2
- package/lib/services/proxy-services/reaction-microservice.js.map +1 -1
- package/lib/services/reaction-service.d.ts +124 -4
- package/lib/services/reaction-service.js +415 -3
- package/lib/services/reaction-service.js.map +1 -1
- package/lib/store/models/channel.d.ts +2 -3
- package/lib/store/models/channel.js +169 -71
- package/lib/store/models/channel.js.map +1 -1
- package/lib/store/models/post-thread.d.ts +3 -3
- package/lib/store/models/post-thread.js +96 -14
- package/lib/store/models/post-thread.js.map +1 -1
- package/lib/store/models/post.d.ts +2 -3
- package/lib/store/models/post.js +85 -18
- package/lib/store/models/post.js.map +1 -1
- package/lib/store/models/reaction.d.ts +2 -3
- package/lib/store/models/reaction.js +67 -8
- package/lib/store/models/reaction.js.map +1 -1
- package/lib/store/repositories/channel-repository.d.ts +6 -6
- package/lib/store/repositories/channel-repository.js +5 -2
- package/lib/store/repositories/channel-repository.js.map +1 -1
- package/lib/store/repositories/post-repository.d.ts +6 -6
- package/lib/store/repositories/post-repository.js +5 -2
- package/lib/store/repositories/post-repository.js.map +1 -1
- package/lib/store/repositories/post-thread-repository.d.ts +6 -6
- package/lib/store/repositories/post-thread-repository.js +5 -2
- package/lib/store/repositories/post-thread-repository.js.map +1 -1
- package/lib/store/repositories/reaction-repository.d.ts +6 -6
- package/lib/store/repositories/reaction-repository.js +5 -2
- package/lib/store/repositories/reaction-repository.js.map +1 -1
- package/lib/templates/repositories/ChannelRepository.ts.template +3 -3
- package/lib/templates/repositories/PostRepository.ts.template +3 -3
- package/lib/templates/repositories/PostThreadRepository.ts.template +3 -3
- package/lib/templates/repositories/ReactionRepository.ts.template +3 -4
- package/lib/templates/services/ChannelService.ts.template +277 -38
- package/lib/templates/services/ExtendedTokenAccountService.ts.template +93 -8
- package/lib/templates/services/PostService.ts.template +182 -20
- package/lib/templates/services/PostThreadService.ts.template +100 -5
- package/lib/templates/services/ReactionService.ts.template +129 -2
- package/package.json +3 -3
- package/lib/store/models/common-options.js +0 -20
- package/lib/store/models/common-options.js.map +0 -1
|
@@ -1,129 +1,338 @@
|
|
|
1
|
-
import {Service}from'moleculer';import {MoleculerTopics,SERVER_TYPES}from'common/server';import {ApolloClientMixin}from'@adminide-stack/platform-server';import {
|
|
2
|
-
|
|
1
|
+
import {Service}from'moleculer';import {MoleculerTopics,SERVER_TYPES}from'common/server';import {ApolloClientMixin}from'@adminide-stack/platform-server';import uniqBy from'lodash/uniqBy';import {logger}from'@common-stack/server-core';import {config}from'../config/env-config.js';/**
|
|
2
|
+
* Post Moleculer Service
|
|
3
|
+
* ----------------------
|
|
4
|
+
*
|
|
5
|
+
* This Moleculer service provides comprehensive post management capabilities within
|
|
6
|
+
* the messenger platform ecosystem. It acts as a distributed service layer for
|
|
7
|
+
* handling post creation, file attachments, message threading, real-time notifications,
|
|
8
|
+
* and cross-service communication.
|
|
9
|
+
*
|
|
10
|
+
* Key capabilities:
|
|
11
|
+
* - Post lifecycle management with threading support
|
|
12
|
+
* - File attachment and upload link generation
|
|
13
|
+
* - Real-time message delivery and read receipts
|
|
14
|
+
* - Post thread creation and management
|
|
15
|
+
* - Channel integration and message counting
|
|
16
|
+
* - Event-driven architecture for real-time updates
|
|
17
|
+
* - Distributed service communication via Moleculer
|
|
18
|
+
* - Comprehensive error handling and logging
|
|
19
|
+
*
|
|
20
|
+
* The service integrates with multiple platform components including channels,
|
|
21
|
+
* notifications, file management, and real-time publishing systems to provide
|
|
22
|
+
* a cohesive messaging experience across the platform.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* PostMoleculerService Class
|
|
26
|
+
*
|
|
27
|
+
* Comprehensive Moleculer service for distributed post management operations.
|
|
28
|
+
* Provides event-driven architecture, real-time communication, and seamless
|
|
29
|
+
* integration with other platform services.
|
|
30
|
+
*/
|
|
3
31
|
class PostMoleculerService extends Service {
|
|
4
32
|
postService;
|
|
33
|
+
container;
|
|
5
34
|
constructor(broker, {
|
|
6
|
-
container
|
|
35
|
+
container,
|
|
36
|
+
settings
|
|
7
37
|
}) {
|
|
8
38
|
super(broker);
|
|
39
|
+
this.container = container;
|
|
9
40
|
const topic = MoleculerTopics.PostService;
|
|
10
41
|
this.postService = container.get(SERVER_TYPES.PostService);
|
|
11
42
|
this.pubsub = container.get('PubSub');
|
|
43
|
+
logger.info(`Initializing PostMoleculerService with topic: ${topic}`);
|
|
12
44
|
this.parseServiceSchema({
|
|
13
45
|
name: topic,
|
|
14
|
-
mixins: [ApolloClientMixin
|
|
46
|
+
mixins: [ApolloClientMixin],
|
|
15
47
|
settings: {
|
|
16
48
|
apolloClient: {
|
|
17
49
|
serverUri: config.GRAPHQL_URL
|
|
18
|
-
}
|
|
50
|
+
},
|
|
51
|
+
...settings
|
|
19
52
|
},
|
|
20
53
|
events: {
|
|
54
|
+
/**
|
|
55
|
+
* Handles post thread creation events
|
|
56
|
+
* Publishes real-time updates for thread creation
|
|
57
|
+
*/
|
|
21
58
|
onCreatePostThread: {
|
|
22
59
|
handler: async ctx => {
|
|
23
|
-
|
|
24
|
-
post,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
60
|
+
try {
|
|
61
|
+
logger.debug('Processing post thread creation event', {
|
|
62
|
+
postId: ctx.params.post?.id,
|
|
63
|
+
threadId: ctx.params.postThread?.id,
|
|
64
|
+
channelId: ctx.params.post?.channel
|
|
65
|
+
});
|
|
66
|
+
const {
|
|
67
|
+
post,
|
|
68
|
+
postThread
|
|
69
|
+
} = ctx.params;
|
|
70
|
+
const {
|
|
71
|
+
channel: channelId,
|
|
72
|
+
parentId: postParentId
|
|
73
|
+
} = post;
|
|
74
|
+
const triggerName = `THREAD_CREATED_UPDATED${channelId ? `_${channelId}` : ''}`;
|
|
75
|
+
const triggerPostThreadName = postParentId ? `THREAD_POST_CREATED_${channelId}_${postParentId}` : `POST_CREATED.${channelId}`;
|
|
76
|
+
const publishPromises = [this.pubsub.publish(triggerName, {
|
|
77
|
+
isCreated: true,
|
|
78
|
+
isUpdated: false,
|
|
79
|
+
lastMessage: post,
|
|
80
|
+
data: postThread
|
|
81
|
+
}), this.pubsub.publish(triggerPostThreadName, post), this.pubsub.publish(`THREAD_CREATED_UPDATED${channelId ? `_${channelId}` : ''}${postParentId ? `_${postParentId}` : ''}`, {
|
|
82
|
+
isCreated: true,
|
|
83
|
+
isUpdated: false,
|
|
84
|
+
lastMessage: post,
|
|
85
|
+
data: postThread
|
|
86
|
+
})];
|
|
87
|
+
await Promise.all(publishPromises);
|
|
88
|
+
logger.debug('Post thread creation event processed successfully', {
|
|
89
|
+
postId: post?.id,
|
|
90
|
+
threadId: postThread?.id,
|
|
91
|
+
publishedEvents: publishPromises.length
|
|
92
|
+
});
|
|
93
|
+
} catch (error) {
|
|
94
|
+
logger.error('Error processing post thread creation event: %o', error);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
44
97
|
}
|
|
45
98
|
},
|
|
99
|
+
/**
|
|
100
|
+
* Handles post thread update events
|
|
101
|
+
* Updates thread participants and publishes real-time updates
|
|
102
|
+
*/
|
|
46
103
|
onUpdatePostThread: {
|
|
47
104
|
handler: async ctx => {
|
|
48
|
-
|
|
49
|
-
post,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
105
|
+
try {
|
|
106
|
+
logger.debug('Processing post thread update event', {
|
|
107
|
+
postId: ctx.params.post?.id,
|
|
108
|
+
threadId: ctx.params.postThread?.id,
|
|
109
|
+
accountId: ctx.params.accountId,
|
|
110
|
+
orgId: ctx.params.orgId
|
|
111
|
+
});
|
|
112
|
+
const {
|
|
113
|
+
post,
|
|
114
|
+
postThread,
|
|
115
|
+
accountId,
|
|
116
|
+
role,
|
|
117
|
+
orgId
|
|
118
|
+
} = ctx.params;
|
|
119
|
+
// Build participant list
|
|
120
|
+
const defaultResponder = [{
|
|
121
|
+
user: accountId,
|
|
122
|
+
roles: role,
|
|
123
|
+
orgName: orgId
|
|
124
|
+
}];
|
|
125
|
+
const normalizedParticipants = [...(postThread?.participants || []), ...defaultResponder].map(i => ({
|
|
126
|
+
...i,
|
|
127
|
+
user: i.user.toString()
|
|
128
|
+
}));
|
|
129
|
+
const participants = uniqBy(normalizedParticipants, 'user');
|
|
130
|
+
// Update post thread
|
|
131
|
+
await this.broker.call(`${MoleculerTopics.PostThreadService}.update`, {
|
|
132
|
+
id: postThread.id,
|
|
133
|
+
data: {
|
|
134
|
+
replyCount: postThread.replyCount + 1,
|
|
135
|
+
lastReplyAt: post.createdAt,
|
|
136
|
+
updatedAt: post.createdAt,
|
|
137
|
+
participants
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
// Prepare trigger payload
|
|
141
|
+
const triggerPayload = {
|
|
142
|
+
isCreated: false,
|
|
143
|
+
isUpdated: true,
|
|
144
|
+
lastMessage: post,
|
|
145
|
+
data: postThread ? {
|
|
146
|
+
...postThread,
|
|
147
|
+
replyCount: postThread.replyCount + 1,
|
|
148
|
+
lastReplyAt: post.createdAt,
|
|
149
|
+
updatedAt: post.createdAt,
|
|
150
|
+
participants
|
|
151
|
+
} : {}
|
|
152
|
+
};
|
|
153
|
+
const {
|
|
154
|
+
channel: channelId,
|
|
155
|
+
parentId: postParentId
|
|
156
|
+
} = post;
|
|
157
|
+
const triggerName = `THREAD_CREATED_UPDATED${channelId ? `_${channelId}` : ''}`;
|
|
158
|
+
const triggerPostThreadName = `THREAD_POST_CREATED_${channelId}_${postParentId}`;
|
|
159
|
+
// Publish updates
|
|
160
|
+
await Promise.all([this.pubsub.publish(triggerName, triggerPayload), this.pubsub.publish(triggerPostThreadName, post), this.pubsub.publish(`${triggerName}${postParentId ? `_${postParentId}` : ''}`, triggerPayload)]);
|
|
161
|
+
logger.debug('Post thread update event processed successfully', {
|
|
162
|
+
postId: post?.id,
|
|
163
|
+
threadId: postThread?.id,
|
|
164
|
+
participantCount: participants.length
|
|
165
|
+
});
|
|
166
|
+
} catch (error) {
|
|
167
|
+
logger.error('Error processing post thread update event: %o', error);
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
/**
|
|
173
|
+
* Handles post creation events
|
|
174
|
+
* Triggers real-time notifications and channel updates
|
|
175
|
+
*/
|
|
176
|
+
onPostCreated: {
|
|
177
|
+
handler: async ctx => {
|
|
178
|
+
try {
|
|
179
|
+
logger.debug('Processing post creation event', {
|
|
180
|
+
postId: ctx.params.post?.id,
|
|
181
|
+
channelId: ctx.params.post?.channel,
|
|
182
|
+
authorId: ctx.params.post?.author
|
|
183
|
+
});
|
|
184
|
+
const {
|
|
185
|
+
post,
|
|
186
|
+
userContext
|
|
187
|
+
} = ctx.params;
|
|
188
|
+
// Emit channel update event
|
|
189
|
+
await this.broker.emit('onChannelUpdated', {
|
|
190
|
+
channelId: post.channel,
|
|
191
|
+
lastPostId: post.id,
|
|
192
|
+
lastPostAt: post.createdAt,
|
|
193
|
+
userContext
|
|
194
|
+
});
|
|
195
|
+
logger.debug('Post creation event processed successfully', {
|
|
196
|
+
postId: post?.id,
|
|
197
|
+
channelId: post?.channel
|
|
198
|
+
});
|
|
199
|
+
} catch (error) {
|
|
200
|
+
logger.error('Error processing post creation event: %o', error);
|
|
201
|
+
// Don't throw to prevent breaking post creation
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
/**
|
|
206
|
+
* Handles bulk post processing events
|
|
207
|
+
* Processes multiple posts in batch operations
|
|
208
|
+
*/
|
|
209
|
+
onBulkPostProcess: {
|
|
210
|
+
handler: async ctx => {
|
|
211
|
+
try {
|
|
212
|
+
logger.debug('Processing bulk post operation', {
|
|
213
|
+
postCount: ctx.params.posts?.length,
|
|
214
|
+
operation: ctx.params.operation
|
|
215
|
+
});
|
|
216
|
+
const {
|
|
217
|
+
posts,
|
|
218
|
+
operation,
|
|
219
|
+
userContext
|
|
220
|
+
} = ctx.params;
|
|
221
|
+
for (const post of posts) {
|
|
222
|
+
switch (operation) {
|
|
223
|
+
case 'delete':
|
|
224
|
+
// Use the base service delete method
|
|
225
|
+
await this.postService.delete({
|
|
226
|
+
id: post.id
|
|
227
|
+
});
|
|
228
|
+
break;
|
|
229
|
+
case 'archive':
|
|
230
|
+
// Implementation for archiving posts
|
|
231
|
+
break;
|
|
232
|
+
default:
|
|
233
|
+
logger.warn('Unknown bulk operation', {
|
|
234
|
+
operation
|
|
235
|
+
});
|
|
236
|
+
}
|
|
72
237
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
lastReplyAt: post.createdAt,
|
|
82
|
-
updatedAt: post.createdAt,
|
|
83
|
-
participants
|
|
84
|
-
} : {}
|
|
85
|
-
};
|
|
86
|
-
const {
|
|
87
|
-
channel: channelId,
|
|
88
|
-
parentId: postParentId
|
|
89
|
-
} = post;
|
|
90
|
-
const triggerName = `THREAD_CREATED_UPDATED${channelId ? `_${channelId}` : ''}`;
|
|
91
|
-
const triggerPostThreadName = `THREAD_POST_CREATED_${channelId}_${postParentId}`;
|
|
92
|
-
await Promise.all([this.pubsub.publish(triggerName, triggerPayload), this.pubsub.publish(triggerPostThreadName, post), this.pubsub.publish(`${triggerName}${postParentId ? `_${postParentId}` : ''}`, triggerPayload)]);
|
|
238
|
+
logger.debug('Bulk post operation completed', {
|
|
239
|
+
postCount: posts.length,
|
|
240
|
+
operation
|
|
241
|
+
});
|
|
242
|
+
} catch (error) {
|
|
243
|
+
logger.error('Error processing bulk post operation: %o', error);
|
|
244
|
+
throw error;
|
|
245
|
+
}
|
|
93
246
|
}
|
|
94
247
|
}
|
|
95
248
|
},
|
|
96
249
|
actions: {
|
|
250
|
+
/**
|
|
251
|
+
* Attaches an uploaded file to a post
|
|
252
|
+
*/
|
|
97
253
|
attachUploadedFile: {
|
|
98
254
|
params: {
|
|
99
255
|
postId: 'string',
|
|
100
256
|
createdBy: 'string',
|
|
101
257
|
file: 'object'
|
|
102
258
|
},
|
|
103
|
-
handler(ctx) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
259
|
+
async handler(ctx) {
|
|
260
|
+
try {
|
|
261
|
+
logger.debug('Attaching uploaded file to post', {
|
|
262
|
+
postId: ctx.params.postId,
|
|
263
|
+
createdBy: ctx.params.createdBy,
|
|
264
|
+
fileName: ctx.params.file?.name
|
|
265
|
+
});
|
|
266
|
+
const {
|
|
267
|
+
postId,
|
|
268
|
+
createdBy,
|
|
269
|
+
file
|
|
270
|
+
} = ctx.params;
|
|
271
|
+
const result = await this.postService.attachUploadedFile(postId, file, createdBy);
|
|
272
|
+
if (result instanceof Error) {
|
|
273
|
+
logger.error('Failed to attach uploaded file', {
|
|
274
|
+
postId,
|
|
275
|
+
error: result.message
|
|
276
|
+
});
|
|
277
|
+
throw result;
|
|
278
|
+
}
|
|
279
|
+
logger.debug('File attached successfully', {
|
|
280
|
+
postId,
|
|
281
|
+
fileId: result?.id,
|
|
282
|
+
createdBy
|
|
283
|
+
});
|
|
284
|
+
return result;
|
|
285
|
+
} catch (error) {
|
|
286
|
+
logger.error('Error in attachUploadedFile action: %o', error);
|
|
287
|
+
throw error;
|
|
288
|
+
}
|
|
110
289
|
}
|
|
111
290
|
},
|
|
291
|
+
/**
|
|
292
|
+
* Creates a file upload link for a post
|
|
293
|
+
*/
|
|
112
294
|
createFileUploadLink: {
|
|
113
295
|
params: {
|
|
114
296
|
postId: 'string',
|
|
115
297
|
filename: 'string',
|
|
116
298
|
userId: 'string'
|
|
117
299
|
},
|
|
118
|
-
handler(ctx) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
300
|
+
async handler(ctx) {
|
|
301
|
+
try {
|
|
302
|
+
logger.debug('Creating file upload link', {
|
|
303
|
+
postId: ctx.params.postId,
|
|
304
|
+
filename: ctx.params.filename,
|
|
305
|
+
userId: ctx.params.userId
|
|
306
|
+
});
|
|
307
|
+
const {
|
|
308
|
+
postId,
|
|
309
|
+
filename,
|
|
310
|
+
userId
|
|
311
|
+
} = ctx.params;
|
|
312
|
+
const result = await this.postService.createFileUploadLink(postId, filename, userId);
|
|
313
|
+
if (result instanceof Error) {
|
|
314
|
+
logger.error('Failed to create file upload link', {
|
|
315
|
+
postId,
|
|
316
|
+
filename,
|
|
317
|
+
error: result.message
|
|
318
|
+
});
|
|
319
|
+
throw result;
|
|
320
|
+
}
|
|
321
|
+
logger.debug('File upload link created successfully', {
|
|
322
|
+
postId,
|
|
323
|
+
filename,
|
|
324
|
+
userId
|
|
325
|
+
});
|
|
326
|
+
return result;
|
|
327
|
+
} catch (error) {
|
|
328
|
+
logger.error('Error in createFileUploadLink action: %o', error);
|
|
329
|
+
throw error;
|
|
330
|
+
}
|
|
125
331
|
}
|
|
126
332
|
},
|
|
333
|
+
/**
|
|
334
|
+
* Attaches multiple uploaded files to a post
|
|
335
|
+
*/
|
|
127
336
|
attachUploadedFiles: {
|
|
128
337
|
params: {
|
|
129
338
|
postId: 'string',
|
|
@@ -133,15 +342,41 @@ class PostMoleculerService extends Service {
|
|
|
133
342
|
items: 'object'
|
|
134
343
|
}
|
|
135
344
|
},
|
|
136
|
-
handler(ctx) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
345
|
+
async handler(ctx) {
|
|
346
|
+
try {
|
|
347
|
+
logger.debug('Attaching multiple uploaded files to post', {
|
|
348
|
+
postId: ctx.params.postId,
|
|
349
|
+
createdBy: ctx.params.createdBy,
|
|
350
|
+
fileCount: ctx.params.files?.length
|
|
351
|
+
});
|
|
352
|
+
const {
|
|
353
|
+
postId,
|
|
354
|
+
createdBy,
|
|
355
|
+
files
|
|
356
|
+
} = ctx.params;
|
|
357
|
+
const result = await this.postService.attachUploadedFiles(postId, files, createdBy);
|
|
358
|
+
if (result instanceof Error) {
|
|
359
|
+
logger.error('Failed to attach uploaded files', {
|
|
360
|
+
postId,
|
|
361
|
+
error: result.message
|
|
362
|
+
});
|
|
363
|
+
throw result;
|
|
364
|
+
}
|
|
365
|
+
logger.debug('Files attached successfully', {
|
|
366
|
+
postId,
|
|
367
|
+
fileCount: result?.length,
|
|
368
|
+
createdBy
|
|
369
|
+
});
|
|
370
|
+
return result;
|
|
371
|
+
} catch (error) {
|
|
372
|
+
logger.error('Error in attachUploadedFiles action: %o', error);
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
143
375
|
}
|
|
144
376
|
},
|
|
377
|
+
/**
|
|
378
|
+
* Creates upload links for multiple files
|
|
379
|
+
*/
|
|
145
380
|
createFilesUploadLink: {
|
|
146
381
|
params: {
|
|
147
382
|
postId: 'string',
|
|
@@ -151,121 +386,423 @@ class PostMoleculerService extends Service {
|
|
|
151
386
|
},
|
|
152
387
|
userId: 'string'
|
|
153
388
|
},
|
|
154
|
-
handler(ctx) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
389
|
+
async handler(ctx) {
|
|
390
|
+
try {
|
|
391
|
+
logger.debug('Creating multiple file upload links', {
|
|
392
|
+
postId: ctx.params.postId,
|
|
393
|
+
fileCount: ctx.params.filenames?.length,
|
|
394
|
+
userId: ctx.params.userId
|
|
395
|
+
});
|
|
396
|
+
const {
|
|
397
|
+
postId,
|
|
398
|
+
filenames,
|
|
399
|
+
userId
|
|
400
|
+
} = ctx.params;
|
|
401
|
+
const result = await this.postService.createFilesUploadLink(postId, filenames, userId);
|
|
402
|
+
if (result instanceof Error) {
|
|
403
|
+
logger.error('Failed to create file upload links', {
|
|
404
|
+
postId,
|
|
405
|
+
error: result.message
|
|
406
|
+
});
|
|
407
|
+
throw result;
|
|
408
|
+
}
|
|
409
|
+
logger.debug('File upload links created successfully', {
|
|
410
|
+
postId,
|
|
411
|
+
linkCount: result?.length,
|
|
412
|
+
userId
|
|
413
|
+
});
|
|
414
|
+
return result;
|
|
415
|
+
} catch (error) {
|
|
416
|
+
logger.error('Error in createFilesUploadLink action: %o', error);
|
|
417
|
+
throw error;
|
|
418
|
+
}
|
|
161
419
|
}
|
|
162
420
|
},
|
|
421
|
+
/**
|
|
422
|
+
* Deletes a file by URL
|
|
423
|
+
*/
|
|
163
424
|
deleteFile: {
|
|
164
425
|
params: {
|
|
165
426
|
url: 'string'
|
|
166
427
|
},
|
|
167
|
-
handler(ctx) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
428
|
+
async handler(ctx) {
|
|
429
|
+
try {
|
|
430
|
+
logger.debug('Deleting file', {
|
|
431
|
+
url: ctx.params.url
|
|
432
|
+
});
|
|
433
|
+
const {
|
|
434
|
+
url
|
|
435
|
+
} = ctx.params;
|
|
436
|
+
const result = await this.postService.deleteFile(url);
|
|
437
|
+
if (result instanceof Error) {
|
|
438
|
+
logger.error('Failed to delete file', {
|
|
439
|
+
url,
|
|
440
|
+
error: result.message
|
|
441
|
+
});
|
|
442
|
+
throw result;
|
|
443
|
+
}
|
|
444
|
+
logger.debug('File deleted successfully', {
|
|
445
|
+
url,
|
|
446
|
+
success: result
|
|
447
|
+
});
|
|
448
|
+
return result;
|
|
449
|
+
} catch (error) {
|
|
450
|
+
logger.error('Error in deleteFile action: %o', error);
|
|
451
|
+
throw error;
|
|
452
|
+
}
|
|
172
453
|
}
|
|
173
454
|
},
|
|
455
|
+
/**
|
|
456
|
+
* Marks a message as read
|
|
457
|
+
*/
|
|
174
458
|
readMessage: {
|
|
175
459
|
params: {
|
|
176
460
|
channelId: 'string',
|
|
177
461
|
messageId: 'string',
|
|
178
462
|
user: 'string'
|
|
179
463
|
},
|
|
180
|
-
handler(ctx) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
464
|
+
async handler(ctx) {
|
|
465
|
+
try {
|
|
466
|
+
logger.debug('Marking message as read', {
|
|
467
|
+
channelId: ctx.params.channelId,
|
|
468
|
+
messageId: ctx.params.messageId,
|
|
469
|
+
userId: ctx.params.user
|
|
470
|
+
});
|
|
471
|
+
const {
|
|
472
|
+
user,
|
|
473
|
+
...rest
|
|
474
|
+
} = ctx.params;
|
|
475
|
+
const result = await this.postService.readMessage(rest, user);
|
|
476
|
+
if (result instanceof Error) {
|
|
477
|
+
logger.error('Failed to mark message as read', {
|
|
478
|
+
messageId: rest.messageId,
|
|
479
|
+
error: result.message
|
|
480
|
+
});
|
|
481
|
+
throw result;
|
|
482
|
+
}
|
|
483
|
+
logger.debug('Message marked as read successfully', {
|
|
484
|
+
messageId: rest.messageId,
|
|
485
|
+
userId: user
|
|
486
|
+
});
|
|
487
|
+
return result;
|
|
488
|
+
} catch (error) {
|
|
489
|
+
logger.error('Error in readMessage action: %o', error);
|
|
490
|
+
throw error;
|
|
491
|
+
}
|
|
186
492
|
}
|
|
187
493
|
},
|
|
494
|
+
/**
|
|
495
|
+
* Marks a message as delivered
|
|
496
|
+
*/
|
|
188
497
|
deliverMessage: {
|
|
189
498
|
params: {
|
|
190
499
|
channelId: 'string',
|
|
191
500
|
messageId: 'string',
|
|
192
501
|
user: 'string'
|
|
193
502
|
},
|
|
194
|
-
handler(ctx) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
503
|
+
async handler(ctx) {
|
|
504
|
+
try {
|
|
505
|
+
logger.debug('Marking message as delivered', {
|
|
506
|
+
channelId: ctx.params.channelId,
|
|
507
|
+
messageId: ctx.params.messageId,
|
|
508
|
+
userId: ctx.params.user
|
|
509
|
+
});
|
|
510
|
+
const {
|
|
511
|
+
user,
|
|
512
|
+
...rest
|
|
513
|
+
} = ctx.params;
|
|
514
|
+
const result = await this.postService.deliverMessage(rest, user);
|
|
515
|
+
if (result instanceof Error) {
|
|
516
|
+
logger.error('Failed to mark message as delivered', {
|
|
517
|
+
messageId: rest.messageId,
|
|
518
|
+
error: result.message
|
|
519
|
+
});
|
|
520
|
+
throw result;
|
|
521
|
+
}
|
|
522
|
+
logger.debug('Message marked as delivered successfully', {
|
|
523
|
+
messageId: rest.messageId,
|
|
524
|
+
userId: user
|
|
525
|
+
});
|
|
526
|
+
return result;
|
|
527
|
+
} catch (error) {
|
|
528
|
+
logger.error('Error in deliverMessage action: %o', error);
|
|
529
|
+
throw error;
|
|
530
|
+
}
|
|
200
531
|
}
|
|
201
532
|
},
|
|
533
|
+
/**
|
|
534
|
+
* Creates a post without subscription/real-time publishing
|
|
535
|
+
*/
|
|
202
536
|
createWithoutSubscription: {
|
|
203
537
|
params: {
|
|
204
538
|
data: 'object'
|
|
205
539
|
},
|
|
206
540
|
async handler(ctx) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
541
|
+
try {
|
|
542
|
+
logger.debug('Creating post without subscription', {
|
|
543
|
+
channelId: ctx.params.data?.channel,
|
|
544
|
+
authorId: ctx.params.data?.author
|
|
545
|
+
});
|
|
546
|
+
const {
|
|
547
|
+
data
|
|
548
|
+
} = ctx.params;
|
|
549
|
+
const result = await this.postService.createWithoutSubscription(data);
|
|
550
|
+
if (result instanceof Error) {
|
|
551
|
+
logger.error('Failed to create post without subscription', {
|
|
552
|
+
error: result.message
|
|
553
|
+
});
|
|
554
|
+
throw result;
|
|
555
|
+
}
|
|
556
|
+
logger.debug('Post created successfully without subscription', {
|
|
557
|
+
postId: result?.id,
|
|
558
|
+
channelId: data?.channel
|
|
559
|
+
});
|
|
560
|
+
return result;
|
|
561
|
+
} catch (error) {
|
|
562
|
+
logger.error('Error in createWithoutSubscription action: %o', error);
|
|
563
|
+
throw error;
|
|
564
|
+
}
|
|
211
565
|
}
|
|
212
566
|
},
|
|
567
|
+
/**
|
|
568
|
+
* Creates a post with associated post thread
|
|
569
|
+
*/
|
|
213
570
|
createPostWithPostThread: {
|
|
214
571
|
async handler(ctx) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
author: responderId || accountId,
|
|
233
|
-
files,
|
|
234
|
-
parentId: postParentId,
|
|
235
|
-
props: notificationParams ? {
|
|
572
|
+
try {
|
|
573
|
+
logger.debug('Creating post with post thread', {
|
|
574
|
+
channelId: ctx.params.channelId,
|
|
575
|
+
accountId: ctx.params.accountId,
|
|
576
|
+
postParentId: ctx.params.postParentId
|
|
577
|
+
});
|
|
578
|
+
const {
|
|
579
|
+
threadMessageInput,
|
|
580
|
+
channelId,
|
|
581
|
+
responderId,
|
|
582
|
+
accountId,
|
|
583
|
+
postParentId,
|
|
584
|
+
postId
|
|
585
|
+
} = ctx.params;
|
|
586
|
+
const {
|
|
587
|
+
content,
|
|
588
|
+
files,
|
|
236
589
|
notificationParams
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
590
|
+
} = threadMessageInput;
|
|
591
|
+
const postPayload = {
|
|
592
|
+
channel: channelId,
|
|
593
|
+
message: content,
|
|
594
|
+
editedBy: responderId || accountId,
|
|
595
|
+
author: responderId || accountId,
|
|
596
|
+
files,
|
|
597
|
+
parentId: postParentId,
|
|
598
|
+
props: notificationParams ? {
|
|
599
|
+
notificationParams
|
|
600
|
+
} : undefined
|
|
601
|
+
};
|
|
602
|
+
const post = await this.postService.createWithoutSubscription({
|
|
603
|
+
...(postId ? {
|
|
604
|
+
_id: postId
|
|
605
|
+
} : {}),
|
|
606
|
+
...postPayload
|
|
607
|
+
});
|
|
608
|
+
if (post instanceof Error) {
|
|
609
|
+
logger.error('Failed to create post for post thread', {
|
|
610
|
+
error: post.message
|
|
611
|
+
});
|
|
612
|
+
throw post;
|
|
613
|
+
}
|
|
614
|
+
const postThread = await this.handlePostThreadCreate({
|
|
615
|
+
...ctx.params,
|
|
616
|
+
post: post
|
|
617
|
+
});
|
|
618
|
+
logger.debug('Post with post thread created successfully', {
|
|
619
|
+
postId: post?.id,
|
|
620
|
+
threadId: postThread?.id
|
|
621
|
+
});
|
|
622
|
+
return {
|
|
623
|
+
post,
|
|
624
|
+
postThread
|
|
625
|
+
};
|
|
626
|
+
} catch (error) {
|
|
627
|
+
logger.error('Error in createPostWithPostThread action: %o', error);
|
|
628
|
+
throw error;
|
|
629
|
+
}
|
|
253
630
|
}
|
|
254
631
|
},
|
|
632
|
+
/**
|
|
633
|
+
* Gets the last message in a channel
|
|
634
|
+
*/
|
|
255
635
|
getLastMessage: {
|
|
256
636
|
params: {
|
|
257
637
|
channelId: 'string'
|
|
258
638
|
},
|
|
259
|
-
handler(ctx) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
639
|
+
async handler(ctx) {
|
|
640
|
+
try {
|
|
641
|
+
logger.debug('Getting last message', {
|
|
642
|
+
channelId: ctx.params.channelId
|
|
643
|
+
});
|
|
644
|
+
const {
|
|
645
|
+
channelId
|
|
646
|
+
} = ctx.params;
|
|
647
|
+
const result = await this.postService.getLastMessage(channelId);
|
|
648
|
+
if (result instanceof Error) {
|
|
649
|
+
logger.error('Failed to get last message', {
|
|
650
|
+
channelId,
|
|
651
|
+
error: result.message
|
|
652
|
+
});
|
|
653
|
+
throw result;
|
|
654
|
+
}
|
|
655
|
+
logger.debug('Last message retrieved successfully', {
|
|
656
|
+
channelId,
|
|
657
|
+
postId: result?.id
|
|
658
|
+
});
|
|
659
|
+
return result;
|
|
660
|
+
} catch (error) {
|
|
661
|
+
logger.error('Error in getLastMessage action: %o', error);
|
|
662
|
+
throw error;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
},
|
|
666
|
+
/**
|
|
667
|
+
* Updates a post using base service method
|
|
668
|
+
*/
|
|
669
|
+
updatePost: {
|
|
670
|
+
params: {
|
|
671
|
+
postId: 'string',
|
|
672
|
+
updates: 'object'
|
|
673
|
+
},
|
|
674
|
+
async handler(ctx) {
|
|
675
|
+
try {
|
|
676
|
+
logger.debug('Updating post', {
|
|
677
|
+
postId: ctx.params.postId,
|
|
678
|
+
updateKeys: Object.keys(ctx.params.updates || {})
|
|
679
|
+
});
|
|
680
|
+
const {
|
|
681
|
+
postId,
|
|
682
|
+
updates
|
|
683
|
+
} = ctx.params;
|
|
684
|
+
const result = await this.postService.update(postId, updates);
|
|
685
|
+
logger.debug('Post updated successfully', {
|
|
686
|
+
postId,
|
|
687
|
+
updatedPostId: result?.id
|
|
688
|
+
});
|
|
689
|
+
return result;
|
|
690
|
+
} catch (error) {
|
|
691
|
+
logger.error('Error in updatePost action: %o', error);
|
|
692
|
+
throw error;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
},
|
|
696
|
+
/**
|
|
697
|
+
* Deletes a post using base service method
|
|
698
|
+
*/
|
|
699
|
+
deletePost: {
|
|
700
|
+
params: {
|
|
701
|
+
postId: 'string'
|
|
702
|
+
},
|
|
703
|
+
async handler(ctx) {
|
|
704
|
+
try {
|
|
705
|
+
logger.debug('Deleting post', {
|
|
706
|
+
postId: ctx.params.postId
|
|
707
|
+
});
|
|
708
|
+
const {
|
|
709
|
+
postId
|
|
710
|
+
} = ctx.params;
|
|
711
|
+
const result = await this.postService.delete({
|
|
712
|
+
id: postId
|
|
713
|
+
});
|
|
714
|
+
logger.debug('Post deleted successfully', {
|
|
715
|
+
postId,
|
|
716
|
+
success: result
|
|
717
|
+
});
|
|
718
|
+
return result;
|
|
719
|
+
} catch (error) {
|
|
720
|
+
logger.error('Error in deletePost action: %o', error);
|
|
721
|
+
throw error;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
/**
|
|
726
|
+
* Gets posts by channel using base service methods
|
|
727
|
+
*/
|
|
728
|
+
getPostsByChannel: {
|
|
729
|
+
params: {
|
|
730
|
+
channelId: 'string',
|
|
731
|
+
limit: {
|
|
732
|
+
type: 'number',
|
|
733
|
+
optional: true,
|
|
734
|
+
default: 50
|
|
735
|
+
},
|
|
736
|
+
offset: {
|
|
737
|
+
type: 'number',
|
|
738
|
+
optional: true,
|
|
739
|
+
default: 0
|
|
740
|
+
}
|
|
741
|
+
},
|
|
742
|
+
async handler(ctx) {
|
|
743
|
+
try {
|
|
744
|
+
logger.debug('Getting posts by channel', {
|
|
745
|
+
channelId: ctx.params.channelId,
|
|
746
|
+
limit: ctx.params.limit,
|
|
747
|
+
offset: ctx.params.offset
|
|
748
|
+
});
|
|
749
|
+
const {
|
|
750
|
+
channelId,
|
|
751
|
+
limit,
|
|
752
|
+
offset
|
|
753
|
+
} = ctx.params;
|
|
754
|
+
// Use base service getAll with criteria
|
|
755
|
+
const result = await this.postService.getAll({
|
|
756
|
+
criteria: {
|
|
757
|
+
channel: channelId
|
|
758
|
+
},
|
|
759
|
+
pagination: {
|
|
760
|
+
limit,
|
|
761
|
+
offset
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
logger.debug('Posts retrieved successfully', {
|
|
765
|
+
channelId,
|
|
766
|
+
postCount: result?.length
|
|
767
|
+
});
|
|
768
|
+
return result;
|
|
769
|
+
} catch (error) {
|
|
770
|
+
logger.error('Error in getPostsByChannel action: %o', error);
|
|
771
|
+
throw error;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
},
|
|
775
|
+
/**
|
|
776
|
+
* Health check endpoint
|
|
777
|
+
*/
|
|
778
|
+
healthCheck: {
|
|
779
|
+
async handler(ctx) {
|
|
780
|
+
try {
|
|
781
|
+
logger.debug('Performing post service health check');
|
|
782
|
+
return {
|
|
783
|
+
status: 'healthy',
|
|
784
|
+
timestamp: new Date().toISOString(),
|
|
785
|
+
service: 'PostMoleculerService',
|
|
786
|
+
version: '1.0.0'
|
|
787
|
+
};
|
|
788
|
+
} catch (error) {
|
|
789
|
+
logger.error('Health check failed: %o', error);
|
|
790
|
+
throw error;
|
|
791
|
+
}
|
|
264
792
|
}
|
|
265
793
|
}
|
|
266
794
|
}
|
|
267
795
|
});
|
|
796
|
+
logger.info('PostMoleculerService initialized successfully');
|
|
268
797
|
}
|
|
798
|
+
/**
|
|
799
|
+
* Handles post thread creation logic
|
|
800
|
+
*
|
|
801
|
+
* @description Creates or updates post threads with proper participant management
|
|
802
|
+
*
|
|
803
|
+
* @param {Object} params - Post thread creation parameters
|
|
804
|
+
* @returns {Promise<IPostThread>} - Created or updated post thread
|
|
805
|
+
*/
|
|
269
806
|
async handlePostThreadCreate({
|
|
270
807
|
post,
|
|
271
808
|
responderId,
|
|
@@ -274,58 +811,88 @@ class PostMoleculerService extends Service {
|
|
|
274
811
|
orgId,
|
|
275
812
|
postThreadId
|
|
276
813
|
}) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
const members = channel?.members?.map(m => ({
|
|
294
|
-
user: m?.user,
|
|
295
|
-
orgName: orgId,
|
|
296
|
-
roles: role
|
|
297
|
-
}));
|
|
298
|
-
const defaultResponder = [{
|
|
299
|
-
user: accountId,
|
|
300
|
-
roles: role,
|
|
301
|
-
orgName: orgId
|
|
302
|
-
}];
|
|
303
|
-
const responder = responderId ? [{
|
|
304
|
-
user: responderId,
|
|
305
|
-
roles: role,
|
|
306
|
-
orgName: orgId
|
|
307
|
-
}, ...defaultResponder] : defaultResponder;
|
|
308
|
-
const normalizedParticipants = [...members, ...(postThread?.participants || []), ...responder].map(i => ({
|
|
309
|
-
...i,
|
|
310
|
-
user: i.user.toString()
|
|
311
|
-
}));
|
|
312
|
-
const participants = uniqBy(normalizedParticipants, 'user');
|
|
313
|
-
if (!postParentId && !postThread || postParentId && !postThread) {
|
|
314
|
-
return this.createPostThread({
|
|
315
|
-
post,
|
|
814
|
+
try {
|
|
815
|
+
logger.debug('Handling post thread creation', {
|
|
816
|
+
postId: post?.id,
|
|
817
|
+
accountId,
|
|
818
|
+
orgId,
|
|
819
|
+
hasExistingThread: !!postThreadId
|
|
820
|
+
});
|
|
821
|
+
const {
|
|
822
|
+
role
|
|
823
|
+
} = threadMessageInput;
|
|
824
|
+
const channelId = post.channel?.toString();
|
|
825
|
+
const postParentId = post.parentId?.toString();
|
|
826
|
+
const postThread = await this.getPostThread({
|
|
827
|
+
accountId,
|
|
828
|
+
postThreadId,
|
|
829
|
+
postParentId,
|
|
316
830
|
channelId,
|
|
317
|
-
|
|
318
|
-
|
|
831
|
+
role,
|
|
832
|
+
orgId
|
|
319
833
|
});
|
|
834
|
+
const channel = await this.broker.call(`${MoleculerTopics.ChannelService}.get`, {
|
|
835
|
+
id: channelId
|
|
836
|
+
});
|
|
837
|
+
const members = channel?.members?.map(m => ({
|
|
838
|
+
user: m?.user,
|
|
839
|
+
orgName: orgId,
|
|
840
|
+
roles: role
|
|
841
|
+
}));
|
|
842
|
+
const defaultResponder = [{
|
|
843
|
+
user: accountId,
|
|
844
|
+
roles: role,
|
|
845
|
+
orgName: orgId
|
|
846
|
+
}];
|
|
847
|
+
const responder = responderId ? [{
|
|
848
|
+
user: responderId,
|
|
849
|
+
roles: role,
|
|
850
|
+
orgName: orgId
|
|
851
|
+
}, ...defaultResponder] : defaultResponder;
|
|
852
|
+
const normalizedParticipants = [...(members || []), ...(postThread?.participants || []), ...responder].map(i => ({
|
|
853
|
+
...i,
|
|
854
|
+
user: i.user.toString()
|
|
855
|
+
}));
|
|
856
|
+
const participants = uniqBy(normalizedParticipants, 'user');
|
|
857
|
+
if (!postParentId && !postThread || postParentId && !postThread) {
|
|
858
|
+
const result = await this.createPostThread({
|
|
859
|
+
post,
|
|
860
|
+
channelId,
|
|
861
|
+
participants,
|
|
862
|
+
postParentId: postParentId ? postParentId : post.id
|
|
863
|
+
});
|
|
864
|
+
logger.debug('New post thread created', {
|
|
865
|
+
postId: post?.id,
|
|
866
|
+
threadId: result?.id,
|
|
867
|
+
participantCount: participants.length
|
|
868
|
+
});
|
|
869
|
+
return result;
|
|
870
|
+
}
|
|
871
|
+
const result = await this.dispatchPostEventsWithParentId({
|
|
872
|
+
post,
|
|
873
|
+
postThread,
|
|
874
|
+
accountId,
|
|
875
|
+
orgId,
|
|
876
|
+
role
|
|
877
|
+
});
|
|
878
|
+
logger.debug('Existing post thread updated', {
|
|
879
|
+
postId: post?.id,
|
|
880
|
+
threadId: result?.id
|
|
881
|
+
});
|
|
882
|
+
return result;
|
|
883
|
+
} catch (error) {
|
|
884
|
+
logger.error('Error handling post thread creation: %o', error);
|
|
885
|
+
throw error;
|
|
320
886
|
}
|
|
321
|
-
return this.dispatchPostEventsWithParentId({
|
|
322
|
-
post,
|
|
323
|
-
postThread,
|
|
324
|
-
accountId,
|
|
325
|
-
orgId,
|
|
326
|
-
role
|
|
327
|
-
});
|
|
328
887
|
}
|
|
888
|
+
/**
|
|
889
|
+
* Retrieves a post thread by criteria
|
|
890
|
+
*
|
|
891
|
+
* @description Finds existing post threads based on various criteria
|
|
892
|
+
*
|
|
893
|
+
* @param {Object} params - Search criteria
|
|
894
|
+
* @returns {Promise<IPostThread>} - Found post thread
|
|
895
|
+
*/
|
|
329
896
|
async getPostThread({
|
|
330
897
|
postThreadId,
|
|
331
898
|
channelId,
|
|
@@ -334,31 +901,55 @@ class PostMoleculerService extends Service {
|
|
|
334
901
|
role,
|
|
335
902
|
orgId
|
|
336
903
|
}) {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
904
|
+
try {
|
|
905
|
+
logger.debug('Getting post thread', {
|
|
906
|
+
postThreadId: postThreadId?.id,
|
|
907
|
+
channelId,
|
|
908
|
+
postParentId,
|
|
909
|
+
accountId,
|
|
910
|
+
orgId
|
|
911
|
+
});
|
|
912
|
+
const criteria = {
|
|
913
|
+
...(postThreadId ? {
|
|
914
|
+
_id: postThreadId
|
|
915
|
+
} : {
|
|
916
|
+
channel: channelId,
|
|
917
|
+
post: postParentId,
|
|
918
|
+
participants: {
|
|
919
|
+
$elemMatch: {
|
|
920
|
+
user: accountId,
|
|
921
|
+
...(role ? {
|
|
922
|
+
roles: role
|
|
923
|
+
} : {}),
|
|
924
|
+
...(orgId ? {
|
|
925
|
+
orgName: orgId
|
|
926
|
+
} : {})
|
|
927
|
+
}
|
|
352
928
|
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
929
|
+
})
|
|
930
|
+
};
|
|
931
|
+
const postThreads = await this.broker.call(`${MoleculerTopics.PostThreadService}.getAll`, {
|
|
932
|
+
criteria
|
|
933
|
+
});
|
|
934
|
+
const [postThread] = postThreads ?? [];
|
|
935
|
+
logger.debug('Post thread retrieved', {
|
|
936
|
+
found: !!postThread,
|
|
937
|
+
threadId: postThread?.id
|
|
938
|
+
});
|
|
939
|
+
return postThread;
|
|
940
|
+
} catch (error) {
|
|
941
|
+
logger.error('Error getting post thread: %o', error);
|
|
942
|
+
throw error;
|
|
943
|
+
}
|
|
361
944
|
}
|
|
945
|
+
/**
|
|
946
|
+
* Dispatches post events with parent ID for thread updates
|
|
947
|
+
*
|
|
948
|
+
* @description Handles event dispatching for post thread updates
|
|
949
|
+
*
|
|
950
|
+
* @param {Object} params - Event parameters
|
|
951
|
+
* @returns {Promise<IPostThread>} - Updated post thread
|
|
952
|
+
*/
|
|
362
953
|
async dispatchPostEventsWithParentId({
|
|
363
954
|
post,
|
|
364
955
|
postThread,
|
|
@@ -366,39 +957,80 @@ class PostMoleculerService extends Service {
|
|
|
366
957
|
orgId,
|
|
367
958
|
role
|
|
368
959
|
}) {
|
|
369
|
-
|
|
370
|
-
post,
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
960
|
+
try {
|
|
961
|
+
logger.debug('Dispatching post events with parent ID', {
|
|
962
|
+
postId: post?.id,
|
|
963
|
+
threadId: postThread?.id,
|
|
964
|
+
accountId,
|
|
965
|
+
orgId
|
|
966
|
+
});
|
|
967
|
+
await this.broker.emit('onUpdatePostThread', {
|
|
968
|
+
post,
|
|
969
|
+
postThread,
|
|
970
|
+
accountId,
|
|
971
|
+
orgId,
|
|
972
|
+
role
|
|
973
|
+
});
|
|
974
|
+
const updatedThread = {
|
|
975
|
+
...postThread,
|
|
976
|
+
replyCount: postThread.replyCount + 1,
|
|
977
|
+
lastReplyAt: post.createdAt
|
|
978
|
+
};
|
|
979
|
+
logger.debug('Post events dispatched successfully', {
|
|
980
|
+
postId: post?.id,
|
|
981
|
+
threadId: updatedThread?.id,
|
|
982
|
+
newReplyCount: updatedThread.replyCount
|
|
983
|
+
});
|
|
984
|
+
return updatedThread;
|
|
985
|
+
} catch (error) {
|
|
986
|
+
logger.error('Error dispatching post events: %o', error);
|
|
987
|
+
throw error;
|
|
988
|
+
}
|
|
381
989
|
}
|
|
990
|
+
/**
|
|
991
|
+
* Creates a new post thread
|
|
992
|
+
*
|
|
993
|
+
* @description Creates a new thread for organizing related posts
|
|
994
|
+
*
|
|
995
|
+
* @param {Object} params - Thread creation parameters
|
|
996
|
+
* @returns {Promise<IPostThread>} - Created post thread
|
|
997
|
+
*/
|
|
382
998
|
async createPostThread({
|
|
383
999
|
channelId,
|
|
384
1000
|
postParentId,
|
|
385
1001
|
post,
|
|
386
1002
|
participants
|
|
387
1003
|
}) {
|
|
388
|
-
|
|
389
|
-
post
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
1004
|
+
try {
|
|
1005
|
+
logger.debug('Creating new post thread', {
|
|
1006
|
+
channelId,
|
|
1007
|
+
postParentId,
|
|
1008
|
+
postId: post?.id,
|
|
1009
|
+
participantCount: participants?.length
|
|
1010
|
+
});
|
|
1011
|
+
const postThreadData = {
|
|
1012
|
+
post: postParentId,
|
|
1013
|
+
channel: channelId,
|
|
1014
|
+
replyCount: 0,
|
|
1015
|
+
lastReplyAt: post.createdAt,
|
|
1016
|
+
participants
|
|
1017
|
+
};
|
|
1018
|
+
const postThread = await this.broker.call(`${MoleculerTopics.PostThreadService}.create`, {
|
|
1019
|
+
data: postThreadData
|
|
1020
|
+
});
|
|
1021
|
+
await this.broker.emit('onCreatePostThread', {
|
|
1022
|
+
post,
|
|
1023
|
+
postThread
|
|
1024
|
+
});
|
|
1025
|
+
logger.debug('Post thread created successfully', {
|
|
1026
|
+
threadId: postThread?.id,
|
|
1027
|
+
channelId,
|
|
1028
|
+
postParentId
|
|
1029
|
+
});
|
|
1030
|
+
return postThread;
|
|
1031
|
+
} catch (error) {
|
|
1032
|
+
logger.error('Error creating post thread: %o', error);
|
|
1033
|
+
throw error;
|
|
1034
|
+
}
|
|
403
1035
|
}
|
|
404
1036
|
}export{PostMoleculerService};//# sourceMappingURL=post-moleculer-service.js.map
|