@flusys/nestjs-notification 7.1.0 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/adapters/index.d.ts +1 -1
  2. package/adapters/notification.adapter.d.ts +2 -2
  3. package/config/index.d.ts +3 -3
  4. package/controllers/index.d.ts +1 -1
  5. package/controllers/notification.controller.d.ts +4 -4
  6. package/docs/index.d.ts +1 -1
  7. package/docs/notification-swagger.config.d.ts +2 -2
  8. package/dtos/index.d.ts +1 -1
  9. package/entities/index.d.ts +5 -5
  10. package/entities/notification-with-company.entity.d.ts +1 -1
  11. package/fesm/244.js +816 -0
  12. package/fesm/446.js +939 -0
  13. package/fesm/adapters/index.js +79 -1
  14. package/fesm/config/index.js +84 -3
  15. package/fesm/controllers/index.js +13 -1
  16. package/fesm/docs/index.js +112 -1
  17. package/fesm/dtos/index.js +311 -1
  18. package/fesm/entities/index.js +211 -8
  19. package/fesm/gateways/index.js +286 -1
  20. package/fesm/index.js +467 -10
  21. package/fesm/interfaces/index.js +16 -2
  22. package/fesm/modules/index.js +269 -1
  23. package/fesm/runtime.js +85 -0
  24. package/fesm/services/index.js +357 -4
  25. package/gateways/index.d.ts +1 -1
  26. package/gateways/notification.gateway.d.ts +2 -2
  27. package/index.d.ts +10 -10
  28. package/interfaces/index.d.ts +2 -2
  29. package/interfaces/notification-module.interface.d.ts +3 -3
  30. package/interfaces/notification.interface.d.ts +1 -1
  31. package/modules/index.d.ts +1 -1
  32. package/modules/notification.module.d.ts +2 -2
  33. package/package.json +33 -44
  34. package/services/index.d.ts +4 -4
  35. package/services/notification-config.service.d.ts +3 -3
  36. package/services/notification-datasource.provider.d.ts +3 -3
  37. package/services/notification-helper.service.d.ts +5 -5
  38. package/services/notification.service.d.ts +8 -8
  39. package/cjs/adapters/index.js +0 -18
  40. package/cjs/adapters/notification.adapter.js +0 -62
  41. package/cjs/adapters/notification.adapter.spec.js +0 -73
  42. package/cjs/config/event-actions.js +0 -33
  43. package/cjs/config/index.js +0 -20
  44. package/cjs/config/message-keys.js +0 -19
  45. package/cjs/config/notification.constants.js +0 -11
  46. package/cjs/controllers/index.js +0 -18
  47. package/cjs/controllers/notification.controller.js +0 -299
  48. package/cjs/controllers/notification.controller.spec.js +0 -214
  49. package/cjs/docs/index.js +0 -18
  50. package/cjs/docs/notification-swagger.config.js +0 -97
  51. package/cjs/docs/notification-swagger.config.spec.js +0 -68
  52. package/cjs/dtos/index.js +0 -18
  53. package/cjs/dtos/notification.dto.js +0 -295
  54. package/cjs/entities/index.js +0 -48
  55. package/cjs/entities/index.spec.js +0 -13
  56. package/cjs/entities/notification-with-company.entity.js +0 -57
  57. package/cjs/entities/notification.entity.js +0 -112
  58. package/cjs/gateways/index.js +0 -18
  59. package/cjs/gateways/notification.gateway.js +0 -172
  60. package/cjs/gateways/notification.gateway.spec.js +0 -359
  61. package/cjs/index.js +0 -28
  62. package/cjs/interfaces/index.js +0 -19
  63. package/cjs/interfaces/notification-module.interface.js +0 -4
  64. package/cjs/interfaces/notification.interface.js +0 -4
  65. package/cjs/modules/index.js +0 -18
  66. package/cjs/modules/notification.module.js +0 -139
  67. package/cjs/modules/notification.module.spec.js +0 -152
  68. package/cjs/services/index.js +0 -21
  69. package/cjs/services/notification-config.service.js +0 -69
  70. package/cjs/services/notification-config.service.spec.js +0 -113
  71. package/cjs/services/notification-datasource.provider.js +0 -133
  72. package/cjs/services/notification-datasource.provider.spec.js +0 -136
  73. package/cjs/services/notification-helper.service.js +0 -197
  74. package/cjs/services/notification-helper.service.spec.js +0 -392
  75. package/cjs/services/notification.service.js +0 -281
  76. package/cjs/services/notification.service.spec.js +0 -560
  77. package/fesm/adapters/notification.adapter.js +0 -52
  78. package/fesm/adapters/notification.adapter.spec.js +0 -69
  79. package/fesm/config/event-actions.js +0 -12
  80. package/fesm/config/message-keys.js +0 -9
  81. package/fesm/config/notification.constants.js +0 -1
  82. package/fesm/controllers/notification.controller.js +0 -289
  83. package/fesm/controllers/notification.controller.spec.js +0 -210
  84. package/fesm/docs/notification-swagger.config.js +0 -87
  85. package/fesm/docs/notification-swagger.config.spec.js +0 -64
  86. package/fesm/dtos/notification.dto.js +0 -262
  87. package/fesm/entities/index.spec.js +0 -9
  88. package/fesm/entities/notification-with-company.entity.js +0 -47
  89. package/fesm/entities/notification.entity.js +0 -102
  90. package/fesm/gateways/notification.gateway.js +0 -162
  91. package/fesm/gateways/notification.gateway.spec.js +0 -355
  92. package/fesm/interfaces/notification-module.interface.js +0 -1
  93. package/fesm/interfaces/notification.interface.js +0 -1
  94. package/fesm/modules/notification.module.js +0 -129
  95. package/fesm/modules/notification.module.spec.js +0 -148
  96. package/fesm/services/notification-config.service.js +0 -59
  97. package/fesm/services/notification-config.service.spec.js +0 -109
  98. package/fesm/services/notification-datasource.provider.js +0 -82
  99. package/fesm/services/notification-datasource.provider.spec.js +0 -132
  100. package/fesm/services/notification-helper.service.js +0 -187
  101. package/fesm/services/notification-helper.service.spec.js +0 -388
  102. package/fesm/services/notification.service.js +0 -271
  103. package/fesm/services/notification.service.spec.js +0 -556
