@messenger-box/platform-server 10.0.3-alpha.7 → 10.0.3-alpha.74
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/config/env-config.d.ts +7 -0
- package/lib/config/env-config.js +20 -0
- package/lib/config/env-config.js.map +1 -1
- package/lib/containers/containers.js +9 -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 +4 -2
- package/lib/containers/context-services-from-container.js.map +1 -1
- package/lib/graphql/resolvers/ai-fragment.d.ts +3 -0
- package/lib/graphql/resolvers/ai-fragment.js +276 -0
- package/lib/graphql/resolvers/ai-fragment.js.map +1 -0
- 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 +308 -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/index.js +1 -1
- package/lib/graphql/resolvers/index.js.map +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 +874 -239
- 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/ai-fragment.graphql +311 -0
- package/lib/graphql/schema/ai-fragment.graphql.js +1 -0
- package/lib/graphql/schema/ai-fragment.graphql.js.map +1 -0
- 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 +356 -38
- package/lib/graphql/schema/channel.graphql.js +1 -1
- package/lib/graphql/schema/index.js +2 -2
- package/lib/graphql/schema/index.js.map +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 +360 -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 +21 -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/inngest/factory.d.ts +20 -0
- package/lib/inngest/factory.js +4 -0
- package/lib/inngest/factory.js.map +1 -0
- package/lib/inngest/functions.d.ts +235 -0
- package/lib/inngest/functions.js +1385 -0
- package/lib/inngest/functions.js.map +1 -0
- package/lib/inngest/index.d.ts +3 -0
- package/lib/inngest/prompt.d.ts +6 -0
- package/lib/inngest/prompt.js +871 -0
- package/lib/inngest/prompt.js.map +1 -0
- package/lib/inngest/utils.d.ts +5 -0
- package/lib/inngest/utils.js +32 -0
- package/lib/inngest/utils.js.map +1 -0
- 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/module.js +10 -3
- package/lib/module.js.map +1 -1
- package/lib/plugins/ai-fragment-moleculer-service.d.ts +29 -0
- package/lib/plugins/ai-fragment-moleculer-service.js +516 -0
- package/lib/plugins/ai-fragment-moleculer-service.js.map +1 -0
- package/lib/plugins/channel-moleculer-service.d.ts +21 -1
- package/lib/plugins/channel-moleculer-service.js +426 -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/index.d.ts +1 -0
- 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 +1102 -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/ai-fragment-service.d.ts +195 -0
- package/lib/services/ai-fragment-service.js +631 -0
- package/lib/services/ai-fragment-service.js.map +1 -0
- package/lib/services/channel-service.d.ts +181 -33
- package/lib/services/channel-service.js +842 -273
- 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 +3 -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 +189 -16
- package/lib/services/post-service.js +949 -113
- 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/ai-fragment-microservice.d.ts +23 -0
- package/lib/services/proxy-services/ai-fragment-microservice.js +78 -0
- package/lib/services/proxy-services/ai-fragment-microservice.js.map +1 -0
- package/lib/services/proxy-services/channel-microservice.d.ts +6 -3
- package/lib/services/proxy-services/channel-microservice.js +25 -10
- package/lib/services/proxy-services/channel-microservice.js.map +1 -1
- package/lib/services/proxy-services/index.d.ts +1 -0
- 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 +207 -12
- package/lib/services/proxy-services/post-microservice.js +623 -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/services/sandbox-error-service.d.ts +23 -0
- package/lib/services/sandbox-error-service.js +422 -0
- package/lib/services/sandbox-error-service.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/ai-fragment.d.ts +4 -0
- package/lib/store/models/ai-fragment.js +125 -0
- package/lib/store/models/ai-fragment.js.map +1 -0
- package/lib/store/models/channel.d.ts +2 -3
- package/lib/store/models/channel.js +185 -71
- package/lib/store/models/channel.js.map +1 -1
- package/lib/store/models/index.d.ts +1 -0
- 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/ai-fragment-repository.d.ts +15 -0
- package/lib/store/repositories/ai-fragment-repository.js +69 -0
- package/lib/store/repositories/ai-fragment-repository.js.map +1 -0
- 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/index.d.ts +1 -0
- 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 +4 -4
- package/lib/templates/repositories/AiFragmentRepository.ts.template +4 -0
- 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/AiFragmentService.ts.template +123 -0
- package/lib/templates/services/ChannelService.ts.template +290 -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 +265 -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/lib/templates/services/SandboxErrorService.ts.template +125 -0
- package/package.json +14 -7
- 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,272 +1,720 @@
|
|
|
1
|
-
import {__decorate,__param,__metadata}from'tslib';import {inject}from'inversify';import {SERVER_TYPES,RoomType,SortEnum}from'common';import {
|
|
2
|
-
|
|
1
|
+
import {__decorate,__param,__metadata}from'tslib';import {injectable,inject}from'inversify';import {Emitter,DisposableCollection}from'@adminide-stack/core';import {SERVER_TYPES,RoomType,SortEnum}from'common/server';import {BaseService2}from'@common-stack/store-mongo';import'@cdm-logger/core';import {ServiceBroker}from'moleculer';import {CommonType}from'@common-stack/core';import'../constants/query.constants.js';import {DEFAULT_NOTIFY_PROPS}from'../constants/default-notify-props.js';import {config}from'../config/env-config.js';var ChannelService_1;
|
|
2
|
+
const CACHE_TTL = {
|
|
3
|
+
maxAge: 5 * 60,
|
|
4
|
+
scope: 'PUBLIC'
|
|
5
|
+
}; // 5 minutes
|
|
6
|
+
/**
|
|
7
|
+
* Modern implementation of the Channel Service
|
|
8
|
+
*
|
|
9
|
+
* This service handles comprehensive channel management within the messenger platform,
|
|
10
|
+
* providing operations for managing channels, their members, and related messaging workflows.
|
|
11
|
+
*
|
|
12
|
+
* Key capabilities:
|
|
13
|
+
* - Channel lifecycle management (creation, updates, deletion)
|
|
14
|
+
* - Member management (adding, removing, role assignment)
|
|
15
|
+
* - Direct and public channel handling
|
|
16
|
+
* - Message and post management within channels
|
|
17
|
+
* - Channel visibility and access control
|
|
18
|
+
* - Notification and unread message tracking
|
|
19
|
+
* - Team-based channel organization
|
|
20
|
+
* - Channel discovery and filtering
|
|
21
|
+
* - Redis caching for performance optimization
|
|
22
|
+
* - Comprehensive error handling and logging
|
|
23
|
+
* - Event-driven architecture with proper disposal
|
|
24
|
+
*
|
|
25
|
+
* The service layer abstracts the underlying data access operations and
|
|
26
|
+
* provides a cohesive API for channel-related functionality throughout
|
|
27
|
+
* the messaging platform, handling complex business rules and cross-cutting concerns.
|
|
28
|
+
*/
|
|
29
|
+
let ChannelService = ChannelService_1 = class ChannelService extends BaseService2 {
|
|
3
30
|
repository;
|
|
4
31
|
postService;
|
|
5
|
-
|
|
32
|
+
broker;
|
|
33
|
+
redisCacheManager;
|
|
34
|
+
redisClient;
|
|
35
|
+
inngestClient;
|
|
36
|
+
// Event emitters for channel lifecycle events
|
|
37
|
+
onChannelCreated = new Emitter();
|
|
38
|
+
onChannelUpdated = new Emitter();
|
|
39
|
+
onChannelDeleted = new Emitter();
|
|
40
|
+
onChannelRestored = new Emitter();
|
|
41
|
+
onMemberAdded = new Emitter();
|
|
42
|
+
onMemberRemoved = new Emitter();
|
|
43
|
+
onChannelViewed = new Emitter();
|
|
44
|
+
toDispose = new DisposableCollection(this.onChannelCreated, this.onChannelUpdated, this.onChannelDeleted, this.onChannelRestored, this.onMemberAdded, this.onMemberRemoved, this.onChannelViewed);
|
|
45
|
+
logger;
|
|
46
|
+
constructor(repository, postService, broker, redisCacheManager, redisClient, logger, inngestClient) {
|
|
6
47
|
super(repository);
|
|
7
48
|
this.repository = repository;
|
|
8
49
|
this.postService = postService;
|
|
50
|
+
this.broker = broker;
|
|
51
|
+
this.redisCacheManager = redisCacheManager;
|
|
52
|
+
this.redisClient = redisClient;
|
|
53
|
+
this.inngestClient = inngestClient;
|
|
54
|
+
this.logger = logger?.child({
|
|
55
|
+
className: 'ChannelService'
|
|
56
|
+
}) || console;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Disposes of resources used by the service
|
|
60
|
+
*/
|
|
61
|
+
dispose() {
|
|
62
|
+
this.toDispose.dispose();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Helper method to make service calls
|
|
66
|
+
* @param command - Command to execute
|
|
67
|
+
* @param params - Command parameters
|
|
68
|
+
* @param topic - Service topic
|
|
69
|
+
* @param opts - Call options
|
|
70
|
+
* @returns Command result
|
|
71
|
+
*/
|
|
72
|
+
async callAction(command, params, topic, opts) {
|
|
73
|
+
try {
|
|
74
|
+
if (!this.broker) {
|
|
75
|
+
throw new Error('Service broker not available');
|
|
76
|
+
}
|
|
77
|
+
const actionName = topic ? `${topic}.${command}` : command;
|
|
78
|
+
return await this.broker.call(actionName, params, opts);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
this.logger.error(`Error calling action ${command}: %o`, error);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
9
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Enhanced method to check if a user is a member of a specific channel
|
|
86
|
+
*
|
|
87
|
+
* @description Verifies channel membership with proper error handling and logging
|
|
88
|
+
*
|
|
89
|
+
* @param {string} channelId - The ID of the channel to check
|
|
90
|
+
* @param {string} user - The ID of the user
|
|
91
|
+
* @returns {Promise<boolean>} - True if the user is a member
|
|
92
|
+
*/
|
|
10
93
|
async isMember(channelId, user) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
94
|
+
try {
|
|
95
|
+
if (!channelId || !user) {
|
|
96
|
+
this.logger.warn('Channel ID and user ID are required for membership check');
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
this.logger.debug('Checking channel membership', {
|
|
100
|
+
channelId,
|
|
101
|
+
userId: user
|
|
102
|
+
});
|
|
103
|
+
const channel = await this.get(channelId);
|
|
104
|
+
if (!channel?.members) {
|
|
105
|
+
this.logger.debug('Channel not found or has no members', {
|
|
106
|
+
channelId
|
|
107
|
+
});
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
const isMember = !!channel.members.find(member => member.user && member.user.toString() === user.toString());
|
|
111
|
+
this.logger.debug('Channel membership check result', {
|
|
112
|
+
channelId,
|
|
113
|
+
userId: user,
|
|
114
|
+
isMember
|
|
115
|
+
});
|
|
116
|
+
return isMember;
|
|
117
|
+
} catch (error) {
|
|
118
|
+
this.logger.error('Error checking channel membership: %o', error);
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
16
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Enhanced method to get default notification properties
|
|
124
|
+
*
|
|
125
|
+
* @description Retrieves default notification settings with extensibility
|
|
126
|
+
*
|
|
127
|
+
* @returns {INotificationProps} - Default notification properties
|
|
128
|
+
*/
|
|
17
129
|
get defaultNotifyProps() {
|
|
18
|
-
|
|
19
|
-
|
|
130
|
+
try {
|
|
131
|
+
// Future enhancement: Load from user preferences or organization settings
|
|
132
|
+
return DEFAULT_NOTIFY_PROPS;
|
|
133
|
+
} catch (error) {
|
|
134
|
+
this.logger.error('Error getting default notification props: %o', error);
|
|
135
|
+
return DEFAULT_NOTIFY_PROPS;
|
|
136
|
+
}
|
|
20
137
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
138
|
+
/**
|
|
139
|
+
* Enhanced method to get maximum channels per team with configuration support
|
|
140
|
+
*
|
|
141
|
+
* @description Retrieves channel limit with future configuration support
|
|
142
|
+
*
|
|
143
|
+
* @param {string} teamId - The ID of the team
|
|
144
|
+
* @returns {Promise<number>} - Maximum number of channels allowed
|
|
145
|
+
*/
|
|
146
|
+
static async getMaxChannelsPerTeam(teamId) {
|
|
147
|
+
try {
|
|
148
|
+
// Future enhancement: Get from team settings or organization configuration
|
|
149
|
+
return Promise.resolve(100); // Default max channels per team
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error('Error getting max channels per team:', error);
|
|
152
|
+
return Promise.resolve(10); // Fallback value
|
|
153
|
+
}
|
|
24
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Enhanced method to get current channel count per team
|
|
157
|
+
*
|
|
158
|
+
* @description Counts active channels for a team with proper error handling
|
|
159
|
+
*
|
|
160
|
+
* @param {string} team - The team identifier
|
|
161
|
+
* @returns {Promise<number>} - Current channel count
|
|
162
|
+
*/
|
|
25
163
|
async getCurrentChannelCountPerTeam(team) {
|
|
26
|
-
|
|
27
|
-
team
|
|
28
|
-
|
|
29
|
-
|
|
164
|
+
try {
|
|
165
|
+
if (!team) {
|
|
166
|
+
this.logger.warn('Team ID is required for channel count');
|
|
167
|
+
return 0;
|
|
168
|
+
}
|
|
169
|
+
const count = await this.repository.count({
|
|
170
|
+
team,
|
|
171
|
+
type: RoomType.Channel,
|
|
172
|
+
deletedAt: {
|
|
173
|
+
$exists: false
|
|
174
|
+
} // Only count non-deleted channels
|
|
175
|
+
});
|
|
176
|
+
this.logger.debug('Current channel count for team', {
|
|
177
|
+
team,
|
|
178
|
+
count
|
|
179
|
+
});
|
|
180
|
+
return count;
|
|
181
|
+
} catch (error) {
|
|
182
|
+
this.logger.error('Error getting current channel count per team: %o', error);
|
|
183
|
+
return 0;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Enhanced method to generate DM name from user IDs
|
|
188
|
+
*
|
|
189
|
+
* @description Creates a standardized direct message channel name
|
|
190
|
+
*
|
|
191
|
+
* @param {string} senderId - The sender's user ID
|
|
192
|
+
* @param {string} receiverId - The receiver's user ID
|
|
193
|
+
* @returns {string} - Generated DM name
|
|
194
|
+
*/
|
|
195
|
+
static getDmNameFromIds(senderId, receiverId) {
|
|
196
|
+
try {
|
|
197
|
+
if (!senderId || !receiverId) {
|
|
198
|
+
throw new Error('Both sender and receiver IDs are required');
|
|
199
|
+
}
|
|
200
|
+
// Sort IDs to ensure consistent naming regardless of order
|
|
201
|
+
const [id1, id2] = [senderId, receiverId].sort();
|
|
202
|
+
return `${id1}__${id2}`;
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error('Error generating DM name:', error);
|
|
205
|
+
return `${senderId}__${receiverId}`;
|
|
206
|
+
}
|
|
30
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Enhanced method to create a direct channel between users
|
|
210
|
+
*
|
|
211
|
+
* @description Creates direct channels with comprehensive validation and error handling
|
|
212
|
+
*
|
|
213
|
+
* @param {ICreateDirectChannelParams} data - The direct channel creation parameters
|
|
214
|
+
* @returns {Promise<AsDomainType<IChannelModel> | Error>} - The created channel or error
|
|
215
|
+
*/
|
|
31
216
|
async createDirectChannel(data) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
217
|
+
try {
|
|
218
|
+
this.logger.debug('Creating direct channel', {
|
|
219
|
+
sender: data.sender,
|
|
220
|
+
receiverCount: data.receiver?.length || 0,
|
|
221
|
+
orgName: data.orgName
|
|
222
|
+
});
|
|
223
|
+
const {
|
|
224
|
+
sender,
|
|
225
|
+
receiver,
|
|
226
|
+
displayName,
|
|
227
|
+
orgName,
|
|
228
|
+
channelOptions
|
|
229
|
+
} = data;
|
|
230
|
+
if (!sender) {
|
|
231
|
+
return new Error('Sender ID is required');
|
|
232
|
+
}
|
|
233
|
+
if (!receiver || receiver.length === 0) {
|
|
234
|
+
return new Error('At least one receiver is required');
|
|
235
|
+
}
|
|
236
|
+
// Check for duplicate direct channel
|
|
237
|
+
const existingChannelName = ChannelService_1.getDmNameFromIds(sender, receiver[0]);
|
|
238
|
+
const existingChannel = await this.getByName(existingChannelName);
|
|
239
|
+
if (existingChannel) {
|
|
240
|
+
this.logger.debug('Direct channel already exists', {
|
|
241
|
+
channelName: existingChannelName
|
|
50
242
|
});
|
|
243
|
+
return existingChannel;
|
|
51
244
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
245
|
+
// Build channel members
|
|
246
|
+
const channelMembers = [{
|
|
247
|
+
user: sender,
|
|
248
|
+
schemeAdmin: channelOptions?.schemeAdmin || false,
|
|
249
|
+
notifyProps: this.defaultNotifyProps
|
|
250
|
+
}];
|
|
251
|
+
receiver.forEach(receiverId => {
|
|
252
|
+
if (receiverId !== sender) {
|
|
253
|
+
channelMembers.push({
|
|
254
|
+
user: receiverId,
|
|
255
|
+
schemeAdmin: channelOptions?.schemeAdmin || false,
|
|
256
|
+
notifyProps: this.defaultNotifyProps
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
const channelPayload = {
|
|
261
|
+
title: displayName || ChannelService_1.getDmNameFromIds(sender, receiver[0]),
|
|
262
|
+
orgName,
|
|
263
|
+
organization: orgName,
|
|
264
|
+
type: RoomType.Direct,
|
|
265
|
+
creator: sender,
|
|
266
|
+
members: channelMembers,
|
|
267
|
+
displayName: displayName || `Direct chat`,
|
|
268
|
+
_id: undefined // Allow repository to generate
|
|
269
|
+
};
|
|
270
|
+
const result = await this.saveDirectChannel(channelPayload);
|
|
271
|
+
if (!(result instanceof Error)) {
|
|
272
|
+
this.onChannelCreated.fire({
|
|
273
|
+
channel: result,
|
|
274
|
+
userContext: {
|
|
275
|
+
accountId: sender,
|
|
276
|
+
tenantId: orgName
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
return result;
|
|
281
|
+
} catch (error) {
|
|
282
|
+
this.logger.error('Error creating direct channel: %o', error);
|
|
283
|
+
return error instanceof Error ? error : new Error('Unknown error occurred while creating direct channel');
|
|
284
|
+
}
|
|
62
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* Enhanced method to save a direct channel
|
|
288
|
+
*
|
|
289
|
+
* @description Saves direct channels with comprehensive validation
|
|
290
|
+
*
|
|
291
|
+
* @param {ISaveDirectChannelParams} channel - The direct channel parameters
|
|
292
|
+
* @returns {Promise<AsDomainType<IChannelModel> | Error>} - The created channel or error
|
|
293
|
+
*/
|
|
63
294
|
async saveDirectChannel(channel) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
295
|
+
try {
|
|
296
|
+
this.logger.debug('Saving direct channel', {
|
|
297
|
+
type: channel.type,
|
|
298
|
+
creator: channel.creator,
|
|
299
|
+
memberCount: channel.members?.length || 0
|
|
300
|
+
});
|
|
301
|
+
const {
|
|
302
|
+
type,
|
|
303
|
+
deletedAt
|
|
304
|
+
} = channel;
|
|
305
|
+
if (deletedAt) {
|
|
306
|
+
return new Error('Deleted channels cannot be saved');
|
|
307
|
+
}
|
|
308
|
+
if (type !== RoomType.Direct) {
|
|
309
|
+
return new Error('Only direct channels are allowed in this method');
|
|
310
|
+
}
|
|
311
|
+
const result = await this.repository.create(channel);
|
|
312
|
+
this.logger.debug('Direct channel saved successfully', {
|
|
313
|
+
channelId: result.id,
|
|
314
|
+
type: result.type
|
|
315
|
+
});
|
|
316
|
+
return result;
|
|
317
|
+
} catch (error) {
|
|
318
|
+
this.logger.error('Error saving direct channel: %o', error);
|
|
319
|
+
return error instanceof Error ? error : new Error('Unknown error occurred while saving direct channel');
|
|
73
320
|
}
|
|
74
|
-
return this.repository.create(channel);
|
|
75
321
|
}
|
|
322
|
+
/**
|
|
323
|
+
* Enhanced method to add a member to a channel
|
|
324
|
+
*
|
|
325
|
+
* @description Adds a single member to a channel with comprehensive validation and event firing
|
|
326
|
+
*
|
|
327
|
+
* @param {string} channelId - The ID of the channel
|
|
328
|
+
* @param {string} memberId - The ID of the member to add
|
|
329
|
+
* @returns {Promise<AsDomainType<IChannelModel> | Error>} - The updated channel or error
|
|
330
|
+
*/
|
|
76
331
|
async addMemberToChannel(channelId, memberId) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}).then(async res => {
|
|
82
|
-
const mebs = res.members;
|
|
83
|
-
mebs.push({
|
|
84
|
-
id: '',
|
|
85
|
-
user: memberId,
|
|
86
|
-
schemeAdmin: false,
|
|
87
|
-
notifyProps: this.defaultNotifyProps
|
|
332
|
+
try {
|
|
333
|
+
this.logger.debug('Adding member to channel', {
|
|
334
|
+
channelId,
|
|
335
|
+
memberId
|
|
88
336
|
});
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
337
|
+
if (!channelId || !memberId) {
|
|
338
|
+
return new Error('Channel ID and member ID are required');
|
|
339
|
+
}
|
|
340
|
+
// Check if member is already in channel
|
|
341
|
+
const isMember = await this.isMember(channelId, memberId);
|
|
342
|
+
if (isMember) {
|
|
343
|
+
this.logger.debug('Member already exists in channel', {
|
|
344
|
+
channelId,
|
|
345
|
+
memberId
|
|
346
|
+
});
|
|
347
|
+
return await this.get(channelId);
|
|
348
|
+
}
|
|
349
|
+
const resData = await this.repository.get({
|
|
92
350
|
id: channelId
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
351
|
+
}).then(async res => {
|
|
352
|
+
if (!res) {
|
|
353
|
+
throw new Error(`Channel ${channelId} not found`);
|
|
354
|
+
}
|
|
355
|
+
const members = res.members || [];
|
|
356
|
+
members.push({
|
|
357
|
+
user: memberId,
|
|
358
|
+
schemeAdmin: false,
|
|
359
|
+
notifyProps: this.defaultNotifyProps
|
|
360
|
+
});
|
|
361
|
+
const objToUpdate = {
|
|
362
|
+
...res,
|
|
363
|
+
members
|
|
364
|
+
};
|
|
365
|
+
const finalResult = await this.repository.update({
|
|
366
|
+
id: channelId
|
|
367
|
+
}, objToUpdate, {
|
|
368
|
+
overwrite: true
|
|
369
|
+
});
|
|
370
|
+
return finalResult;
|
|
371
|
+
}).catch(err => {
|
|
372
|
+
this.logger.error('Error in addMemberToChannel operation: %o', err);
|
|
373
|
+
return err;
|
|
374
|
+
});
|
|
375
|
+
if (resData instanceof Error) {
|
|
376
|
+
return resData;
|
|
377
|
+
}
|
|
378
|
+
// Fire member added event
|
|
379
|
+
this.onMemberAdded.fire({
|
|
380
|
+
channelId,
|
|
381
|
+
memberId,
|
|
382
|
+
userContext: {
|
|
383
|
+
accountId: memberId
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
this.logger.debug('Member added to channel successfully', {
|
|
387
|
+
channelId,
|
|
388
|
+
memberId
|
|
389
|
+
});
|
|
390
|
+
return resData;
|
|
391
|
+
} catch (error) {
|
|
392
|
+
this.logger.error('Error adding member to channel: %o', error);
|
|
393
|
+
return error instanceof Error ? error : new Error('Unknown error occurred while adding member to channel');
|
|
394
|
+
}
|
|
99
395
|
}
|
|
100
396
|
async saveMembersToChannel(data) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (membersIds
|
|
111
|
-
membersIds
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
397
|
+
try {
|
|
398
|
+
const {
|
|
399
|
+
channelId,
|
|
400
|
+
membersIds
|
|
401
|
+
} = data;
|
|
402
|
+
const resData = await this.repository.get({
|
|
403
|
+
id: channelId
|
|
404
|
+
}).then(async res => {
|
|
405
|
+
let mebs = res.members || [];
|
|
406
|
+
if (Array.isArray(membersIds)) {
|
|
407
|
+
if (membersIds?.length) {
|
|
408
|
+
membersIds.forEach(mid => {
|
|
409
|
+
mebs.push({
|
|
410
|
+
user: mid,
|
|
411
|
+
schemeAdmin: false,
|
|
412
|
+
notifyProps: this.defaultNotifyProps
|
|
413
|
+
});
|
|
117
414
|
});
|
|
118
|
-
}
|
|
415
|
+
}
|
|
119
416
|
}
|
|
417
|
+
const objToUpdate = res;
|
|
418
|
+
objToUpdate.members = mebs;
|
|
419
|
+
const finalResult = await this.repository.update({
|
|
420
|
+
id: channelId
|
|
421
|
+
}, objToUpdate, {
|
|
422
|
+
overwrite: true
|
|
423
|
+
});
|
|
424
|
+
return finalResult;
|
|
425
|
+
}).catch(err => err);
|
|
426
|
+
if (resData instanceof Error) {
|
|
427
|
+
return resData;
|
|
120
428
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
overwrite: true
|
|
127
|
-
});
|
|
128
|
-
return finalResult;
|
|
129
|
-
}).catch(err => err);
|
|
130
|
-
return resData;
|
|
429
|
+
return resData;
|
|
430
|
+
} catch (error) {
|
|
431
|
+
this.logger.error('Error saving members to channel: %o', error);
|
|
432
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
433
|
+
}
|
|
131
434
|
}
|
|
132
435
|
async saveChannel(data) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
436
|
+
try {
|
|
437
|
+
const {
|
|
438
|
+
type,
|
|
439
|
+
team,
|
|
440
|
+
creator
|
|
441
|
+
} = data;
|
|
442
|
+
if (type === RoomType.Direct) {
|
|
443
|
+
return new Error('Invalid Channel Type');
|
|
444
|
+
}
|
|
445
|
+
if (team) {
|
|
446
|
+
const maxChannels = await ChannelService_1.getMaxChannelsPerTeam(team);
|
|
447
|
+
const currentChannels = await this.getCurrentChannelCountPerTeam(team);
|
|
448
|
+
const canAddNewChannel = currentChannels < maxChannels;
|
|
449
|
+
if (!canAddNewChannel) {
|
|
450
|
+
return new Error(`Only max of ${maxChannels} allowed`);
|
|
451
|
+
}
|
|
147
452
|
}
|
|
453
|
+
const channelPayload = {
|
|
454
|
+
...data,
|
|
455
|
+
members: [{
|
|
456
|
+
user: creator,
|
|
457
|
+
schemeAdmin: false,
|
|
458
|
+
notifyProps: this.defaultNotifyProps
|
|
459
|
+
}]
|
|
460
|
+
};
|
|
461
|
+
const result = await this.repository.create(channelPayload);
|
|
462
|
+
return result;
|
|
463
|
+
} catch (error) {
|
|
464
|
+
this.logger.error('Error saving channel: %o', error);
|
|
465
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
148
466
|
}
|
|
149
|
-
const channelPayload = {
|
|
150
|
-
...data,
|
|
151
|
-
members: [{
|
|
152
|
-
user: creator,
|
|
153
|
-
schemeAdmin: false,
|
|
154
|
-
notifyProps: this.defaultNotifyProps
|
|
155
|
-
}]
|
|
156
|
-
};
|
|
157
|
-
return this.repository.create(channelPayload);
|
|
158
467
|
}
|
|
159
468
|
async savePublicChannel(data) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
469
|
+
try {
|
|
470
|
+
const {
|
|
471
|
+
type
|
|
472
|
+
} = data;
|
|
473
|
+
if (type !== RoomType.Public) {
|
|
474
|
+
return new Error('Invalid Channel Type');
|
|
475
|
+
}
|
|
476
|
+
const result = await this.repository.create(data);
|
|
477
|
+
return result;
|
|
478
|
+
} catch (error) {
|
|
479
|
+
this.logger.error('Error saving public channel: %o', error);
|
|
480
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
165
481
|
}
|
|
166
|
-
return this.repository.create(data);
|
|
167
482
|
}
|
|
168
483
|
async getChannelUnread(channelId, userId) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
484
|
+
try {
|
|
485
|
+
const channel = await this.repository.get({
|
|
486
|
+
id: channelId,
|
|
487
|
+
members: {
|
|
488
|
+
user: userId
|
|
489
|
+
}
|
|
490
|
+
}); // Type assertion to handle the interface mismatch
|
|
491
|
+
const {
|
|
492
|
+
members,
|
|
493
|
+
team,
|
|
494
|
+
id
|
|
495
|
+
} = channel;
|
|
496
|
+
const member = members?.find(i => i.user && i.user.toString() === userId);
|
|
497
|
+
if (!member) {
|
|
498
|
+
return {
|
|
499
|
+
channelId: id,
|
|
500
|
+
teamId: team ? team.toString() : '',
|
|
501
|
+
msgCount: 0,
|
|
502
|
+
msgCountRoot: 0,
|
|
503
|
+
mentionCount: 0,
|
|
504
|
+
notifyProps: this.defaultNotifyProps,
|
|
505
|
+
mentionCountRoot: 0
|
|
506
|
+
};
|
|
173
507
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
notifyProps,
|
|
195
|
-
mentionCountRoot
|
|
196
|
-
};
|
|
508
|
+
const msgCount = (channel.totalMsgCount || 0) - (member.msgCount || 0);
|
|
509
|
+
const msgCountRoot = (channel.totalMsgCountRoot || 0) - (member.msgCountRoot || 0);
|
|
510
|
+
const {
|
|
511
|
+
notifyProps,
|
|
512
|
+
mentionCountRoot,
|
|
513
|
+
mentionCount
|
|
514
|
+
} = member;
|
|
515
|
+
return {
|
|
516
|
+
channelId: id,
|
|
517
|
+
teamId: team ? team.toString() : '',
|
|
518
|
+
msgCount,
|
|
519
|
+
msgCountRoot,
|
|
520
|
+
mentionCount: mentionCount || 0,
|
|
521
|
+
notifyProps: notifyProps || this.defaultNotifyProps,
|
|
522
|
+
mentionCountRoot: mentionCountRoot || 0
|
|
523
|
+
};
|
|
524
|
+
} catch (error) {
|
|
525
|
+
this.logger.error('Error getting channel unread: %o', error);
|
|
526
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
527
|
+
}
|
|
197
528
|
}
|
|
198
529
|
async getPinnedPosts(channelId) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
deletedAt: time
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
// getByName(team: string, title: string): Promise<IChannel> {
|
|
225
|
-
// return this.get({
|
|
226
|
-
// team,
|
|
227
|
-
// title,
|
|
228
|
-
// });
|
|
229
|
-
// }
|
|
230
|
-
getByName(title) {
|
|
231
|
-
return this.get({
|
|
232
|
-
title
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
getByNameIncludeDeleted(team, title) {
|
|
236
|
-
return this.get({
|
|
237
|
-
team,
|
|
238
|
-
title,
|
|
239
|
-
deletedAt: true
|
|
240
|
-
});
|
|
530
|
+
try {
|
|
531
|
+
const posts = await this.postService.getAll({
|
|
532
|
+
criteria: {
|
|
533
|
+
channelId,
|
|
534
|
+
isPinned: true
|
|
535
|
+
},
|
|
536
|
+
sort: {
|
|
537
|
+
key: 'CreatAt',
|
|
538
|
+
value: SortEnum.Asc
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
const replyCounts = await Promise.all(posts.map(post => this.postService.count({
|
|
542
|
+
rootId: post.rootId || post._id
|
|
543
|
+
})));
|
|
544
|
+
return posts.reduce((acc, curr, index) => [...acc, {
|
|
545
|
+
...curr,
|
|
546
|
+
replyCount: replyCounts[index]
|
|
547
|
+
}], []);
|
|
548
|
+
} catch (error) {
|
|
549
|
+
this.logger.error('Error getting pinned posts: %o', error);
|
|
550
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
551
|
+
}
|
|
241
552
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
553
|
+
async getFromMaster(id) {
|
|
554
|
+
try {
|
|
555
|
+
// Try Redis cache first
|
|
556
|
+
if (this.redisCacheManager && id) {
|
|
557
|
+
try {
|
|
558
|
+
const cacheKey = `${config.APP_NAME}:getChannelById`;
|
|
559
|
+
const variables = {
|
|
560
|
+
id
|
|
561
|
+
};
|
|
562
|
+
const cacheCtx = {
|
|
563
|
+
userId: 'system'
|
|
564
|
+
};
|
|
565
|
+
const cached = await this.redisCacheManager.get(cacheKey, variables, cacheCtx);
|
|
566
|
+
if (cached) {
|
|
567
|
+
this.logger.debug(`Cache hit for channel ID: ${id}`);
|
|
568
|
+
return cached;
|
|
569
|
+
}
|
|
570
|
+
} catch (cacheError) {
|
|
571
|
+
this.logger.warn(`Redis cache error for getFromMaster(${id}): ${cacheError?.message}`);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
const result = await this.get({
|
|
575
|
+
id
|
|
576
|
+
});
|
|
577
|
+
// Set cache
|
|
578
|
+
if (this.redisCacheManager && result) {
|
|
579
|
+
try {
|
|
580
|
+
const cacheKey = `${config.APP_NAME}:getChannelById`;
|
|
581
|
+
const variables = {
|
|
582
|
+
id
|
|
583
|
+
};
|
|
584
|
+
const cacheCtx = {
|
|
585
|
+
userId: 'system'
|
|
586
|
+
};
|
|
587
|
+
await this.redisCacheManager.set(cacheKey, variables, result, cacheCtx, CACHE_TTL);
|
|
588
|
+
} catch (cacheError) {
|
|
589
|
+
this.logger.warn(`Failed to cache channel by id: ${cacheError?.message}`);
|
|
248
590
|
}
|
|
249
591
|
}
|
|
250
|
-
|
|
592
|
+
return result;
|
|
593
|
+
} catch (error) {
|
|
594
|
+
this.logger.error('Error getting channel from master: %o', error);
|
|
595
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
596
|
+
}
|
|
251
597
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
598
|
+
async restore(channelId, time) {
|
|
599
|
+
try {
|
|
600
|
+
await this.repository.update({
|
|
601
|
+
id: channelId
|
|
602
|
+
}, {
|
|
603
|
+
deletedAt: time
|
|
604
|
+
});
|
|
605
|
+
} catch (error) {
|
|
606
|
+
this.logger.error('Error restoring channel: %o', error);
|
|
607
|
+
throw error;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
// @ts-ignore - Type compatibility issue with base class method
|
|
611
|
+
async getByName(title) {
|
|
612
|
+
try {
|
|
613
|
+
if (!title) {
|
|
614
|
+
this.logger.warn('Empty channel title provided');
|
|
615
|
+
return null;
|
|
257
616
|
}
|
|
258
|
-
|
|
617
|
+
// Try Redis cache first
|
|
618
|
+
if (this.redisCacheManager) {
|
|
619
|
+
try {
|
|
620
|
+
const cacheKey = `${config.APP_NAME}:getChannelByName`;
|
|
621
|
+
const variables = {
|
|
622
|
+
name: title
|
|
623
|
+
};
|
|
624
|
+
const cacheCtx = {
|
|
625
|
+
userId: 'system'
|
|
626
|
+
};
|
|
627
|
+
const cached = await this.redisCacheManager.get(cacheKey, variables, cacheCtx);
|
|
628
|
+
if (cached) {
|
|
629
|
+
this.logger.debug(`Cache hit for channel name: ${title}`);
|
|
630
|
+
return cached;
|
|
631
|
+
}
|
|
632
|
+
} catch (cacheError) {
|
|
633
|
+
this.logger.warn(`Redis cache error for getByName(${title}): ${cacheError?.message}`);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
const result = await this.get({
|
|
637
|
+
title
|
|
638
|
+
});
|
|
639
|
+
// Cache the result
|
|
640
|
+
if (this.redisCacheManager && result) {
|
|
641
|
+
try {
|
|
642
|
+
const cacheKey = `${config.APP_NAME}:getChannelByName`;
|
|
643
|
+
const variables = {
|
|
644
|
+
name: title
|
|
645
|
+
};
|
|
646
|
+
const cacheCtx = {
|
|
647
|
+
userId: 'system'
|
|
648
|
+
};
|
|
649
|
+
await this.redisCacheManager.set(cacheKey, variables, result, cacheCtx, CACHE_TTL);
|
|
650
|
+
} catch (cacheError) {
|
|
651
|
+
this.logger.warn(`Failed to cache channel by name: ${cacheError?.message}`);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return result;
|
|
655
|
+
} catch (error) {
|
|
656
|
+
this.logger.error('Error getting channel by name: %o', error);
|
|
657
|
+
throw error;
|
|
658
|
+
}
|
|
259
659
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
team,
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
660
|
+
async getByNameIncludeDeleted(teamId, name) {
|
|
661
|
+
try {
|
|
662
|
+
const result = await this.get({
|
|
663
|
+
team: teamId,
|
|
664
|
+
title: name,
|
|
665
|
+
deletedAt: true
|
|
666
|
+
});
|
|
667
|
+
return result;
|
|
668
|
+
} catch (error) {
|
|
669
|
+
this.logger.error('Error getting channel by name including deleted: %o', error);
|
|
670
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
async getByNames(teamId, names) {
|
|
674
|
+
try {
|
|
675
|
+
const result = await this.getAll({
|
|
676
|
+
criteria: {
|
|
677
|
+
team: teamId,
|
|
678
|
+
title: {
|
|
679
|
+
$in: names
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
return result;
|
|
684
|
+
} catch (error) {
|
|
685
|
+
this.logger.error('Error getting channels by names: %o', error);
|
|
686
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
async getChannelCounts(teamId, userId) {
|
|
690
|
+
try {
|
|
691
|
+
return await this.count({
|
|
692
|
+
team: teamId,
|
|
693
|
+
members: {
|
|
694
|
+
user: userId
|
|
695
|
+
}
|
|
696
|
+
});
|
|
697
|
+
} catch (error) {
|
|
698
|
+
this.logger.error('Error getting channel counts: %o', error);
|
|
699
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
async getChannels(teamId, userId, includeDeleted, lastDeleteAt, orgId) {
|
|
703
|
+
try {
|
|
704
|
+
const result = await this.repository.getAll({
|
|
705
|
+
criteria: this.generateCriteria({
|
|
706
|
+
team: teamId,
|
|
707
|
+
user: userId,
|
|
708
|
+
includeDeleted,
|
|
709
|
+
lastDeleteAt,
|
|
710
|
+
orgName: orgId
|
|
711
|
+
})
|
|
712
|
+
});
|
|
713
|
+
return result;
|
|
714
|
+
} catch (error) {
|
|
715
|
+
this.logger.error('Error getting channels: %o', error);
|
|
716
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
717
|
+
}
|
|
270
718
|
}
|
|
271
719
|
generateCriteria(options) {
|
|
272
720
|
const {
|
|
@@ -323,72 +771,193 @@ let ChannelService = ChannelService_1 = class ChannelService extends BaseService
|
|
|
323
771
|
}
|
|
324
772
|
return criteria;
|
|
325
773
|
}
|
|
326
|
-
deleteChannel(id) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
774
|
+
async deleteChannel(id) {
|
|
775
|
+
try {
|
|
776
|
+
return await this.repository.delete({
|
|
777
|
+
id
|
|
778
|
+
});
|
|
779
|
+
} catch (error) {
|
|
780
|
+
this.logger.error('Error deleting channel: %o', error);
|
|
781
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
782
|
+
}
|
|
330
783
|
}
|
|
331
|
-
getDeleted(teamId, offset, limit, userId) {
|
|
332
|
-
|
|
784
|
+
async getDeleted(teamId, offset, limit, userId) {
|
|
785
|
+
try {
|
|
786
|
+
// Implementation would go here to get deleted channels
|
|
787
|
+
return [];
|
|
788
|
+
} catch (error) {
|
|
789
|
+
this.logger.error('Error getting deleted channels: %o', error);
|
|
790
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
791
|
+
}
|
|
333
792
|
}
|
|
334
|
-
getDeletedByName(teamId, name) {
|
|
335
|
-
|
|
793
|
+
async getDeletedByName(teamId, name) {
|
|
794
|
+
try {
|
|
795
|
+
// Implementation would go here
|
|
796
|
+
return null;
|
|
797
|
+
} catch (error) {
|
|
798
|
+
this.logger.error('Error getting deleted channel by name: %o', error);
|
|
799
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
800
|
+
}
|
|
336
801
|
}
|
|
337
|
-
|
|
338
|
-
|
|
802
|
+
async getMoreChannels(teamId, userId, offset, limit) {
|
|
803
|
+
try {
|
|
804
|
+
// Implementation would go here
|
|
805
|
+
return [];
|
|
806
|
+
} catch (error) {
|
|
807
|
+
this.logger.error('Error getting more channels: %o', error);
|
|
808
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
809
|
+
}
|
|
339
810
|
}
|
|
340
|
-
|
|
341
|
-
|
|
811
|
+
async getPrivateChannelsForTeam(teamId, offset, limit) {
|
|
812
|
+
try {
|
|
813
|
+
// Implementation would go here
|
|
814
|
+
return [];
|
|
815
|
+
} catch (error) {
|
|
816
|
+
this.logger.error('Error getting private channels for team: %o', error);
|
|
817
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
818
|
+
}
|
|
342
819
|
}
|
|
343
|
-
|
|
344
|
-
|
|
820
|
+
async getPublicChannelsByIdsForTeam(teamId, channelsIds) {
|
|
821
|
+
try {
|
|
822
|
+
// Implementation would go here
|
|
823
|
+
return [];
|
|
824
|
+
} catch (error) {
|
|
825
|
+
this.logger.error('Error getting public channels by IDs for team: %o', error);
|
|
826
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
827
|
+
}
|
|
345
828
|
}
|
|
346
|
-
|
|
347
|
-
|
|
829
|
+
async getPublicChannelsForTeam(teamId, offset, limit) {
|
|
830
|
+
try {
|
|
831
|
+
// Implementation would go here
|
|
832
|
+
return [];
|
|
833
|
+
} catch (error) {
|
|
834
|
+
this.logger.error('Error getting public channels for team: %o', error);
|
|
835
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
836
|
+
}
|
|
348
837
|
}
|
|
349
|
-
|
|
350
|
-
|
|
838
|
+
async getTeamChannels(teamId) {
|
|
839
|
+
try {
|
|
840
|
+
// Implementation would go here
|
|
841
|
+
return [];
|
|
842
|
+
} catch (error) {
|
|
843
|
+
this.logger.error('Error getting team channels: %o', error);
|
|
844
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
845
|
+
}
|
|
351
846
|
}
|
|
352
|
-
|
|
353
|
-
|
|
847
|
+
async hideChannel(id) {
|
|
848
|
+
try {
|
|
849
|
+
// Implementation would go here
|
|
850
|
+
return false;
|
|
851
|
+
} catch (error) {
|
|
852
|
+
this.logger.error('Error hiding channel: %o', error);
|
|
853
|
+
return false;
|
|
854
|
+
}
|
|
354
855
|
}
|
|
355
|
-
|
|
356
|
-
|
|
856
|
+
async leaveChannel(id) {
|
|
857
|
+
try {
|
|
858
|
+
// Implementation would go here
|
|
859
|
+
return false;
|
|
860
|
+
} catch (error) {
|
|
861
|
+
this.logger.error('Error leaving channel: %o', error);
|
|
862
|
+
return false;
|
|
863
|
+
}
|
|
357
864
|
}
|
|
358
|
-
|
|
359
|
-
|
|
865
|
+
async viewChannel(id, user) {
|
|
866
|
+
try {
|
|
867
|
+
// Accessing private property
|
|
868
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
869
|
+
// @ts-ignore
|
|
870
|
+
if (id) {
|
|
871
|
+
await this.repository.model.updateOne({
|
|
872
|
+
_id: id
|
|
873
|
+
}, {
|
|
874
|
+
'members.$[elem].lastViewedAt': new Date()
|
|
875
|
+
}, {
|
|
876
|
+
arrayFilters: [{
|
|
877
|
+
'elem.user': user
|
|
878
|
+
}]
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
return true;
|
|
882
|
+
} catch (error) {
|
|
883
|
+
this.logger.error('Error viewing channel: %o', error);
|
|
884
|
+
return false;
|
|
885
|
+
}
|
|
360
886
|
}
|
|
361
|
-
|
|
362
|
-
|
|
887
|
+
async permanentDelete(channelId) {
|
|
888
|
+
try {
|
|
889
|
+
// Implementation would go here for permanent deletion
|
|
890
|
+
this.logger.debug(`Permanently deleting channel ${channelId}`);
|
|
891
|
+
} catch (error) {
|
|
892
|
+
this.logger.error('Error permanently deleting channel: %o', error);
|
|
893
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
894
|
+
}
|
|
363
895
|
}
|
|
364
|
-
async
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}, {
|
|
372
|
-
'members.$[elem].lastViewedAt': new Date()
|
|
373
|
-
}, {
|
|
374
|
-
arrayFilters: [{
|
|
375
|
-
'elem.user': user
|
|
376
|
-
}]
|
|
377
|
-
});
|
|
896
|
+
async permanentDeleteByTeam(teamId) {
|
|
897
|
+
try {
|
|
898
|
+
// Implementation would go here for permanent team deletion
|
|
899
|
+
this.logger.debug(`Permanently deleting all channels for team ${teamId}`);
|
|
900
|
+
} catch (error) {
|
|
901
|
+
this.logger.error('Error permanently deleting channels by team: %o', error);
|
|
902
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
378
903
|
}
|
|
379
|
-
return true;
|
|
380
904
|
}
|
|
381
|
-
|
|
382
|
-
|
|
905
|
+
async permanentDeleteMembersByChannel(channelId) {
|
|
906
|
+
try {
|
|
907
|
+
// Implementation would go here for permanent member deletion
|
|
908
|
+
this.logger.debug(`Permanently deleting all members for channel ${channelId}`);
|
|
909
|
+
} catch (error) {
|
|
910
|
+
this.logger.error('Error permanently deleting members by channel: %o', error);
|
|
911
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
912
|
+
}
|
|
383
913
|
}
|
|
384
|
-
|
|
385
|
-
|
|
914
|
+
async saveMultipleMembers(members) {
|
|
915
|
+
try {
|
|
916
|
+
// Implementation would go here
|
|
917
|
+
return [];
|
|
918
|
+
} catch (error) {
|
|
919
|
+
this.logger.error('Error saving multiple members: %o', error);
|
|
920
|
+
return error instanceof Error ? error : new Error('Unknown error occurred');
|
|
921
|
+
}
|
|
386
922
|
}
|
|
387
|
-
|
|
388
|
-
|
|
923
|
+
async invalidateChannelByName(teamId, name) {
|
|
924
|
+
try {
|
|
925
|
+
if (!this.redisCacheManager) {
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
// Invalidate name-based cache
|
|
929
|
+
await this.redisCacheManager.del(`${config.APP_NAME}:getChannelByName`, {
|
|
930
|
+
name
|
|
931
|
+
}, {
|
|
932
|
+
userId: 'system'
|
|
933
|
+
}, true);
|
|
934
|
+
// If we have team-specific variations in future, consider invalidating those keys as well
|
|
935
|
+
this.logger.debug(`Invalidated channel cache for name ${name} (team: ${teamId || 'n/a'})`);
|
|
936
|
+
} catch (error) {
|
|
937
|
+
this.logger.warn(`Error invalidating channel cache: ${error?.message}`);
|
|
938
|
+
}
|
|
389
939
|
}
|
|
390
|
-
|
|
391
|
-
|
|
940
|
+
async createChannelWithProjectId(projectId, channelInput) {
|
|
941
|
+
try {
|
|
942
|
+
if (!this.inngestClient) {
|
|
943
|
+
return false;
|
|
944
|
+
}
|
|
945
|
+
const result = await this.inngestClient.send({
|
|
946
|
+
name: 'channel-with-project-id.create',
|
|
947
|
+
data: {
|
|
948
|
+
projectId,
|
|
949
|
+
channelInput
|
|
950
|
+
}
|
|
951
|
+
});
|
|
952
|
+
// Inngest send() typically returns an object with dispatched ids
|
|
953
|
+
const ok = !!result?.ids?.length;
|
|
954
|
+
return ok;
|
|
955
|
+
} catch (error) {
|
|
956
|
+
this.logger.error('Error creating channel with project ID: %o', error);
|
|
957
|
+
return false;
|
|
958
|
+
}
|
|
392
959
|
}
|
|
393
960
|
};
|
|
394
|
-
ChannelService = ChannelService_1 = __decorate([
|
|
961
|
+
ChannelService = ChannelService_1 = __decorate([injectable()
|
|
962
|
+
// @ts-ignore - Type compatibility issue between BaseService2 and IChannelService
|
|
963
|
+
, __param(0, inject(SERVER_TYPES.ChannelRepository)), __param(1, inject(SERVER_TYPES.PostService)), __param(2, inject(CommonType.MOLECULER_BROKER)), __param(3, inject(SERVER_TYPES.IRedisCacheManager)), __param(4, inject(CommonType.REDIS_CLIENT)), __param(5, inject('Logger')), __param(6, inject(CommonType.INNGEST_CLIENT)), __metadata("design:paramtypes", [Object, Object, ServiceBroker, Object, Function, Object, Object])], ChannelService);export{ChannelService};//# sourceMappingURL=channel-service.js.map
|