@flusys/nestjs-notification 3.0.1 → 4.0.0-lts
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/cjs/config/index.js +1 -0
- package/cjs/config/message-keys.js +39 -0
- package/cjs/controllers/notification.controller.js +22 -10
- package/cjs/gateways/notification.gateway.js +9 -19
- package/cjs/services/notification-datasource.provider.js +6 -2
- package/cjs/services/notification-helper.service.js +38 -6
- package/cjs/services/notification.service.js +39 -4
- package/config/index.d.ts +1 -0
- package/config/message-keys.d.ts +36 -0
- package/fesm/config/index.js +1 -0
- package/fesm/config/message-keys.js +22 -0
- package/fesm/controllers/notification.controller.js +15 -3
- package/fesm/gateways/notification.gateway.js +10 -20
- package/fesm/services/notification-datasource.provider.js +7 -3
- package/fesm/services/notification-helper.service.js +39 -7
- package/fesm/services/notification.service.js +39 -4
- package/gateways/notification.gateway.d.ts +0 -1
- package/package.json +5 -4
- package/services/notification-datasource.provider.d.ts +0 -2
- package/services/notification-helper.service.d.ts +0 -1
- package/services/notification.service.d.ts +2 -2
package/cjs/config/index.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
5
|
_export_star(require("./notification.constants"), exports);
|
|
6
|
+
_export_star(require("./message-keys"), exports);
|
|
6
7
|
function _export_star(from, to) {
|
|
7
8
|
Object.keys(from).forEach(function(k) {
|
|
8
9
|
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// ==================== NOTIFICATION MODULE MESSAGE KEYS ====================
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
function _export(target, all) {
|
|
7
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
_export(exports, {
|
|
13
|
+
get NOTIFICATION_MESSAGES () {
|
|
14
|
+
return NOTIFICATION_MESSAGES;
|
|
15
|
+
},
|
|
16
|
+
get NOTIFICATION_MODULE_MESSAGES () {
|
|
17
|
+
return NOTIFICATION_MODULE_MESSAGES;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
const NOTIFICATION_MESSAGES = {
|
|
21
|
+
CREATE_SUCCESS: 'notification.create.success',
|
|
22
|
+
CREATE_MANY_SUCCESS: 'notification.create.many.success',
|
|
23
|
+
GET_SUCCESS: 'notification.get.success',
|
|
24
|
+
GET_ALL_SUCCESS: 'notification.get.all.success',
|
|
25
|
+
UPDATE_SUCCESS: 'notification.update.success',
|
|
26
|
+
UPDATE_MANY_SUCCESS: 'notification.update.many.success',
|
|
27
|
+
DELETE_SUCCESS: 'notification.delete.success',
|
|
28
|
+
RESTORE_SUCCESS: 'notification.restore.success',
|
|
29
|
+
NOT_FOUND: 'notification.not.found',
|
|
30
|
+
MARK_READ_SUCCESS: 'notification.mark.read.success',
|
|
31
|
+
MARK_ALL_READ_SUCCESS: 'notification.mark.all.read.success',
|
|
32
|
+
UNREAD_COUNT_SUCCESS: 'notification.unread.count.success',
|
|
33
|
+
MY_NOTIFICATIONS_SUCCESS: 'notification.my.notifications.success',
|
|
34
|
+
SEND_SUCCESS: 'notification.send.success',
|
|
35
|
+
BROADCAST_SUCCESS: 'notification.broadcast.success'
|
|
36
|
+
};
|
|
37
|
+
const NOTIFICATION_MODULE_MESSAGES = {
|
|
38
|
+
NOTIFICATION: NOTIFICATION_MESSAGES
|
|
39
|
+
};
|
|
@@ -9,7 +9,7 @@ Object.defineProperty(exports, "NotificationController", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _classes = require("@flusys/nestjs-shared/classes");
|
|
12
|
-
const
|
|
12
|
+
const _config = require("../config");
|
|
13
13
|
const _decorators = require("@flusys/nestjs-shared/decorators");
|
|
14
14
|
const _dtos = require("@flusys/nestjs-shared/dtos");
|
|
15
15
|
const _guards = require("@flusys/nestjs-shared/guards");
|
|
@@ -48,23 +48,24 @@ function _ts_param(paramIndex, decorator) {
|
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
50
|
let NotificationController = class NotificationController extends (0, _classes.createApiController)(_dtos1.CreateNotificationDto, _dtos1.UpdateNotificationDto, _dtos1.NotificationResponseDto, {
|
|
51
|
+
entityName: 'notification',
|
|
51
52
|
security: {
|
|
52
53
|
insert: {
|
|
53
54
|
level: 'permission',
|
|
54
55
|
permissions: [
|
|
55
|
-
|
|
56
|
+
_classes.NOTIFICATION_PERMISSIONS.CREATE
|
|
56
57
|
]
|
|
57
58
|
},
|
|
58
59
|
insertMany: {
|
|
59
60
|
level: 'permission',
|
|
60
61
|
permissions: [
|
|
61
|
-
|
|
62
|
+
_classes.NOTIFICATION_PERMISSIONS.CREATE
|
|
62
63
|
]
|
|
63
64
|
},
|
|
64
65
|
getById: {
|
|
65
66
|
level: 'permission',
|
|
66
67
|
permissions: [
|
|
67
|
-
|
|
68
|
+
_classes.NOTIFICATION_PERMISSIONS.READ
|
|
68
69
|
]
|
|
69
70
|
},
|
|
70
71
|
getAll: {
|
|
@@ -73,19 +74,19 @@ let NotificationController = class NotificationController extends (0, _classes.c
|
|
|
73
74
|
update: {
|
|
74
75
|
level: 'permission',
|
|
75
76
|
permissions: [
|
|
76
|
-
|
|
77
|
+
_classes.NOTIFICATION_PERMISSIONS.UPDATE
|
|
77
78
|
]
|
|
78
79
|
},
|
|
79
80
|
updateMany: {
|
|
80
81
|
level: 'permission',
|
|
81
82
|
permissions: [
|
|
82
|
-
|
|
83
|
+
_classes.NOTIFICATION_PERMISSIONS.UPDATE
|
|
83
84
|
]
|
|
84
85
|
},
|
|
85
86
|
delete: {
|
|
86
87
|
level: 'permission',
|
|
87
88
|
permissions: [
|
|
88
|
-
|
|
89
|
+
_classes.NOTIFICATION_PERMISSIONS.DELETE
|
|
89
90
|
]
|
|
90
91
|
}
|
|
91
92
|
}
|
|
@@ -95,6 +96,7 @@ let NotificationController = class NotificationController extends (0, _classes.c
|
|
|
95
96
|
return {
|
|
96
97
|
success: true,
|
|
97
98
|
message: 'Notification marked as read',
|
|
99
|
+
messageKey: _config.NOTIFICATION_MESSAGES.MARK_READ_SUCCESS,
|
|
98
100
|
data: (0, _classtransformer.plainToInstance)(_dtos1.NotificationResponseDto, notification)
|
|
99
101
|
};
|
|
100
102
|
}
|
|
@@ -102,7 +104,11 @@ let NotificationController = class NotificationController extends (0, _classes.c
|
|
|
102
104
|
const count = await this.service.markAllAsRead(user);
|
|
103
105
|
return {
|
|
104
106
|
success: true,
|
|
105
|
-
message: `${count} notifications marked as read
|
|
107
|
+
message: `${count} notifications marked as read`,
|
|
108
|
+
messageKey: _config.NOTIFICATION_MESSAGES.MARK_ALL_READ_SUCCESS,
|
|
109
|
+
messageVariables: {
|
|
110
|
+
count
|
|
111
|
+
}
|
|
106
112
|
};
|
|
107
113
|
}
|
|
108
114
|
async getUnreadCount(user) {
|
|
@@ -110,6 +116,7 @@ let NotificationController = class NotificationController extends (0, _classes.c
|
|
|
110
116
|
return {
|
|
111
117
|
success: true,
|
|
112
118
|
message: 'Unread count retrieved',
|
|
119
|
+
messageKey: _config.NOTIFICATION_MESSAGES.UNREAD_COUNT_SUCCESS,
|
|
113
120
|
data: {
|
|
114
121
|
count
|
|
115
122
|
}
|
|
@@ -127,6 +134,7 @@ let NotificationController = class NotificationController extends (0, _classes.c
|
|
|
127
134
|
return {
|
|
128
135
|
success: true,
|
|
129
136
|
message: 'Notification sent successfully',
|
|
137
|
+
messageKey: _config.NOTIFICATION_MESSAGES.SEND_SUCCESS,
|
|
130
138
|
data: (0, _classtransformer.plainToInstance)(_dtos1.NotificationResponseDto, notification)
|
|
131
139
|
};
|
|
132
140
|
}
|
|
@@ -142,6 +150,10 @@ let NotificationController = class NotificationController extends (0, _classes.c
|
|
|
142
150
|
return {
|
|
143
151
|
success: true,
|
|
144
152
|
message: `${notifications.length} notifications sent successfully`,
|
|
153
|
+
messageKey: _config.NOTIFICATION_MESSAGES.BROADCAST_SUCCESS,
|
|
154
|
+
messageVariables: {
|
|
155
|
+
count: notifications.length
|
|
156
|
+
},
|
|
145
157
|
data: notifications.map((n)=>(0, _classtransformer.plainToInstance)(_dtos1.NotificationResponseDto, n)),
|
|
146
158
|
meta: {
|
|
147
159
|
count: notifications.length,
|
|
@@ -222,7 +234,7 @@ _ts_decorate([
|
|
|
222
234
|
(0, _common.Post)('send'),
|
|
223
235
|
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
224
236
|
(0, _common.UseGuards)(_guards.JwtAuthGuard, _guards.PermissionGuard),
|
|
225
|
-
(0, _decorators.RequirePermission)(
|
|
237
|
+
(0, _decorators.RequirePermission)(_classes.NOTIFICATION_PERMISSIONS.CREATE),
|
|
226
238
|
(0, _swagger.ApiOperation)({
|
|
227
239
|
summary: 'Send a notification to a user'
|
|
228
240
|
}),
|
|
@@ -245,7 +257,7 @@ _ts_decorate([
|
|
|
245
257
|
(0, _common.Post)('send-bulk'),
|
|
246
258
|
(0, _common.HttpCode)(_common.HttpStatus.OK),
|
|
247
259
|
(0, _common.UseGuards)(_guards.JwtAuthGuard, _guards.PermissionGuard),
|
|
248
|
-
(0, _decorators.RequirePermission)(
|
|
260
|
+
(0, _decorators.RequirePermission)(_classes.NOTIFICATION_PERMISSIONS.CREATE),
|
|
249
261
|
(0, _swagger.ApiOperation)({
|
|
250
262
|
summary: 'Send a notification to multiple users'
|
|
251
263
|
}),
|
|
@@ -83,19 +83,17 @@ function _ts_param(paramIndex, decorator) {
|
|
|
83
83
|
}
|
|
84
84
|
let NotificationGateway = class NotificationGateway {
|
|
85
85
|
afterInit() {
|
|
86
|
-
|
|
86
|
+
// Gateway initialized
|
|
87
87
|
}
|
|
88
88
|
async handleConnection(client) {
|
|
89
89
|
try {
|
|
90
90
|
const token = this.extractToken(client);
|
|
91
91
|
if (!token) {
|
|
92
|
-
this.logger.warn(`Client ${client.id} connection rejected: No token provided`);
|
|
93
92
|
client.disconnect();
|
|
94
93
|
return;
|
|
95
94
|
}
|
|
96
95
|
const payload = this.verifyToken(token);
|
|
97
96
|
if (!payload) {
|
|
98
|
-
this.logger.warn(`Client ${client.id} connection rejected: Invalid token`);
|
|
99
97
|
client.disconnect();
|
|
100
98
|
return;
|
|
101
99
|
}
|
|
@@ -110,9 +108,7 @@ let NotificationGateway = class NotificationGateway {
|
|
|
110
108
|
if (payload.companyId) {
|
|
111
109
|
client.join(`company:${payload.companyId}`);
|
|
112
110
|
}
|
|
113
|
-
|
|
114
|
-
} catch (error) {
|
|
115
|
-
this.logger.error(`Client ${client.id} connection error: ${error}`);
|
|
111
|
+
} catch {
|
|
116
112
|
client.disconnect();
|
|
117
113
|
}
|
|
118
114
|
}
|
|
@@ -124,11 +120,10 @@ let NotificationGateway = class NotificationGateway {
|
|
|
124
120
|
if (sockets?.size === 0) {
|
|
125
121
|
this.connectedUsers.delete(userId);
|
|
126
122
|
}
|
|
127
|
-
this.logger.log(`Client ${client.id} disconnected for user ${userId}`);
|
|
128
123
|
}
|
|
129
124
|
}
|
|
130
125
|
emitToUser(userId, event, data) {
|
|
131
|
-
this.server
|
|
126
|
+
this.server?.to(`user:${userId}`).emit(event, data);
|
|
132
127
|
}
|
|
133
128
|
/**
|
|
134
129
|
* Emit to a specific user only on sockets connected with a specific company.
|
|
@@ -140,19 +135,18 @@ let NotificationGateway = class NotificationGateway {
|
|
|
140
135
|
* @param event - The event name
|
|
141
136
|
* @param data - The payload
|
|
142
137
|
*/ emitToUserInCompany(userId, companyId, event, data) {
|
|
138
|
+
if (!this.server?.sockets?.adapter) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
143
141
|
if (!companyId) {
|
|
144
|
-
// No company context - emit to all user's sockets
|
|
145
142
|
this.emitToUser(userId, event, data);
|
|
146
143
|
return;
|
|
147
144
|
}
|
|
148
|
-
// Get all sockets in the user's room
|
|
149
145
|
const userRoom = `user:${userId}`;
|
|
150
146
|
const sockets = this.server.sockets.adapter.rooms.get(userRoom);
|
|
151
147
|
if (!sockets) {
|
|
152
|
-
this.logger.debug(`No sockets found for user ${userId}`);
|
|
153
148
|
return;
|
|
154
149
|
}
|
|
155
|
-
// Emit only to sockets that match the company context
|
|
156
150
|
for (const socketId of sockets){
|
|
157
151
|
const socket = this.server.sockets.sockets.get(socketId);
|
|
158
152
|
if (socket && socket.data.companyId === companyId) {
|
|
@@ -161,10 +155,10 @@ let NotificationGateway = class NotificationGateway {
|
|
|
161
155
|
}
|
|
162
156
|
}
|
|
163
157
|
emitToCompany(companyId, event, data) {
|
|
164
|
-
this.server
|
|
158
|
+
this.server?.to(`company:${companyId}`).emit(event, data);
|
|
165
159
|
}
|
|
166
160
|
broadcast(event, data) {
|
|
167
|
-
this.server
|
|
161
|
+
this.server?.emit(event, data);
|
|
168
162
|
}
|
|
169
163
|
isUserOnline(userId) {
|
|
170
164
|
return this.connectedUsers.has(userId);
|
|
@@ -187,22 +181,18 @@ let NotificationGateway = class NotificationGateway {
|
|
|
187
181
|
try {
|
|
188
182
|
const secret = this.configService.getJwtSecret();
|
|
189
183
|
if (!secret) {
|
|
190
|
-
this.logger.error('No JWT secret configured for WebSocket authentication');
|
|
191
184
|
return null;
|
|
192
185
|
}
|
|
193
186
|
return _jsonwebtoken.verify(token, secret);
|
|
194
|
-
} catch
|
|
195
|
-
this.logger.warn(`Token verification failed: ${error}`);
|
|
187
|
+
} catch {
|
|
196
188
|
return null;
|
|
197
189
|
}
|
|
198
190
|
}
|
|
199
191
|
constructor(configService){
|
|
200
192
|
_define_property(this, "configService", void 0);
|
|
201
|
-
_define_property(this, "logger", void 0);
|
|
202
193
|
_define_property(this, "connectedUsers", void 0);
|
|
203
194
|
_define_property(this, "server", void 0);
|
|
204
195
|
this.configService = configService;
|
|
205
|
-
this.logger = new _common.Logger(NotificationGateway.name);
|
|
206
196
|
this.connectedUsers = new Map();
|
|
207
197
|
}
|
|
208
198
|
};
|
|
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "NotificationDataSourceProvider", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _modules = require("@flusys/nestjs-shared/modules");
|
|
12
|
+
const _constants = require("@flusys/nestjs-shared/constants");
|
|
12
13
|
const _common = require("@nestjs/common");
|
|
13
14
|
const _core = require("@nestjs/core");
|
|
14
15
|
const _express = require("express");
|
|
@@ -117,7 +118,10 @@ let NotificationDataSourceProvider = class NotificationDataSourceProvider extend
|
|
|
117
118
|
}
|
|
118
119
|
const config = this.getDefaultDatabaseConfig();
|
|
119
120
|
if (!config) {
|
|
120
|
-
throw new _common.InternalServerErrorException(
|
|
121
|
+
throw new _common.InternalServerErrorException({
|
|
122
|
+
message: 'No database config available. Provide defaultDatabaseConfig or tenantDefaultDatabaseConfig.',
|
|
123
|
+
messageKey: _constants.SYSTEM_MESSAGES.DATABASE_CONFIG_NOT_AVAILABLE
|
|
124
|
+
});
|
|
121
125
|
}
|
|
122
126
|
const connectionPromise = this.createDataSourceFromConfig(config);
|
|
123
127
|
NotificationDataSourceProvider.singleConnectionLock = connectionPromise;
|
|
@@ -150,7 +154,7 @@ let NotificationDataSourceProvider = class NotificationDataSourceProvider extend
|
|
|
150
154
|
}
|
|
151
155
|
}
|
|
152
156
|
constructor(configService, request){
|
|
153
|
-
super(NotificationDataSourceProvider.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0),
|
|
157
|
+
super(NotificationDataSourceProvider.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0), this.configService = configService;
|
|
154
158
|
}
|
|
155
159
|
};
|
|
156
160
|
_define_property(NotificationDataSourceProvider, "tenantConnections", new Map());
|
|
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "NotificationHelperService", {
|
|
|
10
10
|
});
|
|
11
11
|
const _common = require("@nestjs/common");
|
|
12
12
|
const _classes = require("@flusys/nestjs-shared/classes");
|
|
13
|
+
const _nestjsshared = require("@flusys/nestjs-shared");
|
|
13
14
|
const _modules = require("@flusys/nestjs-shared/modules");
|
|
14
15
|
const _notificationconfigservice = require("./notification-config.service");
|
|
15
16
|
const _notificationdatasourceprovider = require("./notification-datasource.provider");
|
|
@@ -72,7 +73,6 @@ let NotificationHelperService = class NotificationHelperService {
|
|
|
72
73
|
const saved = await repo.save(entity);
|
|
73
74
|
await this.clearCache();
|
|
74
75
|
this.emitRealtime(saved);
|
|
75
|
-
this.logger.debug(`Notification sent to user ${userId}: ${title}`);
|
|
76
76
|
return saved;
|
|
77
77
|
}
|
|
78
78
|
async sendToMany(options) {
|
|
@@ -94,12 +94,10 @@ let NotificationHelperService = class NotificationHelperService {
|
|
|
94
94
|
for (const notification of saved){
|
|
95
95
|
this.emitRealtime(notification);
|
|
96
96
|
}
|
|
97
|
-
this.logger.debug(`Notification sent to ${userIds.length} users: ${title}`);
|
|
98
97
|
return saved;
|
|
99
98
|
}
|
|
100
99
|
async sendToCompany(companyId, title, message, type = _enums.NotificationType.INFO, data) {
|
|
101
100
|
if (!this.configService.isCompanyFeatureEnabled()) {
|
|
102
|
-
this.logger.warn('sendToCompany called but company feature is disabled');
|
|
103
101
|
return;
|
|
104
102
|
}
|
|
105
103
|
if (this.configService.isRealtimeEnabled() && this.gateway) {
|
|
@@ -112,7 +110,6 @@ let NotificationHelperService = class NotificationHelperService {
|
|
|
112
110
|
createdAt: new Date()
|
|
113
111
|
};
|
|
114
112
|
this.gateway.emitToCompany(companyId, 'notification:new', payload);
|
|
115
|
-
this.logger.debug(`Broadcast notification sent to company ${companyId}: ${title}`);
|
|
116
113
|
}
|
|
117
114
|
}
|
|
118
115
|
isUserOnline(userId) {
|
|
@@ -154,7 +151,6 @@ let NotificationHelperService = class NotificationHelperService {
|
|
|
154
151
|
_define_property(this, "configService", void 0);
|
|
155
152
|
_define_property(this, "dataSourceProvider", void 0);
|
|
156
153
|
_define_property(this, "gateway", void 0);
|
|
157
|
-
_define_property(this, "logger", void 0);
|
|
158
154
|
_define_property(this, "entityName", void 0);
|
|
159
155
|
_define_property(this, "dataSource", void 0);
|
|
160
156
|
this.cacheManager = cacheManager;
|
|
@@ -162,11 +158,47 @@ let NotificationHelperService = class NotificationHelperService {
|
|
|
162
158
|
this.configService = configService;
|
|
163
159
|
this.dataSourceProvider = dataSourceProvider;
|
|
164
160
|
this.gateway = gateway;
|
|
165
|
-
this.logger = new _common.Logger(NotificationHelperService.name);
|
|
166
161
|
this.entityName = 'notification';
|
|
167
162
|
this.dataSource = null;
|
|
168
163
|
}
|
|
169
164
|
};
|
|
165
|
+
_ts_decorate([
|
|
166
|
+
(0, _nestjsshared.LogAction)({
|
|
167
|
+
action: 'notification.send',
|
|
168
|
+
module: 'notification'
|
|
169
|
+
}),
|
|
170
|
+
_ts_metadata("design:type", Function),
|
|
171
|
+
_ts_metadata("design:paramtypes", [
|
|
172
|
+
typeof SendNotificationOptions === "undefined" ? Object : SendNotificationOptions
|
|
173
|
+
]),
|
|
174
|
+
_ts_metadata("design:returntype", Promise)
|
|
175
|
+
], NotificationHelperService.prototype, "send", null);
|
|
176
|
+
_ts_decorate([
|
|
177
|
+
(0, _nestjsshared.LogAction)({
|
|
178
|
+
action: 'notification.sendToMany',
|
|
179
|
+
module: 'notification'
|
|
180
|
+
}),
|
|
181
|
+
_ts_metadata("design:type", Function),
|
|
182
|
+
_ts_metadata("design:paramtypes", [
|
|
183
|
+
typeof SendBulkNotificationOptions === "undefined" ? Object : SendBulkNotificationOptions
|
|
184
|
+
]),
|
|
185
|
+
_ts_metadata("design:returntype", Promise)
|
|
186
|
+
], NotificationHelperService.prototype, "sendToMany", null);
|
|
187
|
+
_ts_decorate([
|
|
188
|
+
(0, _nestjsshared.LogAction)({
|
|
189
|
+
action: 'notification.sendToCompany',
|
|
190
|
+
module: 'notification'
|
|
191
|
+
}),
|
|
192
|
+
_ts_metadata("design:type", Function),
|
|
193
|
+
_ts_metadata("design:paramtypes", [
|
|
194
|
+
String,
|
|
195
|
+
String,
|
|
196
|
+
Object,
|
|
197
|
+
Object,
|
|
198
|
+
Object
|
|
199
|
+
]),
|
|
200
|
+
_ts_metadata("design:returntype", Promise)
|
|
201
|
+
], NotificationHelperService.prototype, "sendToCompany", null);
|
|
170
202
|
NotificationHelperService = _ts_decorate([
|
|
171
203
|
(0, _common.Injectable)(),
|
|
172
204
|
_ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
|
|
@@ -9,6 +9,9 @@ Object.defineProperty(exports, "NotificationService", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _classes = require("@flusys/nestjs-shared/classes");
|
|
12
|
+
const _nestjsshared = require("@flusys/nestjs-shared");
|
|
13
|
+
const _config = require("../config");
|
|
14
|
+
const _interfaces = require("@flusys/nestjs-shared/interfaces");
|
|
12
15
|
const _modules = require("@flusys/nestjs-shared/modules");
|
|
13
16
|
const _utils = require("@flusys/nestjs-shared/utils");
|
|
14
17
|
const _common = require("@nestjs/common");
|
|
@@ -58,7 +61,12 @@ let NotificationService = class NotificationService extends _classes.RequestScop
|
|
|
58
61
|
id: dto.id
|
|
59
62
|
}
|
|
60
63
|
});
|
|
61
|
-
if (!existing)
|
|
64
|
+
if (!existing) {
|
|
65
|
+
throw new _common.NotFoundException({
|
|
66
|
+
message: 'Notification not found',
|
|
67
|
+
messageKey: _config.NOTIFICATION_MESSAGES.NOT_FOUND
|
|
68
|
+
});
|
|
69
|
+
}
|
|
62
70
|
entity = existing;
|
|
63
71
|
}
|
|
64
72
|
const merged = {
|
|
@@ -108,7 +116,8 @@ let NotificationService = class NotificationService extends _classes.RequestScop
|
|
|
108
116
|
isCompanyFeatureEnabled: this.notificationConfig.isCompanyFeatureEnabled(),
|
|
109
117
|
entityAlias: this.entityName
|
|
110
118
|
}, user);
|
|
111
|
-
|
|
119
|
+
const filterSort = filterDto?.sort;
|
|
120
|
+
if (!filterSort || Object.keys(filterSort).length === 0) {
|
|
112
121
|
query.orderBy(`${this.entityName}.createdAt`, 'DESC');
|
|
113
122
|
}
|
|
114
123
|
return result;
|
|
@@ -128,7 +137,10 @@ let NotificationService = class NotificationService extends _classes.RequestScop
|
|
|
128
137
|
}
|
|
129
138
|
});
|
|
130
139
|
if (!notification) {
|
|
131
|
-
throw new _common.NotFoundException(
|
|
140
|
+
throw new _common.NotFoundException({
|
|
141
|
+
message: 'Notification not found',
|
|
142
|
+
messageKey: _config.NOTIFICATION_MESSAGES.NOT_FOUND
|
|
143
|
+
});
|
|
132
144
|
}
|
|
133
145
|
notification.isRead = true;
|
|
134
146
|
notification.readAt = new Date();
|
|
@@ -196,9 +208,32 @@ let NotificationService = class NotificationService extends _classes.RequestScop
|
|
|
196
208
|
}
|
|
197
209
|
}
|
|
198
210
|
constructor(cacheManager, utilsService, notificationConfig, dataSourceProvider, gateway){
|
|
199
|
-
super('notification', null, cacheManager, utilsService, NotificationService.name, false), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "notificationConfig", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "gateway", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.notificationConfig = notificationConfig, this.dataSourceProvider = dataSourceProvider, this.gateway = gateway;
|
|
211
|
+
super('notification', null, cacheManager, utilsService, NotificationService.name, false, 'notification'), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "notificationConfig", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "gateway", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.notificationConfig = notificationConfig, this.dataSourceProvider = dataSourceProvider, this.gateway = gateway;
|
|
200
212
|
}
|
|
201
213
|
};
|
|
214
|
+
_ts_decorate([
|
|
215
|
+
(0, _nestjsshared.LogAction)({
|
|
216
|
+
action: 'notification.markAsRead',
|
|
217
|
+
module: 'notification'
|
|
218
|
+
}),
|
|
219
|
+
_ts_metadata("design:type", Function),
|
|
220
|
+
_ts_metadata("design:paramtypes", [
|
|
221
|
+
String,
|
|
222
|
+
typeof _interfaces.ILoggedUserInfo === "undefined" ? Object : _interfaces.ILoggedUserInfo
|
|
223
|
+
]),
|
|
224
|
+
_ts_metadata("design:returntype", Promise)
|
|
225
|
+
], NotificationService.prototype, "markAsRead", null);
|
|
226
|
+
_ts_decorate([
|
|
227
|
+
(0, _nestjsshared.LogAction)({
|
|
228
|
+
action: 'notification.markAllAsRead',
|
|
229
|
+
module: 'notification'
|
|
230
|
+
}),
|
|
231
|
+
_ts_metadata("design:type", Function),
|
|
232
|
+
_ts_metadata("design:paramtypes", [
|
|
233
|
+
typeof _interfaces.ILoggedUserInfo === "undefined" ? Object : _interfaces.ILoggedUserInfo
|
|
234
|
+
]),
|
|
235
|
+
_ts_metadata("design:returntype", Promise)
|
|
236
|
+
], NotificationService.prototype, "markAllAsRead", null);
|
|
202
237
|
NotificationService = _ts_decorate([
|
|
203
238
|
(0, _common.Injectable)({
|
|
204
239
|
scope: _common.Scope.REQUEST
|
package/config/index.d.ts
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export declare const NOTIFICATION_MESSAGES: {
|
|
2
|
+
readonly CREATE_SUCCESS: "notification.create.success";
|
|
3
|
+
readonly CREATE_MANY_SUCCESS: "notification.create.many.success";
|
|
4
|
+
readonly GET_SUCCESS: "notification.get.success";
|
|
5
|
+
readonly GET_ALL_SUCCESS: "notification.get.all.success";
|
|
6
|
+
readonly UPDATE_SUCCESS: "notification.update.success";
|
|
7
|
+
readonly UPDATE_MANY_SUCCESS: "notification.update.many.success";
|
|
8
|
+
readonly DELETE_SUCCESS: "notification.delete.success";
|
|
9
|
+
readonly RESTORE_SUCCESS: "notification.restore.success";
|
|
10
|
+
readonly NOT_FOUND: "notification.not.found";
|
|
11
|
+
readonly MARK_READ_SUCCESS: "notification.mark.read.success";
|
|
12
|
+
readonly MARK_ALL_READ_SUCCESS: "notification.mark.all.read.success";
|
|
13
|
+
readonly UNREAD_COUNT_SUCCESS: "notification.unread.count.success";
|
|
14
|
+
readonly MY_NOTIFICATIONS_SUCCESS: "notification.my.notifications.success";
|
|
15
|
+
readonly SEND_SUCCESS: "notification.send.success";
|
|
16
|
+
readonly BROADCAST_SUCCESS: "notification.broadcast.success";
|
|
17
|
+
};
|
|
18
|
+
export declare const NOTIFICATION_MODULE_MESSAGES: {
|
|
19
|
+
readonly NOTIFICATION: {
|
|
20
|
+
readonly CREATE_SUCCESS: "notification.create.success";
|
|
21
|
+
readonly CREATE_MANY_SUCCESS: "notification.create.many.success";
|
|
22
|
+
readonly GET_SUCCESS: "notification.get.success";
|
|
23
|
+
readonly GET_ALL_SUCCESS: "notification.get.all.success";
|
|
24
|
+
readonly UPDATE_SUCCESS: "notification.update.success";
|
|
25
|
+
readonly UPDATE_MANY_SUCCESS: "notification.update.many.success";
|
|
26
|
+
readonly DELETE_SUCCESS: "notification.delete.success";
|
|
27
|
+
readonly RESTORE_SUCCESS: "notification.restore.success";
|
|
28
|
+
readonly NOT_FOUND: "notification.not.found";
|
|
29
|
+
readonly MARK_READ_SUCCESS: "notification.mark.read.success";
|
|
30
|
+
readonly MARK_ALL_READ_SUCCESS: "notification.mark.all.read.success";
|
|
31
|
+
readonly UNREAD_COUNT_SUCCESS: "notification.unread.count.success";
|
|
32
|
+
readonly MY_NOTIFICATIONS_SUCCESS: "notification.my.notifications.success";
|
|
33
|
+
readonly SEND_SUCCESS: "notification.send.success";
|
|
34
|
+
readonly BROADCAST_SUCCESS: "notification.broadcast.success";
|
|
35
|
+
};
|
|
36
|
+
};
|
package/fesm/config/index.js
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// ==================== NOTIFICATION MODULE MESSAGE KEYS ====================
|
|
2
|
+
export const NOTIFICATION_MESSAGES = {
|
|
3
|
+
CREATE_SUCCESS: 'notification.create.success',
|
|
4
|
+
CREATE_MANY_SUCCESS: 'notification.create.many.success',
|
|
5
|
+
GET_SUCCESS: 'notification.get.success',
|
|
6
|
+
GET_ALL_SUCCESS: 'notification.get.all.success',
|
|
7
|
+
UPDATE_SUCCESS: 'notification.update.success',
|
|
8
|
+
UPDATE_MANY_SUCCESS: 'notification.update.many.success',
|
|
9
|
+
DELETE_SUCCESS: 'notification.delete.success',
|
|
10
|
+
RESTORE_SUCCESS: 'notification.restore.success',
|
|
11
|
+
NOT_FOUND: 'notification.not.found',
|
|
12
|
+
MARK_READ_SUCCESS: 'notification.mark.read.success',
|
|
13
|
+
MARK_ALL_READ_SUCCESS: 'notification.mark.all.read.success',
|
|
14
|
+
UNREAD_COUNT_SUCCESS: 'notification.unread.count.success',
|
|
15
|
+
MY_NOTIFICATIONS_SUCCESS: 'notification.my.notifications.success',
|
|
16
|
+
SEND_SUCCESS: 'notification.send.success',
|
|
17
|
+
BROADCAST_SUCCESS: 'notification.broadcast.success'
|
|
18
|
+
};
|
|
19
|
+
// Aggregated export for backward compatibility
|
|
20
|
+
export const NOTIFICATION_MODULE_MESSAGES = {
|
|
21
|
+
NOTIFICATION: NOTIFICATION_MESSAGES
|
|
22
|
+
};
|
|
@@ -25,8 +25,8 @@ function _ts_param(paramIndex, decorator) {
|
|
|
25
25
|
decorator(target, key, paramIndex);
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
import { createApiController } from '@flusys/nestjs-shared/classes';
|
|
29
|
-
import {
|
|
28
|
+
import { createApiController, NOTIFICATION_PERMISSIONS } from '@flusys/nestjs-shared/classes';
|
|
29
|
+
import { NOTIFICATION_MESSAGES } from '../config';
|
|
30
30
|
import { CurrentUser, RequirePermission } from '@flusys/nestjs-shared/decorators';
|
|
31
31
|
import { BulkResponseDto, MessageResponseDto, SingleResponseDto } from '@flusys/nestjs-shared/dtos';
|
|
32
32
|
import { JwtAuthGuard, PermissionGuard } from '@flusys/nestjs-shared/guards';
|
|
@@ -38,6 +38,7 @@ import { CreateNotificationDto, MarkReadDto, NotificationResponseDto, SendBulkNo
|
|
|
38
38
|
import { NotificationHelperService } from '../services/notification-helper.service';
|
|
39
39
|
import { NotificationService } from '../services/notification.service';
|
|
40
40
|
export class NotificationController extends createApiController(CreateNotificationDto, UpdateNotificationDto, NotificationResponseDto, {
|
|
41
|
+
entityName: 'notification',
|
|
41
42
|
security: {
|
|
42
43
|
insert: {
|
|
43
44
|
level: 'permission',
|
|
@@ -85,6 +86,7 @@ export class NotificationController extends createApiController(CreateNotificati
|
|
|
85
86
|
return {
|
|
86
87
|
success: true,
|
|
87
88
|
message: 'Notification marked as read',
|
|
89
|
+
messageKey: NOTIFICATION_MESSAGES.MARK_READ_SUCCESS,
|
|
88
90
|
data: plainToInstance(NotificationResponseDto, notification)
|
|
89
91
|
};
|
|
90
92
|
}
|
|
@@ -92,7 +94,11 @@ export class NotificationController extends createApiController(CreateNotificati
|
|
|
92
94
|
const count = await this.service.markAllAsRead(user);
|
|
93
95
|
return {
|
|
94
96
|
success: true,
|
|
95
|
-
message: `${count} notifications marked as read
|
|
97
|
+
message: `${count} notifications marked as read`,
|
|
98
|
+
messageKey: NOTIFICATION_MESSAGES.MARK_ALL_READ_SUCCESS,
|
|
99
|
+
messageVariables: {
|
|
100
|
+
count
|
|
101
|
+
}
|
|
96
102
|
};
|
|
97
103
|
}
|
|
98
104
|
async getUnreadCount(user) {
|
|
@@ -100,6 +106,7 @@ export class NotificationController extends createApiController(CreateNotificati
|
|
|
100
106
|
return {
|
|
101
107
|
success: true,
|
|
102
108
|
message: 'Unread count retrieved',
|
|
109
|
+
messageKey: NOTIFICATION_MESSAGES.UNREAD_COUNT_SUCCESS,
|
|
103
110
|
data: {
|
|
104
111
|
count
|
|
105
112
|
}
|
|
@@ -117,6 +124,7 @@ export class NotificationController extends createApiController(CreateNotificati
|
|
|
117
124
|
return {
|
|
118
125
|
success: true,
|
|
119
126
|
message: 'Notification sent successfully',
|
|
127
|
+
messageKey: NOTIFICATION_MESSAGES.SEND_SUCCESS,
|
|
120
128
|
data: plainToInstance(NotificationResponseDto, notification)
|
|
121
129
|
};
|
|
122
130
|
}
|
|
@@ -132,6 +140,10 @@ export class NotificationController extends createApiController(CreateNotificati
|
|
|
132
140
|
return {
|
|
133
141
|
success: true,
|
|
134
142
|
message: `${notifications.length} notifications sent successfully`,
|
|
143
|
+
messageKey: NOTIFICATION_MESSAGES.BROADCAST_SUCCESS,
|
|
144
|
+
messageVariables: {
|
|
145
|
+
count: notifications.length
|
|
146
|
+
},
|
|
135
147
|
data: notifications.map((n)=>plainToInstance(NotificationResponseDto, n)),
|
|
136
148
|
meta: {
|
|
137
149
|
count: notifications.length,
|
|
@@ -25,26 +25,24 @@ function _ts_param(paramIndex, decorator) {
|
|
|
25
25
|
decorator(target, key, paramIndex);
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
import { Inject
|
|
28
|
+
import { Inject } from '@nestjs/common';
|
|
29
29
|
import { WebSocketGateway, WebSocketServer } from '@nestjs/websockets';
|
|
30
30
|
import { Server } from 'socket.io';
|
|
31
31
|
import * as jwt from 'jsonwebtoken';
|
|
32
32
|
import { NotificationConfigService } from '../services/notification-config.service';
|
|
33
33
|
export class NotificationGateway {
|
|
34
34
|
afterInit() {
|
|
35
|
-
|
|
35
|
+
// Gateway initialized
|
|
36
36
|
}
|
|
37
37
|
async handleConnection(client) {
|
|
38
38
|
try {
|
|
39
39
|
const token = this.extractToken(client);
|
|
40
40
|
if (!token) {
|
|
41
|
-
this.logger.warn(`Client ${client.id} connection rejected: No token provided`);
|
|
42
41
|
client.disconnect();
|
|
43
42
|
return;
|
|
44
43
|
}
|
|
45
44
|
const payload = this.verifyToken(token);
|
|
46
45
|
if (!payload) {
|
|
47
|
-
this.logger.warn(`Client ${client.id} connection rejected: Invalid token`);
|
|
48
46
|
client.disconnect();
|
|
49
47
|
return;
|
|
50
48
|
}
|
|
@@ -59,9 +57,7 @@ export class NotificationGateway {
|
|
|
59
57
|
if (payload.companyId) {
|
|
60
58
|
client.join(`company:${payload.companyId}`);
|
|
61
59
|
}
|
|
62
|
-
|
|
63
|
-
} catch (error) {
|
|
64
|
-
this.logger.error(`Client ${client.id} connection error: ${error}`);
|
|
60
|
+
} catch {
|
|
65
61
|
client.disconnect();
|
|
66
62
|
}
|
|
67
63
|
}
|
|
@@ -73,11 +69,10 @@ export class NotificationGateway {
|
|
|
73
69
|
if (sockets?.size === 0) {
|
|
74
70
|
this.connectedUsers.delete(userId);
|
|
75
71
|
}
|
|
76
|
-
this.logger.log(`Client ${client.id} disconnected for user ${userId}`);
|
|
77
72
|
}
|
|
78
73
|
}
|
|
79
74
|
emitToUser(userId, event, data) {
|
|
80
|
-
this.server
|
|
75
|
+
this.server?.to(`user:${userId}`).emit(event, data);
|
|
81
76
|
}
|
|
82
77
|
/**
|
|
83
78
|
* Emit to a specific user only on sockets connected with a specific company.
|
|
@@ -89,19 +84,18 @@ export class NotificationGateway {
|
|
|
89
84
|
* @param event - The event name
|
|
90
85
|
* @param data - The payload
|
|
91
86
|
*/ emitToUserInCompany(userId, companyId, event, data) {
|
|
87
|
+
if (!this.server?.sockets?.adapter) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
92
90
|
if (!companyId) {
|
|
93
|
-
// No company context - emit to all user's sockets
|
|
94
91
|
this.emitToUser(userId, event, data);
|
|
95
92
|
return;
|
|
96
93
|
}
|
|
97
|
-
// Get all sockets in the user's room
|
|
98
94
|
const userRoom = `user:${userId}`;
|
|
99
95
|
const sockets = this.server.sockets.adapter.rooms.get(userRoom);
|
|
100
96
|
if (!sockets) {
|
|
101
|
-
this.logger.debug(`No sockets found for user ${userId}`);
|
|
102
97
|
return;
|
|
103
98
|
}
|
|
104
|
-
// Emit only to sockets that match the company context
|
|
105
99
|
for (const socketId of sockets){
|
|
106
100
|
const socket = this.server.sockets.sockets.get(socketId);
|
|
107
101
|
if (socket && socket.data.companyId === companyId) {
|
|
@@ -110,10 +104,10 @@ export class NotificationGateway {
|
|
|
110
104
|
}
|
|
111
105
|
}
|
|
112
106
|
emitToCompany(companyId, event, data) {
|
|
113
|
-
this.server
|
|
107
|
+
this.server?.to(`company:${companyId}`).emit(event, data);
|
|
114
108
|
}
|
|
115
109
|
broadcast(event, data) {
|
|
116
|
-
this.server
|
|
110
|
+
this.server?.emit(event, data);
|
|
117
111
|
}
|
|
118
112
|
isUserOnline(userId) {
|
|
119
113
|
return this.connectedUsers.has(userId);
|
|
@@ -136,22 +130,18 @@ export class NotificationGateway {
|
|
|
136
130
|
try {
|
|
137
131
|
const secret = this.configService.getJwtSecret();
|
|
138
132
|
if (!secret) {
|
|
139
|
-
this.logger.error('No JWT secret configured for WebSocket authentication');
|
|
140
133
|
return null;
|
|
141
134
|
}
|
|
142
135
|
return jwt.verify(token, secret);
|
|
143
|
-
} catch
|
|
144
|
-
this.logger.warn(`Token verification failed: ${error}`);
|
|
136
|
+
} catch {
|
|
145
137
|
return null;
|
|
146
138
|
}
|
|
147
139
|
}
|
|
148
140
|
constructor(configService){
|
|
149
141
|
_define_property(this, "configService", void 0);
|
|
150
|
-
_define_property(this, "logger", void 0);
|
|
151
142
|
_define_property(this, "connectedUsers", void 0);
|
|
152
143
|
_define_property(this, "server", void 0);
|
|
153
144
|
this.configService = configService;
|
|
154
|
-
this.logger = new Logger(NotificationGateway.name);
|
|
155
145
|
this.connectedUsers = new Map();
|
|
156
146
|
}
|
|
157
147
|
}
|
|
@@ -26,7 +26,8 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { MultiTenantDataSourceService } from '@flusys/nestjs-shared/modules';
|
|
29
|
-
import {
|
|
29
|
+
import { SYSTEM_MESSAGES } from '@flusys/nestjs-shared/constants';
|
|
30
|
+
import { Inject, Injectable, InternalServerErrorException, Optional, Scope } from '@nestjs/common';
|
|
30
31
|
import { REQUEST } from '@nestjs/core';
|
|
31
32
|
import { Request } from 'express';
|
|
32
33
|
import { NotificationConfigService } from './notification-config.service';
|
|
@@ -66,7 +67,10 @@ export class NotificationDataSourceProvider extends MultiTenantDataSourceService
|
|
|
66
67
|
}
|
|
67
68
|
const config = this.getDefaultDatabaseConfig();
|
|
68
69
|
if (!config) {
|
|
69
|
-
throw new InternalServerErrorException(
|
|
70
|
+
throw new InternalServerErrorException({
|
|
71
|
+
message: 'No database config available. Provide defaultDatabaseConfig or tenantDefaultDatabaseConfig.',
|
|
72
|
+
messageKey: SYSTEM_MESSAGES.DATABASE_CONFIG_NOT_AVAILABLE
|
|
73
|
+
});
|
|
70
74
|
}
|
|
71
75
|
const connectionPromise = this.createDataSourceFromConfig(config);
|
|
72
76
|
NotificationDataSourceProvider.singleConnectionLock = connectionPromise;
|
|
@@ -99,7 +103,7 @@ export class NotificationDataSourceProvider extends MultiTenantDataSourceService
|
|
|
99
103
|
}
|
|
100
104
|
}
|
|
101
105
|
constructor(configService, request){
|
|
102
|
-
super(NotificationDataSourceProvider.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0),
|
|
106
|
+
super(NotificationDataSourceProvider.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0), this.configService = configService;
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
109
|
_define_property(NotificationDataSourceProvider, "tenantConnections", new Map());
|
|
@@ -25,8 +25,9 @@ function _ts_param(paramIndex, decorator) {
|
|
|
25
25
|
decorator(target, key, paramIndex);
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
import { Inject, Injectable,
|
|
28
|
+
import { Inject, Injectable, Optional } from '@nestjs/common';
|
|
29
29
|
import { HybridCache } from '@flusys/nestjs-shared/classes';
|
|
30
|
+
import { LogAction } from '@flusys/nestjs-shared';
|
|
30
31
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
31
32
|
import { NotificationConfigService } from './notification-config.service';
|
|
32
33
|
import { NotificationDataSourceProvider } from './notification-datasource.provider';
|
|
@@ -62,7 +63,6 @@ export class NotificationHelperService {
|
|
|
62
63
|
const saved = await repo.save(entity);
|
|
63
64
|
await this.clearCache();
|
|
64
65
|
this.emitRealtime(saved);
|
|
65
|
-
this.logger.debug(`Notification sent to user ${userId}: ${title}`);
|
|
66
66
|
return saved;
|
|
67
67
|
}
|
|
68
68
|
async sendToMany(options) {
|
|
@@ -84,12 +84,10 @@ export class NotificationHelperService {
|
|
|
84
84
|
for (const notification of saved){
|
|
85
85
|
this.emitRealtime(notification);
|
|
86
86
|
}
|
|
87
|
-
this.logger.debug(`Notification sent to ${userIds.length} users: ${title}`);
|
|
88
87
|
return saved;
|
|
89
88
|
}
|
|
90
89
|
async sendToCompany(companyId, title, message, type = NotificationType.INFO, data) {
|
|
91
90
|
if (!this.configService.isCompanyFeatureEnabled()) {
|
|
92
|
-
this.logger.warn('sendToCompany called but company feature is disabled');
|
|
93
91
|
return;
|
|
94
92
|
}
|
|
95
93
|
if (this.configService.isRealtimeEnabled() && this.gateway) {
|
|
@@ -102,7 +100,6 @@ export class NotificationHelperService {
|
|
|
102
100
|
createdAt: new Date()
|
|
103
101
|
};
|
|
104
102
|
this.gateway.emitToCompany(companyId, 'notification:new', payload);
|
|
105
|
-
this.logger.debug(`Broadcast notification sent to company ${companyId}: ${title}`);
|
|
106
103
|
}
|
|
107
104
|
}
|
|
108
105
|
isUserOnline(userId) {
|
|
@@ -144,7 +141,6 @@ export class NotificationHelperService {
|
|
|
144
141
|
_define_property(this, "configService", void 0);
|
|
145
142
|
_define_property(this, "dataSourceProvider", void 0);
|
|
146
143
|
_define_property(this, "gateway", void 0);
|
|
147
|
-
_define_property(this, "logger", void 0);
|
|
148
144
|
_define_property(this, "entityName", void 0);
|
|
149
145
|
_define_property(this, "dataSource", void 0);
|
|
150
146
|
this.cacheManager = cacheManager;
|
|
@@ -152,11 +148,47 @@ export class NotificationHelperService {
|
|
|
152
148
|
this.configService = configService;
|
|
153
149
|
this.dataSourceProvider = dataSourceProvider;
|
|
154
150
|
this.gateway = gateway;
|
|
155
|
-
this.logger = new Logger(NotificationHelperService.name);
|
|
156
151
|
this.entityName = 'notification';
|
|
157
152
|
this.dataSource = null;
|
|
158
153
|
}
|
|
159
154
|
}
|
|
155
|
+
_ts_decorate([
|
|
156
|
+
LogAction({
|
|
157
|
+
action: 'notification.send',
|
|
158
|
+
module: 'notification'
|
|
159
|
+
}),
|
|
160
|
+
_ts_metadata("design:type", Function),
|
|
161
|
+
_ts_metadata("design:paramtypes", [
|
|
162
|
+
typeof SendNotificationOptions === "undefined" ? Object : SendNotificationOptions
|
|
163
|
+
]),
|
|
164
|
+
_ts_metadata("design:returntype", Promise)
|
|
165
|
+
], NotificationHelperService.prototype, "send", null);
|
|
166
|
+
_ts_decorate([
|
|
167
|
+
LogAction({
|
|
168
|
+
action: 'notification.sendToMany',
|
|
169
|
+
module: 'notification'
|
|
170
|
+
}),
|
|
171
|
+
_ts_metadata("design:type", Function),
|
|
172
|
+
_ts_metadata("design:paramtypes", [
|
|
173
|
+
typeof SendBulkNotificationOptions === "undefined" ? Object : SendBulkNotificationOptions
|
|
174
|
+
]),
|
|
175
|
+
_ts_metadata("design:returntype", Promise)
|
|
176
|
+
], NotificationHelperService.prototype, "sendToMany", null);
|
|
177
|
+
_ts_decorate([
|
|
178
|
+
LogAction({
|
|
179
|
+
action: 'notification.sendToCompany',
|
|
180
|
+
module: 'notification'
|
|
181
|
+
}),
|
|
182
|
+
_ts_metadata("design:type", Function),
|
|
183
|
+
_ts_metadata("design:paramtypes", [
|
|
184
|
+
String,
|
|
185
|
+
String,
|
|
186
|
+
Object,
|
|
187
|
+
Object,
|
|
188
|
+
Object
|
|
189
|
+
]),
|
|
190
|
+
_ts_metadata("design:returntype", Promise)
|
|
191
|
+
], NotificationHelperService.prototype, "sendToCompany", null);
|
|
160
192
|
NotificationHelperService = _ts_decorate([
|
|
161
193
|
Injectable(),
|
|
162
194
|
_ts_param(0, Inject('CACHE_INSTANCE')),
|
|
@@ -26,6 +26,9 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { HybridCache, RequestScopedApiService } from '@flusys/nestjs-shared/classes';
|
|
29
|
+
import { LogAction } from '@flusys/nestjs-shared';
|
|
30
|
+
import { NOTIFICATION_MESSAGES } from '../config';
|
|
31
|
+
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
29
32
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
30
33
|
import { applyCompanyFilter } from '@flusys/nestjs-shared/utils';
|
|
31
34
|
import { Inject, Injectable, NotFoundException, Optional, Scope } from '@nestjs/common';
|
|
@@ -48,7 +51,12 @@ export class NotificationService extends RequestScopedApiService {
|
|
|
48
51
|
id: dto.id
|
|
49
52
|
}
|
|
50
53
|
});
|
|
51
|
-
if (!existing)
|
|
54
|
+
if (!existing) {
|
|
55
|
+
throw new NotFoundException({
|
|
56
|
+
message: 'Notification not found',
|
|
57
|
+
messageKey: NOTIFICATION_MESSAGES.NOT_FOUND
|
|
58
|
+
});
|
|
59
|
+
}
|
|
52
60
|
entity = existing;
|
|
53
61
|
}
|
|
54
62
|
const merged = {
|
|
@@ -98,7 +106,8 @@ export class NotificationService extends RequestScopedApiService {
|
|
|
98
106
|
isCompanyFeatureEnabled: this.notificationConfig.isCompanyFeatureEnabled(),
|
|
99
107
|
entityAlias: this.entityName
|
|
100
108
|
}, user);
|
|
101
|
-
|
|
109
|
+
const filterSort = filterDto?.sort;
|
|
110
|
+
if (!filterSort || Object.keys(filterSort).length === 0) {
|
|
102
111
|
query.orderBy(`${this.entityName}.createdAt`, 'DESC');
|
|
103
112
|
}
|
|
104
113
|
return result;
|
|
@@ -118,7 +127,10 @@ export class NotificationService extends RequestScopedApiService {
|
|
|
118
127
|
}
|
|
119
128
|
});
|
|
120
129
|
if (!notification) {
|
|
121
|
-
throw new NotFoundException(
|
|
130
|
+
throw new NotFoundException({
|
|
131
|
+
message: 'Notification not found',
|
|
132
|
+
messageKey: NOTIFICATION_MESSAGES.NOT_FOUND
|
|
133
|
+
});
|
|
122
134
|
}
|
|
123
135
|
notification.isRead = true;
|
|
124
136
|
notification.readAt = new Date();
|
|
@@ -186,9 +198,32 @@ export class NotificationService extends RequestScopedApiService {
|
|
|
186
198
|
}
|
|
187
199
|
}
|
|
188
200
|
constructor(cacheManager, utilsService, notificationConfig, dataSourceProvider, gateway){
|
|
189
|
-
super('notification', null, cacheManager, utilsService, NotificationService.name, false), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "notificationConfig", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "gateway", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.notificationConfig = notificationConfig, this.dataSourceProvider = dataSourceProvider, this.gateway = gateway;
|
|
201
|
+
super('notification', null, cacheManager, utilsService, NotificationService.name, false, 'notification'), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "notificationConfig", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "gateway", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.notificationConfig = notificationConfig, this.dataSourceProvider = dataSourceProvider, this.gateway = gateway;
|
|
190
202
|
}
|
|
191
203
|
}
|
|
204
|
+
_ts_decorate([
|
|
205
|
+
LogAction({
|
|
206
|
+
action: 'notification.markAsRead',
|
|
207
|
+
module: 'notification'
|
|
208
|
+
}),
|
|
209
|
+
_ts_metadata("design:type", Function),
|
|
210
|
+
_ts_metadata("design:paramtypes", [
|
|
211
|
+
String,
|
|
212
|
+
typeof ILoggedUserInfo === "undefined" ? Object : ILoggedUserInfo
|
|
213
|
+
]),
|
|
214
|
+
_ts_metadata("design:returntype", Promise)
|
|
215
|
+
], NotificationService.prototype, "markAsRead", null);
|
|
216
|
+
_ts_decorate([
|
|
217
|
+
LogAction({
|
|
218
|
+
action: 'notification.markAllAsRead',
|
|
219
|
+
module: 'notification'
|
|
220
|
+
}),
|
|
221
|
+
_ts_metadata("design:type", Function),
|
|
222
|
+
_ts_metadata("design:paramtypes", [
|
|
223
|
+
typeof ILoggedUserInfo === "undefined" ? Object : ILoggedUserInfo
|
|
224
|
+
]),
|
|
225
|
+
_ts_metadata("design:returntype", Promise)
|
|
226
|
+
], NotificationService.prototype, "markAllAsRead", null);
|
|
192
227
|
NotificationService = _ts_decorate([
|
|
193
228
|
Injectable({
|
|
194
229
|
scope: Scope.REQUEST
|
|
@@ -3,7 +3,6 @@ import { Server, Socket } from 'socket.io';
|
|
|
3
3
|
import { NotificationConfigService } from '../services/notification-config.service';
|
|
4
4
|
export declare class NotificationGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
|
|
5
5
|
private readonly configService;
|
|
6
|
-
private readonly logger;
|
|
7
6
|
private readonly connectedUsers;
|
|
8
7
|
server: Server;
|
|
9
8
|
constructor(configService: NotificationConfigService);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-notification",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-lts",
|
|
4
4
|
"description": "Notification module with real-time Socket.IO support",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "fesm/index.js",
|
|
@@ -88,11 +88,12 @@
|
|
|
88
88
|
"class-transformer": "^0.5.0",
|
|
89
89
|
"class-validator": "^0.14.0",
|
|
90
90
|
"socket.io": "^4.0.0",
|
|
91
|
-
"typeorm": "^0.3.0"
|
|
91
|
+
"typeorm": "^0.3.0",
|
|
92
|
+
"express": "^4.18.0"
|
|
92
93
|
},
|
|
93
94
|
"dependencies": {
|
|
94
|
-
"@flusys/nestjs-core": "
|
|
95
|
-
"@flusys/nestjs-shared": "
|
|
95
|
+
"@flusys/nestjs-core": "4.0.0-lts",
|
|
96
|
+
"@flusys/nestjs-shared": "4.0.0-lts",
|
|
96
97
|
"jsonwebtoken": "^9.0.0"
|
|
97
98
|
}
|
|
98
99
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { MultiTenantDataSourceService } from '@flusys/nestjs-shared/modules';
|
|
2
2
|
import { IDatabaseConfig, ITenantDatabaseConfig } from '@flusys/nestjs-core';
|
|
3
|
-
import { Logger } from '@nestjs/common';
|
|
4
3
|
import { Request } from 'express';
|
|
5
4
|
import { DataSource } from 'typeorm';
|
|
6
5
|
import { NotificationConfigService } from './notification-config.service';
|
|
7
6
|
export declare class NotificationDataSourceProvider extends MultiTenantDataSourceService {
|
|
8
7
|
private readonly configService;
|
|
9
|
-
protected readonly logger: Logger;
|
|
10
8
|
protected static readonly tenantConnections: Map<string, DataSource>;
|
|
11
9
|
protected static singleDataSource: DataSource | null;
|
|
12
10
|
protected static readonly tenantsRegistry: Map<string, ITenantDatabaseConfig>;
|
|
@@ -27,7 +27,6 @@ export declare class NotificationHelperService {
|
|
|
27
27
|
private readonly configService;
|
|
28
28
|
private readonly dataSourceProvider;
|
|
29
29
|
private readonly gateway?;
|
|
30
|
-
private readonly logger;
|
|
31
30
|
private readonly entityName;
|
|
32
31
|
private dataSource;
|
|
33
32
|
constructor(cacheManager: HybridCache, utilsService: UtilsService, configService: NotificationConfigService, dataSourceProvider: NotificationDataSourceProvider, gateway?: NotificationGateway);
|
|
@@ -18,11 +18,11 @@ export declare class NotificationService extends RequestScopedApiService<CreateN
|
|
|
18
18
|
protected resolveEntity(): EntityTarget<NotificationBase>;
|
|
19
19
|
protected getDataSourceProvider(): NotificationDataSourceProvider;
|
|
20
20
|
convertSingleDtoToEntity(dto: CreateNotificationDto | UpdateNotificationDto, user: ILoggedUserInfo | null): Promise<NotificationBase>;
|
|
21
|
-
protected getFilterQuery(query: SelectQueryBuilder<NotificationBase>, filter: Record<string,
|
|
21
|
+
protected getFilterQuery(query: SelectQueryBuilder<NotificationBase>, filter: Record<string, unknown>, _user: ILoggedUserInfo | null): Promise<{
|
|
22
22
|
query: SelectQueryBuilder<NotificationBase>;
|
|
23
23
|
isRaw: boolean;
|
|
24
24
|
}>;
|
|
25
|
-
protected getExtraManipulateQuery(query: SelectQueryBuilder<NotificationBase>, filterDto:
|
|
25
|
+
protected getExtraManipulateQuery(query: SelectQueryBuilder<NotificationBase>, filterDto: Record<string, unknown>, user: ILoggedUserInfo | null): Promise<{
|
|
26
26
|
query: SelectQueryBuilder<NotificationBase>;
|
|
27
27
|
isRaw: boolean;
|
|
28
28
|
}>;
|