@@ -1,9 +0,0 @@
1
- // ==================== NOTIFICATION MODULE MESSAGE KEYS ====================
2
- export const NOTIFICATION_MESSAGES = {
3
- NOT_FOUND: 'notification.not.found',
4
- MARK_READ_SUCCESS: 'notification.mark.read.success',
5
- MARK_ALL_READ_SUCCESS: 'notification.mark.all.read.success',
6
- UNREAD_COUNT_SUCCESS: 'notification.unread.count.success',
7
- SEND_SUCCESS: 'notification.send.success',
8
- BROADCAST_SUCCESS: 'notification.broadcast.success'
9
- };
@@ -1 +0,0 @@
1
- export const NOTIFICATION_MODULE_OPTIONS = 'NOTIFICATION_MODULE_OPTIONS';
@@ -1,289 +0,0 @@
1
- function _define_property(obj, key, value) {
2
- if (key in obj) {
3
- Object.defineProperty(obj, key, {
4
- value: value,
5
- enumerable: true,
6
- configurable: true,
7
- writable: true
8
- });
9
- } else {
10
- obj[key] = value;
11
- }
12
- return obj;
13
- }
14
- function _ts_decorate(decorators, target, key, desc) {
15
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
18
- return c > 3 && r && Object.defineProperty(target, key, r), r;
19
- }
20
- function _ts_metadata(k, v) {
21
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
- }
23
- function _ts_param(paramIndex, decorator) {
24
- return function(target, key) {
25
- decorator(target, key, paramIndex);
26
- };
27
- }
28
- import { createApiController, NOTIFICATION_PERMISSIONS } from '@flusys/nestjs-shared/classes';
29
- import { CurrentUser, RequirePermission } from '@flusys/nestjs-shared/decorators';
30
- import { BulkResponseDto, MessageResponseDto, SingleResponseDto } from '@flusys/nestjs-shared/dtos';
31
- import { JwtAuthGuard, PermissionGuard } from '@flusys/nestjs-shared/guards';
32
- import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
33
- import { Body, Controller, HttpCode, HttpStatus, Inject, Post, UseGuards } from '@nestjs/common';
34
- import { ApiBearerAuth, ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
35
- import { plainToInstance } from 'class-transformer';
36
- import { NOTIFICATION_MESSAGES } from '../config';
37
- import { CreateNotificationDto, MarkReadDto, NotificationResponseDto, SendBulkNotificationDto, SendNotificationDto, UpdateNotificationDto } from '../dtos';
38
- import { NotificationHelperService } from '../services/notification-helper.service';
39
- import { NotificationService } from '../services/notification.service';
40
- export class NotificationController extends createApiController(CreateNotificationDto, UpdateNotificationDto, NotificationResponseDto, {
41
- entityName: 'notification',
42
- security: {
43
- insert: {
44
- level: 'permission',
45
- permissions: [
46
- NOTIFICATION_PERMISSIONS.CREATE
47
- ]
48
- },
49
- insertMany: {
50
- level: 'permission',
51
- permissions: [
52
- NOTIFICATION_PERMISSIONS.CREATE
53
- ]
54
- },
55
- getById: {
56
- level: 'permission',
57
- permissions: [
58
- NOTIFICATION_PERMISSIONS.READ
59
- ]
60
- },
61
- getAll: {
62
- level: 'jwt'
63
- },
64
- update: {
65
- level: 'permission',
66
- permissions: [
67
- NOTIFICATION_PERMISSIONS.UPDATE
68
- ]
69
- },
70
- updateMany: {
71
- level: 'permission',
72
- permissions: [
73
- NOTIFICATION_PERMISSIONS.UPDATE
74
- ]
75
- },
76
- delete: {
77
- level: 'permission',
78
- permissions: [
79
- NOTIFICATION_PERMISSIONS.DELETE
80
- ]
81
- }
82
- }
83
- }) {
84
- async markAsRead(dto, user) {
85
- const notification = await this.service.markAsRead(dto.id, user);
86
- const plainOptions = {
87
- excludeExtraneousValues: true
88
- };
89
- return {
90
- success: true,
91
- message: 'Notification marked as read',
92
- messageKey: NOTIFICATION_MESSAGES.MARK_READ_SUCCESS,
93
- data: plainToInstance(NotificationResponseDto, notification, plainOptions)
94
- };
95
- }
96
- async markAllAsRead(user) {
97
- const count = await this.service.markAllAsRead(user);
98
- return {
99
- success: true,
100
- message: `${count} notifications marked as read`,
101
- messageKey: NOTIFICATION_MESSAGES.MARK_ALL_READ_SUCCESS,
102
- messageVariables: {
103
- count
104
- }
105
- };
106
- }
107
- async getUnreadCount(user) {
108
- const count = await this.service.getUnreadCount(user);
109
- return {
110
- success: true,
111
- message: 'Unread count retrieved',
112
- messageKey: NOTIFICATION_MESSAGES.UNREAD_COUNT_SUCCESS,
113
- data: {
114
- count
115
- }
116
- };
117
- }
118
- async sendNotification(dto) {
119
- const notification = await this.notificationHelper.send({
120
- userId: dto.userId,
121
- title: dto.title,
122
- message: dto.message,
123
- type: dto.type,
124
- data: dto.data,
125
- companyId: dto.companyId
126
- });
127
- const plainOptions = {
128
- excludeExtraneousValues: true
129
- };
130
- return {
131
- success: true,
132
- message: 'Notification sent successfully',
133
- messageKey: NOTIFICATION_MESSAGES.SEND_SUCCESS,
134
- data: plainToInstance(NotificationResponseDto, notification, plainOptions)
135
- };
136
- }
137
- async sendBulkNotification(dto) {
138
- const notifications = await this.notificationHelper.sendToMany({
139
- userIds: dto.userIds,
140
- title: dto.title,
141
- message: dto.message,
142
- type: dto.type,
143
- data: dto.data,
144
- companyId: dto.companyId
145
- });
146
- const plainOptions = {
147
- excludeExtraneousValues: true
148
- };
149
- return {
150
- success: true,
151
- message: `${notifications.length} notifications sent successfully`,
152
- messageKey: NOTIFICATION_MESSAGES.BROADCAST_SUCCESS,
153
- messageVariables: {
154
- count: notifications.length
155
- },
156
- data: notifications.map((n)=>plainToInstance(NotificationResponseDto, n, plainOptions)),
157
- meta: {
158
- count: notifications.length,
159
- total: dto.userIds.length
160
- }
161
- };
162
- }
163
- constructor(service, notificationHelper){
164
- super(service), _define_property(this, "service", void 0), _define_property(this, "notificationHelper", void 0), this.service = service, this.notificationHelper = notificationHelper;
165
- }
166
- }
167
- _ts_decorate([
168
- Post('mark-read'),
169
- HttpCode(HttpStatus.OK),
170
- UseGuards(JwtAuthGuard),
171
- ApiBearerAuth(),
172
- ApiOperation({
173
- summary: 'Mark a notification as read'
174
- }),
175
- ApiBody({
176
- type: MarkReadDto
177
- }),
178
- ApiResponse({
179
- status: 200,
180
- description: 'Notification marked as read',
181
- type: SingleResponseDto
182
- }),
183
- _ts_param(0, Body()),
184
- _ts_param(1, CurrentUser()),
185
- _ts_metadata("design:type", Function),
186
- _ts_metadata("design:paramtypes", [
187
- typeof MarkReadDto === "undefined" ? Object : MarkReadDto,
188
- typeof ILoggedUserInfo === "undefined" ? Object : ILoggedUserInfo
189
- ]),
190
- _ts_metadata("design:returntype", Promise)
191
- ], NotificationController.prototype, "markAsRead", null);
192
- _ts_decorate([
193
- Post('mark-all-read'),
194
- HttpCode(HttpStatus.OK),
195
- UseGuards(JwtAuthGuard),
196
- ApiBearerAuth(),
197
- ApiOperation({
198
- summary: 'Mark all notifications as read'
199
- }),
200
- ApiResponse({
201
- status: 200,
202
- description: 'All notifications marked as read',
203
- type: MessageResponseDto
204
- }),
205
- _ts_param(0, CurrentUser()),
206
- _ts_metadata("design:type", Function),
207
- _ts_metadata("design:paramtypes", [
208
- typeof ILoggedUserInfo === "undefined" ? Object : ILoggedUserInfo
209
- ]),
210
- _ts_metadata("design:returntype", Promise)
211
- ], NotificationController.prototype, "markAllAsRead", null);
212
- _ts_decorate([
213
- Post('unread-count'),
214
- HttpCode(HttpStatus.OK),
215
- UseGuards(JwtAuthGuard),
216
- ApiBearerAuth(),
217
- ApiOperation({
218
- summary: 'Get unread notification count'
219
- }),
220
- ApiResponse({
221
- status: 200,
222
- description: 'Unread count retrieved',
223
- type: SingleResponseDto
224
- }),
225
- _ts_param(0, CurrentUser()),
226
- _ts_metadata("design:type", Function),
227
- _ts_metadata("design:paramtypes", [
228
- typeof ILoggedUserInfo === "undefined" ? Object : ILoggedUserInfo
229
- ]),
230
- _ts_metadata("design:returntype", Promise)
231
- ], NotificationController.prototype, "getUnreadCount", null);
232
- _ts_decorate([
233
- Post('send'),
234
- HttpCode(HttpStatus.OK),
235
- UseGuards(JwtAuthGuard, PermissionGuard),
236
- RequirePermission(NOTIFICATION_PERMISSIONS.CREATE),
237
- ApiOperation({
238
- summary: 'Send a notification to a user'
239
- }),
240
- ApiBody({
241
- type: SendNotificationDto
242
- }),
243
- ApiResponse({
244
- status: 200,
245
- description: 'Notification sent successfully',
246
- type: SingleResponseDto
247
- }),
248
- _ts_param(0, Body()),
249
- _ts_metadata("design:type", Function),
250
- _ts_metadata("design:paramtypes", [
251
- typeof SendNotificationDto === "undefined" ? Object : SendNotificationDto
252
- ]),
253
- _ts_metadata("design:returntype", Promise)
254
- ], NotificationController.prototype, "sendNotification", null);
255
- _ts_decorate([
256
- Post('send-bulk'),
257
- HttpCode(HttpStatus.OK),
258
- UseGuards(JwtAuthGuard, PermissionGuard),
259
- RequirePermission(NOTIFICATION_PERMISSIONS.CREATE),
260
- ApiOperation({
261
- summary: 'Send a notification to multiple users'
262
- }),
263
- ApiBody({
264
- type: SendBulkNotificationDto
265
- }),
266
- ApiResponse({
267
- status: 200,
268
- description: 'Notifications sent successfully',
269
- type: BulkResponseDto
270
- }),
271
- _ts_param(0, Body()),
272
- _ts_metadata("design:type", Function),
273
- _ts_metadata("design:paramtypes", [
274
- typeof SendBulkNotificationDto === "undefined" ? Object : SendBulkNotificationDto
275
- ]),
276
- _ts_metadata("design:returntype", Promise)
277
- ], NotificationController.prototype, "sendBulkNotification", null);
278
- NotificationController = _ts_decorate([
279
- ApiTags('Notifications'),
280
- ApiBearerAuth(),
281
- Controller('notification'),
282
- _ts_param(0, Inject(NotificationService)),
283
- _ts_param(1, Inject(NotificationHelperService)),
284
- _ts_metadata("design:type", Function),
285
- _ts_metadata("design:paramtypes", [
286
- typeof NotificationService === "undefined" ? Object : NotificationService,
287
- typeof NotificationHelperService === "undefined" ? Object : NotificationHelperService
288
- ])
289
- ], NotificationController);
@@ -1,210 +0,0 @@
1
- import { NotificationType } from '@flusys/nestjs-shared/enums';
2
- import { buildMockUser } from '@test-utils/mocks/logged-user.mock';
3
- import { NotificationController } from './notification.controller';
4
- import { NOTIFICATION_MESSAGES } from '../config';
5
- function buildNotification(overrides = {}) {
6
- return {
7
- id: 'notif-1',
8
- userId: 'user-uuid-1',
9
- type: NotificationType.INFO,
10
- title: 'Title',
11
- message: 'Message',
12
- data: null,
13
- isRead: false,
14
- readAt: null,
15
- createdAt: new Date(),
16
- updatedAt: new Date(),
17
- ...overrides
18
- };
19
- }
20
- describe('NotificationController', ()=>{
21
- let controller;
22
- let mockService;
23
- let mockHelper;
24
- beforeEach(()=>{
25
- mockService = {
26
- markAsRead: jest.fn(),
27
- markAllAsRead: jest.fn(),
28
- getUnreadCount: jest.fn(),
29
- insert: jest.fn(),
30
- insertMany: jest.fn(),
31
- findById: jest.fn(),
32
- findByIds: jest.fn(),
33
- update: jest.fn(),
34
- updateMany: jest.fn(),
35
- bulkUpsert: jest.fn(),
36
- getAll: jest.fn(),
37
- delete: jest.fn()
38
- };
39
- mockHelper = {
40
- send: jest.fn(),
41
- sendToMany: jest.fn(),
42
- isUserOnline: jest.fn(),
43
- getOnlineUserCount: jest.fn()
44
- };
45
- controller = new NotificationController(mockService, mockHelper);
46
- });
47
- describe('markAsRead', ()=>{
48
- it('marks the notification as read and returns the mapped response', async ()=>{
49
- const user = buildMockUser();
50
- const notification = buildNotification({
51
- isRead: true
52
- });
53
- mockService.markAsRead.mockResolvedValue(notification);
54
- const result = await controller.markAsRead({
55
- id: 'notif-1'
56
- }, user);
57
- expect(mockService.markAsRead).toHaveBeenCalledWith('notif-1', user);
58
- expect(result.success).toBe(true);
59
- expect(result.messageKey).toBe(NOTIFICATION_MESSAGES.MARK_READ_SUCCESS);
60
- expect(result.data?.id).toBe('notif-1');
61
- expect(result.data?.isRead).toBe(true);
62
- });
63
- it('propagates a not-found error from the service', async ()=>{
64
- mockService.markAsRead.mockRejectedValue(new Error(NOTIFICATION_MESSAGES.NOT_FOUND));
65
- await expect(controller.markAsRead({
66
- id: 'missing'
67
- }, buildMockUser())).rejects.toThrow();
68
- });
69
- });
70
- describe('markAllAsRead', ()=>{
71
- it('returns the count of notifications marked as read', async ()=>{
72
- mockService.markAllAsRead.mockResolvedValue(3);
73
- const result = await controller.markAllAsRead(buildMockUser());
74
- expect(result.success).toBe(true);
75
- expect(result.messageKey).toBe(NOTIFICATION_MESSAGES.MARK_ALL_READ_SUCCESS);
76
- expect(result.messageVariables).toEqual({
77
- count: 3
78
- });
79
- expect(result.message).toBe('3 notifications marked as read');
80
- });
81
- it('handles a user with zero unread notifications gracefully', async ()=>{
82
- mockService.markAllAsRead.mockResolvedValue(0);
83
- const result = await controller.markAllAsRead(buildMockUser());
84
- expect(result.messageVariables).toEqual({
85
- count: 0
86
- });
87
- expect(result.message).toBe('0 notifications marked as read');
88
- });
89
- });
90
- describe('getUnreadCount', ()=>{
91
- it('returns the unread count wrapped in a single response', async ()=>{
92
- mockService.getUnreadCount.mockResolvedValue(5);
93
- const result = await controller.getUnreadCount(buildMockUser());
94
- expect(result.success).toBe(true);
95
- expect(result.messageKey).toBe(NOTIFICATION_MESSAGES.UNREAD_COUNT_SUCCESS);
96
- expect(result.data).toEqual({
97
- count: 5
98
- });
99
- });
100
- it('returns zero for a user with no unread notifications', async ()=>{
101
- mockService.getUnreadCount.mockResolvedValue(0);
102
- const result = await controller.getUnreadCount(buildMockUser());
103
- expect(result.data).toEqual({
104
- count: 0
105
- });
106
- });
107
- });
108
- describe('sendNotification', ()=>{
109
- it('sends a notification via the helper service and returns the mapped response', async ()=>{
110
- const notification = buildNotification({
111
- id: 'notif-2'
112
- });
113
- mockHelper.send.mockResolvedValue(notification);
114
- const result = await controller.sendNotification({
115
- userId: 'user-uuid-1',
116
- title: 'Hello',
117
- message: 'World'
118
- });
119
- expect(mockHelper.send).toHaveBeenCalledWith({
120
- userId: 'user-uuid-1',
121
- title: 'Hello',
122
- message: 'World',
123
- type: undefined,
124
- data: undefined,
125
- companyId: undefined
126
- });
127
- expect(result.success).toBe(true);
128
- expect(result.messageKey).toBe(NOTIFICATION_MESSAGES.SEND_SUCCESS);
129
- expect(result.data?.id).toBe('notif-2');
130
- });
131
- it('propagates errors from the helper service', async ()=>{
132
- mockHelper.send.mockRejectedValue(new Error('db down'));
133
- await expect(controller.sendNotification({
134
- userId: 'user-1',
135
- title: 'X'
136
- })).rejects.toThrow('db down');
137
- });
138
- });
139
- describe('sendBulkNotification', ()=>{
140
- it('sends notifications to multiple users and returns bulk meta', async ()=>{
141
- const notifications = [
142
- buildNotification({
143
- id: 'n1',
144
- userId: 'user-1'
145
- }),
146
- buildNotification({
147
- id: 'n2',
148
- userId: 'user-2'
149
- })
150
- ];
151
- mockHelper.sendToMany.mockResolvedValue(notifications);
152
- const result = await controller.sendBulkNotification({
153
- userIds: [
154
- 'user-1',
155
- 'user-2'
156
- ],
157
- title: 'Broadcast'
158
- });
159
- expect(mockHelper.sendToMany).toHaveBeenCalledWith({
160
- userIds: [
161
- 'user-1',
162
- 'user-2'
163
- ],
164
- title: 'Broadcast',
165
- message: undefined,
166
- type: undefined,
167
- data: undefined,
168
- companyId: undefined
169
- });
170
- expect(result.success).toBe(true);
171
- expect(result.messageKey).toBe(NOTIFICATION_MESSAGES.BROADCAST_SUCCESS);
172
- expect(result.data).toHaveLength(2);
173
- expect(result.meta).toEqual({
174
- count: 2,
175
- total: 2
176
- });
177
- });
178
- it('reports a mismatch between requested and sent counts in the meta', async ()=>{
179
- mockHelper.sendToMany.mockResolvedValue([
180
- buildNotification({
181
- id: 'n1'
182
- })
183
- ]);
184
- const result = await controller.sendBulkNotification({
185
- userIds: [
186
- 'user-1',
187
- 'user-2',
188
- 'user-3'
189
- ],
190
- title: 'Partial broadcast'
191
- });
192
- expect(result.meta).toEqual({
193
- count: 1,
194
- total: 3
195
- });
196
- });
197
- it('handles an empty userIds bulk send without throwing', async ()=>{
198
- mockHelper.sendToMany.mockResolvedValue([]);
199
- const result = await controller.sendBulkNotification({
200
- userIds: [],
201
- title: 'Nobody'
202
- });
203
- expect(result.data).toEqual([]);
204
- expect(result.meta).toEqual({
205
- count: 0,
206
- total: 0
207
- });
208
- });
209
- });
210
- });
@@ -1,87 +0,0 @@
1
- /** Schema properties to exclude when company feature is disabled */ const COMPANY_SCHEMA_EXCLUSIONS = [
2
- {
3
- schemaName: 'NotificationResponseDto',
4
- properties: [
5
- 'companyId'
6
- ]
7
- },
8
- {
9
- schemaName: 'CreateNotificationDto',
10
- properties: [
11
- 'companyId'
12
- ]
13
- },
14
- {
15
- schemaName: 'SendNotificationDto',
16
- properties: [
17
- 'companyId'
18
- ]
19
- },
20
- {
21
- schemaName: 'SendBulkNotificationDto',
22
- properties: [
23
- 'companyId'
24
- ]
25
- },
26
- {
27
- schemaName: 'UpdateNotificationDto',
28
- properties: [
29
- 'companyId'
30
- ]
31
- }
32
- ];
33
- export function notificationSwaggerConfig(bootstrapConfig) {
34
- const enableCompanyFeature = bootstrapConfig?.enableCompanyFeature ?? true;
35
- const isMultiTenant = bootstrapConfig?.databaseMode === 'multi-tenant';
36
- const multiTenantNote = isMultiTenant ? `\n> **Multi-Tenant Mode**: Include \`x-tenant-id\` header to target a specific tenant database.\n` : '';
37
- return {
38
- title: 'Notification API',
39
- description: `
40
- ## Notification API
41
- ${multiTenantNote}
42
- Real-time notification system with WebSocket support.
43
-
44
- ### Features
45
- - Push notifications to users
46
- - Mark notifications as read
47
- - Unread count tracking
48
- - Real-time delivery via WebSocket
49
- - Bulk notification sending
50
-
51
- ### Endpoints
52
-
53
- #### User Notifications
54
- - \`POST /notification/get-all\` - Get user's notifications (paginated, sorted by newest)
55
- - \`POST /notification/get/:id\` - Get single notification
56
- - \`POST /notification/mark-read\` - Mark notification as read
57
- - \`POST /notification/mark-all-read\` - Mark all notifications as read
58
- - \`POST /notification/unread-count\` - Get unread notification count
59
-
60
- #### Admin/System
61
- - \`POST /notification/send\` - Send notification to a user
62
- - \`POST /notification/send-bulk\` - Send notification to multiple users
63
-
64
- ### WebSocket Events
65
-
66
- Connect to WebSocket with JWT authentication:
67
- \`\`\`
68
- ws://localhost:2002/notification?token=<jwt>
69
- \`\`\`
70
-
71
- **Events:**
72
- - \`notification:new\` - New notification received
73
- - \`notification:read\` - Notification marked as read
74
- - \`notification:read-all\` - All notifications marked as read
75
-
76
- ### Notification Types
77
- - \`info\` - General information
78
- - \`success\` - Success message
79
- - \`warning\` - Warning message
80
- - \`error\` - Error message
81
- `,
82
- version: '1.0',
83
- path: 'api/docs/notification',
84
- bearerAuth: true,
85
- excludeSchemaProperties: enableCompanyFeature ? undefined : COMPANY_SCHEMA_EXCLUSIONS
86
- };
87
- }
@@ -1,64 +0,0 @@
1
- import { notificationSwaggerConfig } from './notification-swagger.config';
2
- describe('notificationSwaggerConfig', ()=>{
3
- it('should default to company feature enabled and single-database mode when no config is given', ()=>{
4
- const config = notificationSwaggerConfig();
5
- expect(config.title).toBe('Notification API');
6
- expect(config.path).toBe('api/docs/notification');
7
- expect(config.bearerAuth).toBe(true);
8
- expect(config.excludeSchemaProperties).toBeUndefined();
9
- expect(config.description).not.toContain('Multi-Tenant Mode');
10
- });
11
- it('should exclude companyId schema properties across all notification DTOs when the company feature is disabled', ()=>{
12
- const config = notificationSwaggerConfig({
13
- enableCompanyFeature: false
14
- });
15
- expect(config.excludeSchemaProperties).toEqual([
16
- {
17
- schemaName: 'NotificationResponseDto',
18
- properties: [
19
- 'companyId'
20
- ]
21
- },
22
- {
23
- schemaName: 'CreateNotificationDto',
24
- properties: [
25
- 'companyId'
26
- ]
27
- },
28
- {
29
- schemaName: 'SendNotificationDto',
30
- properties: [
31
- 'companyId'
32
- ]
33
- },
34
- {
35
- schemaName: 'SendBulkNotificationDto',
36
- properties: [
37
- 'companyId'
38
- ]
39
- },
40
- {
41
- schemaName: 'UpdateNotificationDto',
42
- properties: [
43
- 'companyId'
44
- ]
45
- }
46
- ]);
47
- });
48
- it('should not exclude any schema properties when the company feature is enabled', ()=>{
49
- const config = notificationSwaggerConfig({
50
- enableCompanyFeature: true
51
- });
52
- expect(config.excludeSchemaProperties).toBeUndefined();
53
- });
54
- it('should mention multi-tenant mode in the description only for multi-tenant database mode', ()=>{
55
- const multiTenant = notificationSwaggerConfig({
56
- databaseMode: 'multi-tenant'
57
- });
58
- const single = notificationSwaggerConfig({
59
- databaseMode: 'single'
60
- });
61
- expect(multiTenant.description).toContain('Multi-Tenant Mode');
62
- expect(single.description).not.toContain('Multi-Tenant Mode');
63
- });
64
- });