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