@messenger-box/platform-server 10.0.3-alpha.6 → 10.0.3-alpha.62

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.
Files changed (144) hide show
  1. package/lib/containers/containers.js +3 -1
  2. package/lib/containers/containers.js.map +1 -1
  3. package/lib/containers/context-services-from-container.d.ts +2 -2
  4. package/lib/containers/context-services-from-container.js +2 -1
  5. package/lib/containers/context-services-from-container.js.map +1 -1
  6. package/lib/graphql/resolvers/channel-member.d.ts +3 -3
  7. package/lib/graphql/resolvers/channel-member.js +30 -5
  8. package/lib/graphql/resolvers/channel-member.js.map +1 -1
  9. package/lib/graphql/resolvers/channel.d.ts +3 -3
  10. package/lib/graphql/resolvers/channel.js +275 -53
  11. package/lib/graphql/resolvers/channel.js.map +1 -1
  12. package/lib/graphql/resolvers/extended-token-account.d.ts +3 -32
  13. package/lib/graphql/resolvers/extended-token-account.js +90 -23
  14. package/lib/graphql/resolvers/extended-token-account.js.map +1 -1
  15. package/lib/graphql/resolvers/index.d.ts +1 -31
  16. package/lib/graphql/resolvers/post-thread.d.ts +2 -3
  17. package/lib/graphql/resolvers/post-thread.js +294 -132
  18. package/lib/graphql/resolvers/post-thread.js.map +1 -1
  19. package/lib/graphql/resolvers/post.d.ts +2 -3
  20. package/lib/graphql/resolvers/post.js +697 -234
  21. package/lib/graphql/resolvers/post.js.map +1 -1
  22. package/lib/graphql/resolvers/reaction.d.ts +3 -3
  23. package/lib/graphql/resolvers/reaction.js +96 -14
  24. package/lib/graphql/resolvers/reaction.js.map +1 -1
  25. package/lib/graphql/schema/channel-member.graphql +110 -21
  26. package/lib/graphql/schema/channel-member.graphql.js +1 -1
  27. package/lib/graphql/schema/channel.graphql +331 -38
  28. package/lib/graphql/schema/channel.graphql.js +1 -1
  29. package/lib/graphql/schema/post-thread.graphql +166 -21
  30. package/lib/graphql/schema/post-thread.graphql.js +1 -1
  31. package/lib/graphql/schema/post.graphql +280 -40
  32. package/lib/graphql/schema/post.graphql.js +1 -1
  33. package/lib/graphql/schema/reaction.graphql +71 -13
  34. package/lib/graphql/schema/reaction.graphql.js +1 -1
  35. package/lib/graphql/schema/services.graphql +2 -0
  36. package/lib/graphql/schema/users.graphql +76 -13
  37. package/lib/graphql/schema/users.graphql.js +1 -1
  38. package/lib/index.js +1 -1
  39. package/lib/index.js.map +1 -1
  40. package/lib/interfaces/index.d.ts +0 -1
  41. package/lib/interfaces/services.d.ts +1 -2
  42. package/lib/migrations/dbMigrations/AddPostsConfigurationsMigration.d.ts +17 -0
  43. package/lib/migrations/dbMigrations/AddPostsConfigurationsMigration.js +44 -0
  44. package/lib/migrations/dbMigrations/AddPostsConfigurationsMigration.js.map +1 -0
  45. package/lib/migrations/dbMigrations/index.d.ts +1 -0
  46. package/lib/migrations/index.d.ts +1 -0
  47. package/lib/migrations/mail-template-migration.js +1 -1
  48. package/lib/migrations/message-notification-template-migration.d.ts +1 -1
  49. package/lib/migrations/message-notification-template-migration.js +1 -1
  50. package/lib/plugins/channel-moleculer-service.d.ts +21 -1
  51. package/lib/plugins/channel-moleculer-service.js +417 -115
  52. package/lib/plugins/channel-moleculer-service.js.map +1 -1
  53. package/lib/plugins/extended-token-account-moleculer-service.d.ts +25 -1
  54. package/lib/plugins/extended-token-account-moleculer-service.js +348 -22
  55. package/lib/plugins/extended-token-account-moleculer-service.js.map +1 -1
  56. package/lib/plugins/messenger-notification-moleculer-service.d.ts +27 -3
  57. package/lib/plugins/messenger-notification-moleculer-service.js +404 -58
  58. package/lib/plugins/messenger-notification-moleculer-service.js.map +1 -1
  59. package/lib/plugins/post-moleculer-service.d.ts +85 -21
  60. package/lib/plugins/post-moleculer-service.js +986 -256
  61. package/lib/plugins/post-moleculer-service.js.map +1 -1
  62. package/lib/plugins/post-thread-moleculer-service.d.ts +33 -1
  63. package/lib/plugins/post-thread-moleculer-service.js +326 -8
  64. package/lib/plugins/post-thread-moleculer-service.js.map +1 -1
  65. package/lib/plugins/reaction-moleculer-service.js +1 -1
  66. package/lib/plugins/reaction-moleculer-service.js.map +1 -1
  67. package/lib/preferences/settings/post-settings.d.ts +2 -0
  68. package/lib/preferences/settings/post-settings.js +47 -9
  69. package/lib/preferences/settings/post-settings.js.map +1 -1
  70. package/lib/services/channel-service.d.ts +178 -33
  71. package/lib/services/channel-service.js +735 -276
  72. package/lib/services/channel-service.js.map +1 -1
  73. package/lib/services/extended-token-account-service.d.ts +130 -14
  74. package/lib/services/extended-token-account-service.js +462 -52
  75. package/lib/services/extended-token-account-service.js.map +1 -1
  76. package/lib/services/messenger-notification-service.d.ts +106 -13
  77. package/lib/services/messenger-notification-service.js +824 -442
  78. package/lib/services/messenger-notification-service.js.map +1 -1
  79. package/lib/services/post-service.d.ts +172 -16
  80. package/lib/services/post-service.js +580 -113
  81. package/lib/services/post-service.js.map +1 -1
  82. package/lib/services/post-thread-service.d.ts +114 -5
  83. package/lib/services/post-thread-service.js +400 -13
  84. package/lib/services/post-thread-service.js.map +1 -1
  85. package/lib/services/proxy-services/channel-microservice.d.ts +5 -3
  86. package/lib/services/proxy-services/channel-microservice.js +19 -10
  87. package/lib/services/proxy-services/channel-microservice.js.map +1 -1
  88. package/lib/services/proxy-services/messenger-notification-microservice.d.ts +128 -8
  89. package/lib/services/proxy-services/messenger-notification-microservice.js +324 -29
  90. package/lib/services/proxy-services/messenger-notification-microservice.js.map +1 -1
  91. package/lib/services/proxy-services/post-microservice.d.ts +186 -12
  92. package/lib/services/proxy-services/post-microservice.js +543 -54
  93. package/lib/services/proxy-services/post-microservice.js.map +1 -1
  94. package/lib/services/proxy-services/post-thread-microservice.d.ts +134 -3
  95. package/lib/services/proxy-services/post-thread-microservice.js +388 -6
  96. package/lib/services/proxy-services/post-thread-microservice.js.map +1 -1
  97. package/lib/services/proxy-services/reaction-microservice.d.ts +161 -3
  98. package/lib/services/proxy-services/reaction-microservice.js +474 -2
  99. package/lib/services/proxy-services/reaction-microservice.js.map +1 -1
  100. package/lib/services/reaction-service.d.ts +124 -4
  101. package/lib/services/reaction-service.js +415 -3
  102. package/lib/services/reaction-service.js.map +1 -1
  103. package/lib/store/models/account-token-store.d.ts +1 -1
  104. package/lib/store/models/account-token-store.js.map +1 -1
  105. package/lib/store/models/channel.d.ts +2 -3
  106. package/lib/store/models/channel.js +180 -71
  107. package/lib/store/models/channel.js.map +1 -1
  108. package/lib/store/models/post-thread.d.ts +3 -3
  109. package/lib/store/models/post-thread.js +96 -14
  110. package/lib/store/models/post-thread.js.map +1 -1
  111. package/lib/store/models/post.d.ts +2 -3
  112. package/lib/store/models/post.js +143 -23
  113. package/lib/store/models/post.js.map +1 -1
  114. package/lib/store/models/reaction.d.ts +2 -3
  115. package/lib/store/models/reaction.js +67 -8
  116. package/lib/store/models/reaction.js.map +1 -1
  117. package/lib/store/repositories/__tests__/__fixtures__/team-repository.d.ts +3 -3
  118. package/lib/store/repositories/channel-repository.d.ts +6 -6
  119. package/lib/store/repositories/channel-repository.js +5 -2
  120. package/lib/store/repositories/channel-repository.js.map +1 -1
  121. package/lib/store/repositories/post-repository.d.ts +6 -6
  122. package/lib/store/repositories/post-repository.js +5 -2
  123. package/lib/store/repositories/post-repository.js.map +1 -1
  124. package/lib/store/repositories/post-thread-repository.d.ts +6 -6
  125. package/lib/store/repositories/post-thread-repository.js +5 -2
  126. package/lib/store/repositories/post-thread-repository.js.map +1 -1
  127. package/lib/store/repositories/reaction-repository.d.ts +6 -6
  128. package/lib/store/repositories/reaction-repository.js +5 -2
  129. package/lib/store/repositories/reaction-repository.js.map +1 -1
  130. package/lib/templates/constants/SERVER_TYPES.ts.template +0 -3
  131. package/lib/templates/repositories/ChannelRepository.ts.template +3 -3
  132. package/lib/templates/repositories/PostRepository.ts.template +3 -3
  133. package/lib/templates/repositories/PostThreadRepository.ts.template +3 -3
  134. package/lib/templates/repositories/ReactionRepository.ts.template +3 -4
  135. package/lib/templates/services/ChannelService.ts.template +278 -39
  136. package/lib/templates/services/ExtendedTokenAccountService.ts.template +107 -3
  137. package/lib/templates/services/MessengerNotificationService.ts.template +94 -19
  138. package/lib/templates/services/PostService.ts.template +184 -20
  139. package/lib/templates/services/PostThreadService.ts.template +151 -6
  140. package/lib/templates/services/ReactionService.ts.template +129 -3
  141. package/package.json +4 -4
  142. package/lib/interfaces/context.d.ts +0 -14
  143. package/lib/store/models/common-options.js +0 -20
  144. package/lib/store/models/common-options.js.map +0 -1
@@ -1,10 +1,30 @@
1
- import {__decorate,__param,__metadata}from'tslib';import'@cdm-logger/core';import {inject}from'inversify';import {set}from'lodash-es';import {SERVER_TYPES,FileRefType}from'common';import {BaseService}from'@common-stack/store-mongo';import {PubSubEngine}from'graphql-subscriptions';import {CommonType}from'@common-stack/core';import {ServiceBroker}from'moleculer';import {ChannelRepository}from'../store/repositories/channel-repository.js';import {PostRepository}from'../store/repositories/post-repository.js';import'../store/repositories/post-thread-repository.js';import'../store/repositories/reaction-repository.js';import {PostTypes}from'../preferences/settings/post-settings.js';import'../preferences/permissions/inbox-permission-contribution.js';import'../preferences/permissions/inbox-roles-permission-overwrite.js';import {config}from'../config/env-config.js';var PostService_1;
2
- let PostService = PostService_1 = class PostService extends BaseService {
1
+ import {__decorate,__param,__metadata}from'tslib';import'@cdm-logger/core';import {inject}from'inversify';import {set}from'lodash-es';import {SERVER_TYPES,FileRefType}from'common/server';import {BaseService2}from'@common-stack/store-mongo';import {PubSubEngine}from'graphql-subscriptions';import {CommonType}from'@common-stack/core';import {ServiceBroker}from'moleculer';import {DisposableCollection}from'@adminide-stack/core';import {ChannelRepository}from'../store/repositories/channel-repository.js';import {PostRepository}from'../store/repositories/post-repository.js';import'../store/repositories/post-thread-repository.js';import'../store/repositories/reaction-repository.js';import {PostTypes}from'../preferences/settings/post-settings.js';import'../preferences/permissions/inbox-permission-contribution.js';import'../preferences/permissions/inbox-roles-permission-overwrite.js';import {config}from'../config/env-config.js';var PostService_1;
2
+ /**
3
+ * Post Service Implementation
4
+ *
5
+ * This service handles comprehensive post management within the messenger platform,
6
+ * providing operations for creating, updating, managing posts and their associated
7
+ * content including file attachments, notifications, threading, and real-time
8
+ * message delivery across channels and organizations.
9
+ *
10
+ * Key capabilities:
11
+ * - Post lifecycle management (creation, updates, deletion)
12
+ * - File attachment handling and upload management
13
+ * - Real-time message delivery and notifications
14
+ * - Post threading and conversation management
15
+ * - Message status tracking (read, delivered)
16
+ * - Channel integration and message counting
17
+ * - Expo push notification integration
18
+ * - File upload link generation and management
19
+ */
20
+ // @ts-ignore - Type compatibility issue between BaseService2 and IPostService
21
+ let PostService = PostService_1 = class PostService extends BaseService2 {
3
22
  channelRepo;
4
23
  fileInfoService;
5
24
  messengerNotificationService;
6
25
  broker;
7
26
  pubsub;
27
+ toDispose = new DisposableCollection();
8
28
  logger;
9
29
  constructor(repository, channelRepo, fileInfoService, messengerNotificationService, broker, pubsub, logger) {
10
30
  super(repository);
@@ -17,39 +37,149 @@ let PostService = PostService_1 = class PostService extends BaseService {
17
37
  className: PostService_1.name
18
38
  });
19
39
  }
20
- createFileUploadLink(postId, filename, userId) {
21
- return this.fileInfoService.uploadByUrl({
22
- filename,
23
- refType: FileRefType.Post,
24
- ref: postId,
25
- userId
26
- });
40
+ /**
41
+ * Disposes of resources used by the service
42
+ */
43
+ dispose() {
44
+ this.toDispose.dispose();
45
+ }
46
+ // Override base service methods to handle errors internally
47
+ async create(data) {
48
+ try {
49
+ this.logger.debug('Creating post', {
50
+ data
51
+ });
52
+ // Validate required fields
53
+ if (!data) {
54
+ throw new Error('Post data is required');
55
+ }
56
+ if (!data.channel) {
57
+ throw new Error('Channel is required for post creation');
58
+ }
59
+ if (!data.author) {
60
+ throw new Error('Author is required for post creation');
61
+ }
62
+ // Add timestamps and default type
63
+ const postData = {
64
+ ...data,
65
+ type: data.type || 'Simple',
66
+ // Default to Simple type for regular messages
67
+ createdAt: new Date(),
68
+ updatedAt: new Date()
69
+ };
70
+ // Create the post using repository
71
+ const result = await this.repository.create(postData);
72
+ if (!result) {
73
+ throw new Error('Failed to create post');
74
+ }
75
+ // Update channel statistics
76
+ try {
77
+ await this.channelRepo.model.updateOne({
78
+ _id: data.channel
79
+ }, {
80
+ lastPostAt: result.createdAt,
81
+ $inc: {
82
+ totalMsgCount: 1,
83
+ totalMsgCountRoot: 1,
84
+ 'members.$[elem].msgCountRoot': 1,
85
+ 'members.$[elem].msgCount': 1
86
+ }
87
+ }, {
88
+ arrayFilters: [{
89
+ 'elem.user': data.author
90
+ }]
91
+ });
92
+ } catch (channelError) {
93
+ this.logger.error('Error updating channel stats:', channelError);
94
+ // Don't fail the post creation if stats update fails
95
+ }
96
+ return result;
97
+ } catch (error) {
98
+ this.logger.error('Error creating post:', error);
99
+ throw error;
100
+ }
101
+ }
102
+ async update(id, data) {
103
+ try {
104
+ const result = await super.update(id, data);
105
+ if (!result || typeof result === 'object' && 'message' in result) {
106
+ this.logger.error('Failed to update post', {
107
+ error: result
108
+ });
109
+ throw new Error('Failed to update post');
110
+ }
111
+ return result;
112
+ } catch (error) {
113
+ this.logger.error('Error updating post', {
114
+ error
115
+ });
116
+ throw error;
117
+ }
118
+ }
119
+ async delete(criteria) {
120
+ try {
121
+ const result = await super.delete(criteria);
122
+ if (typeof result !== 'boolean') {
123
+ this.logger.error('Failed to delete post', {
124
+ error: result
125
+ });
126
+ throw new Error('Failed to delete post');
127
+ }
128
+ return result;
129
+ } catch (error) {
130
+ this.logger.error('Error deleting post', {
131
+ error
132
+ });
133
+ throw error;
134
+ }
135
+ }
136
+ /**
137
+ * Creates a file upload link for a post
138
+ *
139
+ * @description Generates a secure upload URL for attaching files to posts
140
+ *
141
+ * @param {string} postId - The post identifier
142
+ * @param {string} filename - The name of the file to upload
143
+ * @param {string} userId - The user performing the upload
144
+ * @returns {Promise<string | Error>} - Upload URL or error
145
+ */
146
+ async createFileUploadLink(postId, filename, userId) {
147
+ try {
148
+ if (!postId || !filename || !userId) {
149
+ return new Error('Post ID, filename, and user ID are required');
150
+ }
151
+ const uploadUrl = await this.fileInfoService.uploadByUrl({
152
+ filename,
153
+ refType: FileRefType.Post,
154
+ ref: postId,
155
+ userId
156
+ });
157
+ this.logger.debug('File upload link created', {
158
+ postId,
159
+ filename,
160
+ userId
161
+ });
162
+ return uploadUrl;
163
+ } catch (error) {
164
+ this.logger.error('Error creating file upload link: %o', error);
165
+ return error instanceof Error ? error : new Error('Unknown error occurred while creating upload link');
166
+ }
27
167
  }
168
+ /**
169
+ * Attaches an uploaded file to a post
170
+ *
171
+ * @description Processes and attaches a completed file upload to a post
172
+ *
173
+ * @param {string} postId - The post identifier
174
+ * @param {IUploadedFileInput} file - The uploaded file information
175
+ * @param {string} createdBy - The user who uploaded the file
176
+ * @returns {Promise<IFileInfo | Error>} - File information or error
177
+ */
28
178
  async attachUploadedFile(postId, file, createdBy) {
29
- const {
30
- id
31
- } = await this.fileInfoService.createUploadedFile({
32
- ...file,
33
- refType: FileRefType.Post,
34
- ref: postId,
35
- createdBy
36
- });
37
- const fileResponse = await this.fileInfoService.get(id);
38
- return {
39
- ...fileResponse,
40
- url: this.fileInfoService.getDefaultImage(fileResponse.url)
41
- };
42
- }
43
- createFilesUploadLink(postId, filenames, userId) {
44
- return Promise.all(filenames.map(filename => this.fileInfoService.uploadByUrl({
45
- filename,
46
- refType: FileRefType.Post,
47
- ref: postId,
48
- userId
49
- })));
50
- }
51
- attachUploadedFiles(postId, files, createdBy) {
52
- return Promise.all(files.map(async file => {
179
+ try {
180
+ if (!postId || !file || !createdBy) {
181
+ return new Error('Post ID, file data, and creator ID are required');
182
+ }
53
183
  const {
54
184
  id
55
185
  } = await this.fileInfoService.createUploadedFile({
@@ -59,103 +189,440 @@ let PostService = PostService_1 = class PostService extends BaseService {
59
189
  createdBy
60
190
  });
61
191
  const fileResponse = await this.fileInfoService.get(id);
62
- return {
192
+ const result = {
63
193
  ...fileResponse,
64
194
  url: this.fileInfoService.getDefaultImage(fileResponse.url)
65
195
  };
66
- }));
196
+ this.logger.debug('File attached to post', {
197
+ postId,
198
+ fileId: id,
199
+ createdBy
200
+ });
201
+ return result;
202
+ } catch (error) {
203
+ this.logger.error('Error attaching uploaded file: %o', error);
204
+ return error instanceof Error ? error : new Error('Unknown error occurred while attaching file');
205
+ }
67
206
  }
68
- async create(data) {
69
- const post = await super.create(data);
70
- const {
71
- channel
72
- } = data;
73
- // Accessing private property
74
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
75
- // @ts-ignore
76
- await this.channelRepo.model.updateOne({
77
- _id: channel
78
- }, {
79
- lastPostAt: post.createdAt,
80
- $inc: {
81
- totalMsgCount: 1,
82
- totalMsgCountRoot: 1,
83
- 'members.$[elem].msgCountRoot': 1,
84
- 'members.$[elem].msgCount': 1
85
- }
86
- }, {
87
- arrayFilters: [{
88
- 'elem.user': data.author
89
- }]
90
- });
91
- await this.pubsub.publish(`POST_CREATED.${channel}`, post);
92
- await this.sendExpoNotification(post);
93
- // if (post?.props?.notificationParams) await this.messengerNotificationService.sendExpoNotificationOnPost(post);
94
- this.logger.trace('Post created');
95
- return post;
207
+ /**
208
+ * Creates upload links for multiple files
209
+ *
210
+ * @description Generates secure upload URLs for multiple files to be attached to a post
211
+ *
212
+ * @param {string} postId - The post identifier
213
+ * @param {string[]} filenames - Array of file names
214
+ * @param {string} userId - The user performing the uploads
215
+ * @returns {Promise<string[] | Error>} - Array of upload URLs or error
216
+ */
217
+ async createFilesUploadLink(postId, filenames, userId) {
218
+ try {
219
+ if (!postId || !filenames || !Array.isArray(filenames) || !userId) {
220
+ return new Error('Post ID, filenames array, and user ID are required');
221
+ }
222
+ if (filenames.length === 0) {
223
+ return new Error('At least one filename is required');
224
+ }
225
+ const uploadUrls = await Promise.all(filenames.map(filename => this.fileInfoService.uploadByUrl({
226
+ filename,
227
+ refType: FileRefType.Post,
228
+ ref: postId,
229
+ userId
230
+ })));
231
+ this.logger.debug('Multiple file upload links created', {
232
+ postId,
233
+ fileCount: filenames.length,
234
+ userId
235
+ });
236
+ return uploadUrls;
237
+ } catch (error) {
238
+ this.logger.error('Error creating multiple file upload links: %o', error);
239
+ return error instanceof Error ? error : new Error('Unknown error occurred while creating upload links');
240
+ }
241
+ }
242
+ /**
243
+ * Attaches multiple uploaded files to a post
244
+ *
245
+ * @description Processes and attaches multiple completed file uploads to a post
246
+ *
247
+ * @param {string} postId - The post identifier
248
+ * @param {IUploadedFileInput[]} files - Array of uploaded file information
249
+ * @param {string} createdBy - The user who uploaded the files
250
+ * @returns {Promise<IFileInfo[] | Error>} - Array of file information or error
251
+ */
252
+ async attachUploadedFiles(postId, files, createdBy) {
253
+ try {
254
+ if (!postId || !files || !Array.isArray(files) || !createdBy) {
255
+ return new Error('Post ID, files array, and creator ID are required');
256
+ }
257
+ if (files.length === 0) {
258
+ return new Error('At least one file is required');
259
+ }
260
+ const fileResults = await Promise.all(files.map(async file => {
261
+ const {
262
+ id
263
+ } = await this.fileInfoService.createUploadedFile({
264
+ ...file,
265
+ refType: FileRefType.Post,
266
+ ref: postId,
267
+ createdBy
268
+ });
269
+ const fileResponse = await this.fileInfoService.get(id);
270
+ return {
271
+ ...fileResponse,
272
+ url: this.fileInfoService.getDefaultImage(fileResponse.url)
273
+ };
274
+ }));
275
+ this.logger.debug('Multiple files attached to post', {
276
+ postId,
277
+ fileCount: files.length,
278
+ createdBy
279
+ });
280
+ return fileResults;
281
+ } catch (error) {
282
+ this.logger.error('Error attaching multiple uploaded files: %o', error);
283
+ return error instanceof Error ? error : new Error('Unknown error occurred while attaching files');
284
+ }
96
285
  }
286
+ /**
287
+ * Creates a new post with full integration
288
+ *
289
+ * @description Creates a post with channel updates, notifications, and real-time publishing
290
+ *
291
+ * @param {IPostServiceInput} data - Post creation data
292
+ * @returns {Promise<AsDomainType<IPostModel> | Error>} - Created post or error
293
+ */
294
+ // @ts-ignore - Type compatibility issue between interface and implementation
97
295
  async createWithoutSubscription(data) {
98
- const post = await super.create(data);
99
- const {
100
- channel
101
- } = data;
102
- await this.channelRepo.model.updateOne({
103
- _id: channel
104
- }, {
105
- lastPostAt: post.createdAt,
106
- $inc: {
107
- totalMsgCount: 1,
108
- totalMsgCountRoot: 1,
109
- 'members.$[elem].msgCountRoot': 1,
110
- 'members.$[elem].msgCount': 1
111
- }
112
- }, {
113
- arrayFilters: [{
114
- 'elem.user': data.author
115
- }]
116
- });
117
- return post;
296
+ try {
297
+ if (!data) {
298
+ return new Error('Post data is required');
299
+ }
300
+ if (!data.channel) {
301
+ return new Error('Channel is required for post creation');
302
+ }
303
+ if (!data.author) {
304
+ return new Error('Author is required for post creation');
305
+ }
306
+ // Create the post
307
+ const postData = {
308
+ ...data,
309
+ createdAt: new Date(),
310
+ updatedAt: new Date()
311
+ }; // Type assertion for compatibility
312
+ const post = await this.repository.create(postData);
313
+ if (!post) {
314
+ return new Error('Failed to create post');
315
+ }
316
+ const {
317
+ channel
318
+ } = data;
319
+ // Update channel statistics without real-time publishing
320
+ // @ts-ignore - Accessing private property for channel updates
321
+ await this.channelRepo.model.updateOne({
322
+ _id: channel
323
+ }, {
324
+ lastPostAt: post.createdAt,
325
+ $inc: {
326
+ totalMsgCount: 1,
327
+ totalMsgCountRoot: 1,
328
+ 'members.$[elem].msgCountRoot': 1,
329
+ 'members.$[elem].msgCount': 1
330
+ }
331
+ }, {
332
+ arrayFilters: [{
333
+ 'elem.user': data.author
334
+ }]
335
+ });
336
+ this.logger.debug('Post created without subscription', {
337
+ postId: post.id,
338
+ channelId: channel,
339
+ authorId: data.author
340
+ });
341
+ return post;
342
+ } catch (error) {
343
+ this.logger.error('Error creating post without subscription: %o', error);
344
+ return error instanceof Error ? error : new Error('Unknown error occurred while creating post');
345
+ }
118
346
  }
119
- deleteFile(url) {
120
- return this.fileInfoService.deleteByUrl(url);
347
+ /**
348
+ * Deletes a file by URL
349
+ *
350
+ * @description Removes a file from storage using its URL
351
+ *
352
+ * @param {string} url - The file URL to delete
353
+ * @returns {Promise<boolean | Error>} - Success status or error
354
+ */
355
+ async deleteFile(url) {
356
+ try {
357
+ if (!url) {
358
+ return new Error('File URL is required');
359
+ }
360
+ const success = await this.fileInfoService.deleteByUrl(url);
361
+ this.logger.debug('File deleted', {
362
+ url,
363
+ success
364
+ });
365
+ return success;
366
+ } catch (error) {
367
+ this.logger.error('Error deleting file: %o', error);
368
+ return error instanceof Error ? error : new Error('Unknown error occurred while deleting file');
369
+ }
121
370
  }
371
+ /**
372
+ * Marks a message as read by a user
373
+ *
374
+ * @description Updates message status to indicate it has been read by a specific user
375
+ *
376
+ * @param {IMessageIdentifier} messageId - Message identifier
377
+ * @param {string} user - User ID who read the message
378
+ * @returns {Promise<boolean | Error>} - Success status or error
379
+ */
122
380
  async readMessage(messageId, user) {
123
- await this.update(messageId.messageId, {
124
- props: {
125
- [`[${user}]`]: set({}, PostTypes.isRead, true)
381
+ try {
382
+ if (!messageId?.messageId || !user) {
383
+ return new Error('Message ID and user ID are required');
126
384
  }
127
- });
128
- return true;
385
+ await this.update(messageId.messageId, {
386
+ props: {
387
+ [`[${user}]`]: set({}, PostTypes.isRead, true)
388
+ }
389
+ });
390
+ this.logger.debug('Message marked as read', {
391
+ messageId: messageId.messageId,
392
+ userId: user
393
+ });
394
+ return true;
395
+ } catch (error) {
396
+ this.logger.error('Error marking message as read: %o', error);
397
+ return error instanceof Error ? error : new Error('Unknown error occurred while marking message as read');
398
+ }
129
399
  }
400
+ /**
401
+ * Marks a message as delivered to a user
402
+ *
403
+ * @description Updates message status to indicate it has been delivered to a specific user
404
+ *
405
+ * @param {IMessageIdentifier} messageId - Message identifier
406
+ * @param {string} user - User ID who received the message
407
+ * @returns {Promise<boolean | Error>} - Success status or error
408
+ */
130
409
  async deliverMessage(messageId, user) {
131
- await this.update(messageId.messageId, {
132
- props: {
133
- [`[${user}]`]: set({}, PostTypes.isDelivered, true)
410
+ try {
411
+ if (!messageId?.messageId || !user) {
412
+ return new Error('Message ID and user ID are required');
134
413
  }
135
- });
136
- return true;
414
+ await this.update(messageId.messageId, {
415
+ props: {
416
+ [`[${user}]`]: set({}, PostTypes.isDelivered, true)
417
+ }
418
+ });
419
+ this.logger.debug('Message marked as delivered', {
420
+ messageId: messageId.messageId,
421
+ userId: user
422
+ });
423
+ return true;
424
+ } catch (error) {
425
+ this.logger.error('Error marking message as delivered: %o', error);
426
+ return error instanceof Error ? error : new Error('Unknown error occurred while marking message as delivered');
427
+ }
137
428
  }
138
- async sendExpoNotification(post) {
139
- if (post?.props?.notificationParams && (!post?.type || post?.type !== 'ALERT')) {
140
- await this.messengerNotificationService.sendExpoNotificationOnPost(post);
141
- } else if (!post?.type || post?.type !== 'ALERT') {
142
- const notificationData = {
143
- url: config.INBOX_MESSEGE_PATH,
144
- params: {
145
- channelId: post?.channel,
146
- hideTabBar: true
147
- },
148
- screen: 'DialogMessages',
149
- other: {
150
- sound: 'default'
429
+ /**
430
+ * Creates a post with associated post thread
431
+ *
432
+ * @description Creates both a post and its associated thread for threaded conversations
433
+ *
434
+ * @param {CreatePostThreadOptions} data - Post and thread creation options
435
+ * @returns {Promise<{post: AsDomainType<IPostModel>; postThread: IPostThread} | Error>} - Created post and thread or error
436
+ */
437
+ // @ts-ignore - Type compatibility issue between interface and implementation
438
+ async createPostWithPostThread(data) {
439
+ try {
440
+ if (!data) {
441
+ return new Error('Post thread creation data is required');
442
+ }
443
+ // This would require integration with PostThreadService
444
+ // For now, return an error indicating it needs implementation
445
+ return new Error('Post thread creation is not yet implemented');
446
+ } catch (error) {
447
+ this.logger.error('Error creating post with thread: %o', error);
448
+ return error instanceof Error ? error : new Error('Unknown error occurred while creating post with thread');
449
+ }
450
+ }
451
+ /**
452
+ * Retrieves the last message in a channel
453
+ *
454
+ * @description Gets the most recent post/message from a specific channel
455
+ *
456
+ * @param {string} channelId - The channel identifier
457
+ * @returns {Promise<AsDomainType<IPostModel> | Error>} - Last message or error
458
+ */
459
+ // @ts-ignore - Type compatibility issue between interface and implementation
460
+ async getLastMessage(channelId) {
461
+ try {
462
+ if (!channelId) {
463
+ return new Error('Channel ID is required');
464
+ }
465
+ // @ts-ignore - Accessing private property for direct query
466
+ const post = await this.repository.model.findOne({
467
+ channel: channelId
468
+ }).sort({
469
+ createdAt: -1
470
+ });
471
+ if (!post) {
472
+ return new Error('No messages found in channel');
473
+ }
474
+ this.logger.debug('Last message retrieved', {
475
+ channelId,
476
+ postId: post._id
477
+ });
478
+ return post;
479
+ } catch (error) {
480
+ this.logger.error('Error getting last message: %o', error);
481
+ return error instanceof Error ? error : new Error('Unknown error occurred while getting last message');
482
+ }
483
+ }
484
+ /**
485
+ * Gets posts by channel with pagination
486
+ *
487
+ * @description Retrieves posts from a channel with pagination support
488
+ *
489
+ * @param {string} channelId - The channel identifier
490
+ * @param {number} limit - Maximum number of posts to return
491
+ * @param {number} offset - Number of posts to skip
492
+ * @returns {Promise<Array<AsDomainType<IPostModel>> | Error>} - Array of posts or error
493
+ */
494
+ async getPostsByChannel(channelId, limit = 50, offset = 0) {
495
+ try {
496
+ if (!channelId) {
497
+ return new Error('Channel ID is required');
498
+ }
499
+ const posts = await this.getAll({
500
+ criteria: {
501
+ channel: channelId
151
502
  }
152
- };
153
- await this.messengerNotificationService.sendExpoNotificationOnPost(post, notificationData);
503
+ });
504
+ // Apply manual pagination
505
+ const paginatedPosts = posts.slice(offset, offset + limit);
506
+ this.logger.debug('Posts retrieved by channel', {
507
+ channelId,
508
+ count: paginatedPosts.length,
509
+ limit,
510
+ offset
511
+ });
512
+ return paginatedPosts;
513
+ } catch (error) {
514
+ this.logger.error('Error getting posts by channel: %o', error);
515
+ return error instanceof Error ? error : new Error('Unknown error occurred while getting posts by channel');
516
+ }
517
+ }
518
+ /**
519
+ * Updates a post
520
+ *
521
+ * @description Updates post content and metadata
522
+ *
523
+ * @param {string} postId - The post identifier
524
+ * @param {Partial<IPostServiceInput>} updates - Update data
525
+ * @returns {Promise<AsDomainType<IPostModel> | Error>} - Updated post or error
526
+ */
527
+ async updatePost(postId, updates) {
528
+ try {
529
+ if (!postId) {
530
+ return new Error('Post ID is required');
531
+ }
532
+ if (!updates || Object.keys(updates).length === 0) {
533
+ return new Error('Updates are required');
534
+ }
535
+ // Get existing post
536
+ const existingPost = await this.get(postId);
537
+ if (!existingPost) {
538
+ return new Error('Post not found');
539
+ }
540
+ // Prepare update data
541
+ const updateData = {
542
+ ...updates,
543
+ updatedAt: new Date()
544
+ }; // Type assertion for compatibility
545
+ // Update the post
546
+ const updatedPost = await this.update(postId, updateData);
547
+ if (!updatedPost) {
548
+ return new Error('Failed to update post');
549
+ }
550
+ this.logger.debug('Post updated successfully', {
551
+ postId,
552
+ updates: Object.keys(updates)
553
+ });
554
+ return updatedPost;
555
+ } catch (error) {
556
+ this.logger.error('Error updating post: %o', error);
557
+ return error instanceof Error ? error : new Error('Unknown error occurred while updating post');
558
+ }
559
+ }
560
+ /**
561
+ * Deletes a post
562
+ *
563
+ * @description Soft deletes a post and its associated data
564
+ *
565
+ * @param {string} postId - The post identifier
566
+ * @returns {Promise<boolean | Error>} - Success status or error
567
+ */
568
+ async deletePost(postId) {
569
+ try {
570
+ if (!postId) {
571
+ return new Error('Post ID is required');
572
+ }
573
+ // Get post to verify it exists
574
+ const post = await this.get(postId);
575
+ if (!post) {
576
+ return new Error('Post not found');
577
+ }
578
+ // Soft delete the post
579
+ const success = await this.repository.delete({
580
+ id: postId
581
+ });
582
+ if (success) {
583
+ this.logger.debug('Post deleted successfully', {
584
+ postId
585
+ });
586
+ }
587
+ return success;
588
+ } catch (error) {
589
+ this.logger.error('Error deleting post: %o', error);
590
+ return error instanceof Error ? error : new Error('Unknown error occurred while deleting post');
154
591
  }
155
592
  }
156
- // eslint-disable-next-line class-methods-use-this
157
- createPostWithPostThread(data) {
158
- throw new Error('Not implemented');
593
+ /**
594
+ * Sends Expo push notification for a post
595
+ *
596
+ * @description Handles push notification logic for new posts
597
+ *
598
+ * @param {any} post - The post data
599
+ * @private
600
+ */
601
+ async sendExpoNotification(post) {
602
+ try {
603
+ if (post?.props?.notificationParams && (!post?.type || post?.type !== 'ALERT')) {
604
+ await this.messengerNotificationService.sendExpoNotificationOnPost(post);
605
+ } else if (!post?.type || post?.type !== 'ALERT') {
606
+ const notificationData = {
607
+ url: config.INBOX_MESSEGE_PATH,
608
+ params: {
609
+ channelId: post?.channel,
610
+ hideTabBar: true
611
+ },
612
+ screen: 'DialogMessages',
613
+ other: {
614
+ sound: 'default'
615
+ }
616
+ };
617
+ await this.messengerNotificationService.sendExpoNotificationOnPost(post, notificationData);
618
+ }
619
+ this.logger.debug('Expo notification sent', {
620
+ postId: post?.id
621
+ });
622
+ } catch (error) {
623
+ this.logger.error('Error sending Expo notification: %o', error);
624
+ // Don't throw error as notification failure shouldn't break post creation
625
+ }
159
626
  }
160
627
  };
161
628
  PostService = PostService_1 = __decorate([__param(0, inject(SERVER_TYPES.PostRepository)), __param(1, inject(SERVER_TYPES.ChannelRepository)), __param(2, inject(SERVER_TYPES.FileInfoService)), __param(3, inject(SERVER_TYPES.MessengerNotificationService)), __param(4, inject(CommonType.MOLECULER_BROKER)), __param(5, inject('PubSub')), __param(6, inject('Logger')), __metadata("design:paramtypes", [PostRepository, ChannelRepository, Object, Object, ServiceBroker, PubSubEngine, Object])], PostService);export{PostService};//# sourceMappingURL=post-service.js.map