@flusys/nestjs-notification 5.1.1 → 5.1.3
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/adapters/notification.adapter.d.ts +3 -4
- package/cjs/adapters/notification.adapter.js +2 -19
- package/cjs/controllers/notification.controller.js +13 -4
- package/cjs/dtos/notification.dto.js +65 -14
- package/cjs/modules/notification.module.js +2 -6
- package/cjs/services/notification-config.service.js +0 -3
- package/cjs/services/notification-datasource.provider.js +0 -45
- package/cjs/services/notification-helper.service.js +44 -83
- package/cjs/services/notification.service.js +10 -19
- package/controllers/notification.controller.d.ts +6 -6
- package/dtos/notification.dto.d.ts +1 -1
- package/fesm/adapters/notification.adapter.js +3 -20
- package/fesm/controllers/notification.controller.js +13 -4
- package/fesm/dtos/notification.dto.js +65 -14
- package/fesm/modules/notification.module.js +2 -6
- package/fesm/services/notification-config.service.js +0 -3
- package/fesm/services/notification-datasource.provider.js +1 -46
- package/fesm/services/notification-helper.service.js +44 -83
- package/fesm/services/notification.service.js +11 -20
- package/interfaces/notification-module.interface.d.ts +0 -1
- package/package.json +15 -15
- package/services/notification-config.service.d.ts +0 -1
- package/services/notification-datasource.provider.d.ts +0 -2
- package/services/notification-helper.service.d.ts +10 -27
- package/services/notification.service.d.ts +4 -6
|
@@ -4,19 +4,19 @@ import { CreateNotificationDto, MarkReadDto, NotificationResponseDto, SendBulkNo
|
|
|
4
4
|
import { NotificationHelperService } from '../services/notification-helper.service';
|
|
5
5
|
import { NotificationService } from '../services/notification.service';
|
|
6
6
|
declare const NotificationController_base: abstract new (service: NotificationService) => {
|
|
7
|
-
readonly enabledEndpoints: import("@flusys/nestjs-shared
|
|
7
|
+
readonly enabledEndpoints: import("@flusys/nestjs-shared").ApiEndpoint[] | "all";
|
|
8
8
|
service: NotificationService;
|
|
9
|
-
isEnabled(endpoint: import("@flusys/nestjs-shared
|
|
9
|
+
isEnabled(endpoint: import("@flusys/nestjs-shared").ApiEndpoint): boolean;
|
|
10
10
|
insert(addDto: CreateNotificationDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<NotificationResponseDto>>;
|
|
11
11
|
insertMany(addDto: CreateNotificationDto[], user: ILoggedUserInfo | null): Promise<BulkResponseDto<NotificationResponseDto>>;
|
|
12
|
-
getById(id: string, body: import("@flusys/nestjs-shared
|
|
13
|
-
getByIds(body: import("@flusys/nestjs-shared
|
|
12
|
+
getById(id: string, body: import("@flusys/nestjs-shared").GetByIdBodyDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<NotificationResponseDto>>;
|
|
13
|
+
getByIds(body: import("@flusys/nestjs-shared").GetByIdsDto, user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").ListResponseDto<NotificationResponseDto>>;
|
|
14
14
|
update(updateDto: UpdateNotificationDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<NotificationResponseDto>>;
|
|
15
15
|
updateMany(updateDtos: UpdateNotificationDto[], user: ILoggedUserInfo | null): Promise<BulkResponseDto<NotificationResponseDto>>;
|
|
16
16
|
bulkUpsert(dtos: (CreateNotificationDto | UpdateNotificationDto)[], user: ILoggedUserInfo | null): Promise<BulkResponseDto<NotificationResponseDto>>;
|
|
17
17
|
getByFilter(filter: Record<string, any>, user: ILoggedUserInfo | null): Promise<SingleResponseDto<NotificationResponseDto>>;
|
|
18
|
-
getAll(filterAndPaginationDto: import("@flusys/nestjs-shared
|
|
19
|
-
delete(deleteDto: import("@flusys/nestjs-shared
|
|
18
|
+
getAll(filterAndPaginationDto: import("@flusys/nestjs-shared").FilterAndPaginationDto, user: ILoggedUserInfo | null, search?: string): Promise<import("@flusys/nestjs-shared").ListResponseDto<NotificationResponseDto>>;
|
|
19
|
+
delete(deleteDto: import("@flusys/nestjs-shared").DeleteDto, user: ILoggedUserInfo | null): Promise<MessageResponseDto>;
|
|
20
20
|
};
|
|
21
21
|
export declare class NotificationController extends NotificationController_base {
|
|
22
22
|
service: NotificationService;
|
|
@@ -25,31 +25,14 @@ function _ts_param(paramIndex, decorator) {
|
|
|
25
25
|
decorator(target, key, paramIndex);
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
import {
|
|
28
|
+
import { Inject, Injectable } from '@nestjs/common';
|
|
29
29
|
import { NotificationHelperService } from '../services/notification-helper.service';
|
|
30
30
|
export class NotificationAdapter {
|
|
31
31
|
async send(options) {
|
|
32
|
-
await this.notificationHelper.send(
|
|
33
|
-
userId: options.userId,
|
|
34
|
-
title: options.title,
|
|
35
|
-
message: options.message,
|
|
36
|
-
type: options.type,
|
|
37
|
-
data: options.data,
|
|
38
|
-
companyId: options.companyId
|
|
39
|
-
});
|
|
32
|
+
await this.notificationHelper.send(options);
|
|
40
33
|
}
|
|
41
34
|
async sendToMany(options) {
|
|
42
|
-
await this.notificationHelper.sendToMany(
|
|
43
|
-
userIds: options.userIds,
|
|
44
|
-
title: options.title,
|
|
45
|
-
message: options.message,
|
|
46
|
-
type: options.type,
|
|
47
|
-
data: options.data,
|
|
48
|
-
companyId: options.companyId
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
async broadcastToCompany(companyId, title, message, type, data) {
|
|
52
|
-
await this.notificationHelper.sendToCompany(companyId, title, message, type, data);
|
|
35
|
+
await this.notificationHelper.sendToMany(options);
|
|
53
36
|
}
|
|
54
37
|
isUserOnline(userId) {
|
|
55
38
|
return this.notificationHelper.isUserOnline(userId);
|
|
@@ -26,7 +26,6 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { createApiController, NOTIFICATION_PERMISSIONS } from '@flusys/nestjs-shared/classes';
|
|
29
|
-
import { NOTIFICATION_MESSAGES } from '../config';
|
|
30
29
|
import { CurrentUser, RequirePermission } from '@flusys/nestjs-shared/decorators';
|
|
31
30
|
import { BulkResponseDto, MessageResponseDto, SingleResponseDto } from '@flusys/nestjs-shared/dtos';
|
|
32
31
|
import { JwtAuthGuard, PermissionGuard } from '@flusys/nestjs-shared/guards';
|
|
@@ -34,6 +33,7 @@ import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
|
34
33
|
import { Body, Controller, HttpCode, HttpStatus, Inject, Post, UseGuards } from '@nestjs/common';
|
|
35
34
|
import { ApiBearerAuth, ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
|
36
35
|
import { plainToInstance } from 'class-transformer';
|
|
36
|
+
import { NOTIFICATION_MESSAGES } from '../config';
|
|
37
37
|
import { CreateNotificationDto, MarkReadDto, NotificationResponseDto, SendBulkNotificationDto, SendNotificationDto, UpdateNotificationDto } from '../dtos';
|
|
38
38
|
import { NotificationHelperService } from '../services/notification-helper.service';
|
|
39
39
|
import { NotificationService } from '../services/notification.service';
|
|
@@ -83,11 +83,14 @@ export class NotificationController extends createApiController(CreateNotificati
|
|
|
83
83
|
}) {
|
|
84
84
|
async markAsRead(dto, user) {
|
|
85
85
|
const notification = await this.service.markAsRead(dto.id, user);
|
|
86
|
+
const plainOptions = {
|
|
87
|
+
excludeExtraneousValues: true
|
|
88
|
+
};
|
|
86
89
|
return {
|
|
87
90
|
success: true,
|
|
88
91
|
message: 'Notification marked as read',
|
|
89
92
|
messageKey: NOTIFICATION_MESSAGES.MARK_READ_SUCCESS,
|
|
90
|
-
data: plainToInstance(NotificationResponseDto, notification)
|
|
93
|
+
data: plainToInstance(NotificationResponseDto, notification, plainOptions)
|
|
91
94
|
};
|
|
92
95
|
}
|
|
93
96
|
async markAllAsRead(user) {
|
|
@@ -121,11 +124,14 @@ export class NotificationController extends createApiController(CreateNotificati
|
|
|
121
124
|
data: dto.data,
|
|
122
125
|
companyId: dto.companyId
|
|
123
126
|
});
|
|
127
|
+
const plainOptions = {
|
|
128
|
+
excludeExtraneousValues: true
|
|
129
|
+
};
|
|
124
130
|
return {
|
|
125
131
|
success: true,
|
|
126
132
|
message: 'Notification sent successfully',
|
|
127
133
|
messageKey: NOTIFICATION_MESSAGES.SEND_SUCCESS,
|
|
128
|
-
data: plainToInstance(NotificationResponseDto, notification)
|
|
134
|
+
data: plainToInstance(NotificationResponseDto, notification, plainOptions)
|
|
129
135
|
};
|
|
130
136
|
}
|
|
131
137
|
async sendBulkNotification(dto) {
|
|
@@ -137,6 +143,9 @@ export class NotificationController extends createApiController(CreateNotificati
|
|
|
137
143
|
data: dto.data,
|
|
138
144
|
companyId: dto.companyId
|
|
139
145
|
});
|
|
146
|
+
const plainOptions = {
|
|
147
|
+
excludeExtraneousValues: true
|
|
148
|
+
};
|
|
140
149
|
return {
|
|
141
150
|
success: true,
|
|
142
151
|
message: `${notifications.length} notifications sent successfully`,
|
|
@@ -144,7 +153,7 @@ export class NotificationController extends createApiController(CreateNotificati
|
|
|
144
153
|
messageVariables: {
|
|
145
154
|
count: notifications.length
|
|
146
155
|
},
|
|
147
|
-
data: notifications.map((n)=>plainToInstance(NotificationResponseDto, n)),
|
|
156
|
+
data: notifications.map((n)=>plainToInstance(NotificationResponseDto, n, plainOptions)),
|
|
148
157
|
meta: {
|
|
149
158
|
count: notifications.length,
|
|
150
159
|
total: dto.userIds.length
|
|
@@ -20,10 +20,10 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
20
20
|
function _ts_metadata(k, v) {
|
|
21
21
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
22
|
}
|
|
23
|
+
import { NotificationType } from '@flusys/nestjs-shared/enums';
|
|
23
24
|
import { ApiProperty, ApiPropertyOptional, IntersectionType, OmitType, PartialType } from '@nestjs/swagger';
|
|
24
25
|
import { Expose } from 'class-transformer';
|
|
25
26
|
import { IsEnum, IsNotEmpty, IsObject, IsOptional, IsString, IsUUID, MaxLength } from 'class-validator';
|
|
26
|
-
import { NotificationType } from '@flusys/nestjs-shared/enums';
|
|
27
27
|
let NotificationContentDto = class NotificationContentDto {
|
|
28
28
|
constructor(){
|
|
29
29
|
_define_property(this, "title", void 0);
|
|
@@ -140,59 +140,106 @@ export class NotificationResponseDto {
|
|
|
140
140
|
}
|
|
141
141
|
_ts_decorate([
|
|
142
142
|
Expose(),
|
|
143
|
-
ApiProperty(
|
|
143
|
+
ApiProperty({
|
|
144
|
+
description: 'Unique identifier of the notification',
|
|
145
|
+
example: '018e1b2c-3d4e-5f6a-7b8c-9d0e1f2a3b4c'
|
|
146
|
+
}),
|
|
144
147
|
_ts_metadata("design:type", String)
|
|
145
148
|
], NotificationResponseDto.prototype, "id", void 0);
|
|
146
149
|
_ts_decorate([
|
|
147
150
|
Expose(),
|
|
148
|
-
ApiProperty(
|
|
151
|
+
ApiProperty({
|
|
152
|
+
description: 'ID of the user this notification belongs to',
|
|
153
|
+
example: '018e1b2c-3d4e-5f6a-7b8c-9d0e1f2a3b4c'
|
|
154
|
+
}),
|
|
149
155
|
_ts_metadata("design:type", String)
|
|
150
156
|
], NotificationResponseDto.prototype, "userId", void 0);
|
|
151
157
|
_ts_decorate([
|
|
152
158
|
Expose(),
|
|
153
159
|
ApiProperty({
|
|
154
|
-
|
|
160
|
+
description: 'Category of the notification',
|
|
161
|
+
enum: NotificationType,
|
|
162
|
+
example: NotificationType.SUCCESS
|
|
155
163
|
}),
|
|
156
|
-
_ts_metadata("design:type",
|
|
164
|
+
_ts_metadata("design:type", typeof NotificationType === "undefined" ? Object : NotificationType)
|
|
157
165
|
], NotificationResponseDto.prototype, "type", void 0);
|
|
158
166
|
_ts_decorate([
|
|
159
167
|
Expose(),
|
|
160
|
-
ApiProperty(
|
|
168
|
+
ApiProperty({
|
|
169
|
+
description: 'Short title of the notification',
|
|
170
|
+
example: 'Your export is ready'
|
|
171
|
+
}),
|
|
161
172
|
_ts_metadata("design:type", String)
|
|
162
173
|
], NotificationResponseDto.prototype, "title", void 0);
|
|
163
174
|
_ts_decorate([
|
|
164
175
|
Expose(),
|
|
165
|
-
ApiPropertyOptional(
|
|
176
|
+
ApiPropertyOptional({
|
|
177
|
+
description: 'Optional longer body text for the notification',
|
|
178
|
+
example: 'Your CSV export has finished processing and is ready to download.',
|
|
179
|
+
nullable: true
|
|
180
|
+
}),
|
|
166
181
|
_ts_metadata("design:type", Object)
|
|
167
182
|
], NotificationResponseDto.prototype, "message", void 0);
|
|
168
183
|
_ts_decorate([
|
|
169
184
|
Expose(),
|
|
170
|
-
ApiPropertyOptional(
|
|
185
|
+
ApiPropertyOptional({
|
|
186
|
+
description: 'Arbitrary JSON payload attached to the notification',
|
|
187
|
+
type: 'object',
|
|
188
|
+
additionalProperties: true,
|
|
189
|
+
nullable: true,
|
|
190
|
+
example: {
|
|
191
|
+
exportId: 'abc123',
|
|
192
|
+
fileUrl: 'https://cdn.example.com/export.csv'
|
|
193
|
+
}
|
|
194
|
+
}),
|
|
171
195
|
_ts_metadata("design:type", Object)
|
|
172
196
|
], NotificationResponseDto.prototype, "data", void 0);
|
|
173
197
|
_ts_decorate([
|
|
174
198
|
Expose(),
|
|
175
|
-
ApiProperty(
|
|
199
|
+
ApiProperty({
|
|
200
|
+
description: 'Whether the user has read this notification',
|
|
201
|
+
example: false
|
|
202
|
+
}),
|
|
176
203
|
_ts_metadata("design:type", Boolean)
|
|
177
204
|
], NotificationResponseDto.prototype, "isRead", void 0);
|
|
178
205
|
_ts_decorate([
|
|
179
206
|
Expose(),
|
|
180
|
-
ApiPropertyOptional(
|
|
207
|
+
ApiPropertyOptional({
|
|
208
|
+
description: 'Timestamp when the notification was marked as read; null if unread',
|
|
209
|
+
type: 'string',
|
|
210
|
+
format: 'date-time',
|
|
211
|
+
nullable: true,
|
|
212
|
+
example: '2024-03-15T10:30:00.000Z'
|
|
213
|
+
}),
|
|
181
214
|
_ts_metadata("design:type", Object)
|
|
182
215
|
], NotificationResponseDto.prototype, "readAt", void 0);
|
|
183
216
|
_ts_decorate([
|
|
184
217
|
Expose(),
|
|
185
|
-
ApiPropertyOptional(
|
|
218
|
+
ApiPropertyOptional({
|
|
219
|
+
description: 'Company scope for the notification; null for personal notifications',
|
|
220
|
+
example: '018e1b2c-3d4e-5f6a-7b8c-9d0e1f2a3b4c',
|
|
221
|
+
nullable: true
|
|
222
|
+
}),
|
|
186
223
|
_ts_metadata("design:type", Object)
|
|
187
224
|
], NotificationResponseDto.prototype, "companyId", void 0);
|
|
188
225
|
_ts_decorate([
|
|
189
226
|
Expose(),
|
|
190
|
-
ApiProperty(
|
|
227
|
+
ApiProperty({
|
|
228
|
+
description: 'Timestamp when the notification was created',
|
|
229
|
+
type: 'string',
|
|
230
|
+
format: 'date-time',
|
|
231
|
+
example: '2024-03-15T10:00:00.000Z'
|
|
232
|
+
}),
|
|
191
233
|
_ts_metadata("design:type", typeof Date === "undefined" ? Object : Date)
|
|
192
234
|
], NotificationResponseDto.prototype, "createdAt", void 0);
|
|
193
235
|
_ts_decorate([
|
|
194
236
|
Expose(),
|
|
195
|
-
ApiProperty(
|
|
237
|
+
ApiProperty({
|
|
238
|
+
description: 'Timestamp when the notification was last updated',
|
|
239
|
+
type: 'string',
|
|
240
|
+
format: 'date-time',
|
|
241
|
+
example: '2024-03-15T10:30:00.000Z'
|
|
242
|
+
}),
|
|
196
243
|
_ts_metadata("design:type", typeof Date === "undefined" ? Object : Date)
|
|
197
244
|
], NotificationResponseDto.prototype, "updatedAt", void 0);
|
|
198
245
|
export class UnreadCountResponseDto {
|
|
@@ -202,7 +249,11 @@ export class UnreadCountResponseDto {
|
|
|
202
249
|
}
|
|
203
250
|
_ts_decorate([
|
|
204
251
|
Expose(),
|
|
205
|
-
ApiProperty(
|
|
252
|
+
ApiProperty({
|
|
253
|
+
description: 'Total number of unread notifications for the user',
|
|
254
|
+
example: 5,
|
|
255
|
+
minimum: 0
|
|
256
|
+
}),
|
|
206
257
|
_ts_metadata("design:type", Number)
|
|
207
258
|
], UnreadCountResponseDto.prototype, "count", void 0);
|
|
208
259
|
export class SendNotificationDto extends IntersectionType(UserIdDto, NotificationContentDto) {
|
|
@@ -27,10 +27,6 @@ const ADAPTER_PROVIDER = {
|
|
|
27
27
|
};
|
|
28
28
|
export class NotificationModule {
|
|
29
29
|
static forRoot(options) {
|
|
30
|
-
const enableRealtime = options.config?.enableRealtime !== false;
|
|
31
|
-
const gatewayProviders = enableRealtime ? [
|
|
32
|
-
NotificationGateway
|
|
33
|
-
] : [];
|
|
34
30
|
return {
|
|
35
31
|
module: NotificationModule,
|
|
36
32
|
global: options.global ?? false,
|
|
@@ -41,13 +37,13 @@ export class NotificationModule {
|
|
|
41
37
|
controllers: options.includeController !== false ? CONTROLLERS : [],
|
|
42
38
|
providers: [
|
|
43
39
|
...this.buildProviders(options),
|
|
44
|
-
|
|
40
|
+
NotificationGateway,
|
|
45
41
|
NotificationAdapter,
|
|
46
42
|
ADAPTER_PROVIDER
|
|
47
43
|
],
|
|
48
44
|
exports: [
|
|
49
45
|
...EXPORTED_SERVICES,
|
|
50
|
-
|
|
46
|
+
NotificationGateway,
|
|
51
47
|
NOTIFICATION_ADAPTER
|
|
52
48
|
]
|
|
53
49
|
};
|
|
@@ -38,9 +38,6 @@ export class NotificationConfigService {
|
|
|
38
38
|
isMultiTenant() {
|
|
39
39
|
return this.getDatabaseMode() === 'multi-tenant';
|
|
40
40
|
}
|
|
41
|
-
isRealtimeEnabled() {
|
|
42
|
-
return this.options.config?.enableRealtime !== false;
|
|
43
|
-
}
|
|
44
41
|
getJwtSecret() {
|
|
45
42
|
return this.options.config?.jwtSecret;
|
|
46
43
|
}
|
|
@@ -26,8 +26,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { MultiTenantDataSourceService } from '@flusys/nestjs-shared/modules';
|
|
29
|
-
import {
|
|
30
|
-
import { Inject, Injectable, InternalServerErrorException, Optional, Scope } from '@nestjs/common';
|
|
29
|
+
import { Inject, Injectable, Optional, Scope } from '@nestjs/common';
|
|
31
30
|
import { REQUEST } from '@nestjs/core';
|
|
32
31
|
import { Request } from 'express';
|
|
33
32
|
import { NotificationConfigService } from './notification-config.service';
|
|
@@ -58,50 +57,6 @@ export class NotificationDataSourceProvider extends MultiTenantDataSourceService
|
|
|
58
57
|
const entities = await this.getNotificationEntities(enableCompanyFeature);
|
|
59
58
|
return super.createDataSourceFromConfig(config, entities);
|
|
60
59
|
}
|
|
61
|
-
async getSingleDataSource() {
|
|
62
|
-
if (NotificationDataSourceProvider.singleDataSource?.isInitialized) {
|
|
63
|
-
return NotificationDataSourceProvider.singleDataSource;
|
|
64
|
-
}
|
|
65
|
-
if (NotificationDataSourceProvider.singleConnectionLock) {
|
|
66
|
-
return NotificationDataSourceProvider.singleConnectionLock;
|
|
67
|
-
}
|
|
68
|
-
const config = this.getDefaultDatabaseConfig();
|
|
69
|
-
if (!config) {
|
|
70
|
-
throw new InternalServerErrorException({
|
|
71
|
-
message: 'No database config available. Provide defaultDatabaseConfig or tenantDefaultDatabaseConfig.',
|
|
72
|
-
messageKey: SYSTEM_MESSAGES.DATABASE_CONFIG_NOT_AVAILABLE
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
const connectionPromise = this.createDataSourceFromConfig(config);
|
|
76
|
-
NotificationDataSourceProvider.singleConnectionLock = connectionPromise;
|
|
77
|
-
try {
|
|
78
|
-
const dataSource = await connectionPromise;
|
|
79
|
-
NotificationDataSourceProvider.singleDataSource = dataSource;
|
|
80
|
-
return dataSource;
|
|
81
|
-
} finally{
|
|
82
|
-
NotificationDataSourceProvider.singleConnectionLock = null;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
async getOrCreateTenantConnection(tenant) {
|
|
86
|
-
const existing = NotificationDataSourceProvider.tenantConnections.get(tenant.id);
|
|
87
|
-
if (existing?.isInitialized) {
|
|
88
|
-
return existing;
|
|
89
|
-
}
|
|
90
|
-
const pendingConnection = NotificationDataSourceProvider.connectionLocks.get(tenant.id);
|
|
91
|
-
if (pendingConnection) {
|
|
92
|
-
return pendingConnection;
|
|
93
|
-
}
|
|
94
|
-
const config = this.buildTenantDatabaseConfig(tenant);
|
|
95
|
-
const connectionPromise = this.createDataSourceFromConfig(config);
|
|
96
|
-
NotificationDataSourceProvider.connectionLocks.set(tenant.id, connectionPromise);
|
|
97
|
-
try {
|
|
98
|
-
const dataSource = await connectionPromise;
|
|
99
|
-
NotificationDataSourceProvider.tenantConnections.set(tenant.id, dataSource);
|
|
100
|
-
return dataSource;
|
|
101
|
-
} finally{
|
|
102
|
-
NotificationDataSourceProvider.connectionLocks.delete(tenant.id);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
60
|
constructor(configService, request){
|
|
106
61
|
super(NotificationDataSourceProvider.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0), this.configService = configService;
|
|
107
62
|
}
|
|
@@ -25,100 +25,78 @@ function _ts_param(paramIndex, decorator) {
|
|
|
25
25
|
decorator(target, key, paramIndex);
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
import {
|
|
28
|
+
import { INotificationBulkSendOptions, INotificationSendOptions, LogAction } from '@flusys/nestjs-shared';
|
|
29
29
|
import { HybridCache } from '@flusys/nestjs-shared/classes';
|
|
30
|
-
import {
|
|
30
|
+
import { NotificationType } from '@flusys/nestjs-shared/enums';
|
|
31
31
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
32
|
+
import { Inject, Injectable, Optional } from '@nestjs/common';
|
|
33
|
+
import { Notification, NotificationWithCompany } from '../entities';
|
|
34
|
+
import { NotificationGateway } from '../gateways';
|
|
32
35
|
import { NotificationConfigService } from './notification-config.service';
|
|
33
36
|
import { NotificationDataSourceProvider } from './notification-datasource.provider';
|
|
34
|
-
import { NotificationGateway } from '../gateways';
|
|
35
|
-
import { Notification, NotificationWithCompany } from '../entities';
|
|
36
|
-
import { NotificationType } from '@flusys/nestjs-shared/enums';
|
|
37
37
|
export class NotificationHelperService {
|
|
38
|
-
async getDataSource() {
|
|
39
|
-
if (!this.dataSource) {
|
|
40
|
-
this.dataSource = await this.dataSourceProvider.getDataSource();
|
|
41
|
-
}
|
|
42
|
-
return this.dataSource;
|
|
43
|
-
}
|
|
44
|
-
async getRepository() {
|
|
45
|
-
const ds = await this.getDataSource();
|
|
46
|
-
const EntityClass = this.configService.isCompanyFeatureEnabled() ? NotificationWithCompany : Notification;
|
|
47
|
-
return ds.getRepository(EntityClass);
|
|
48
|
-
}
|
|
49
38
|
async send(options) {
|
|
50
|
-
const { userId, title, message = null, type = NotificationType.INFO, data = null, companyId } = options;
|
|
51
39
|
const repo = await this.getRepository();
|
|
52
|
-
const entity =
|
|
53
|
-
userId,
|
|
54
|
-
type,
|
|
55
|
-
title,
|
|
56
|
-
message,
|
|
57
|
-
data,
|
|
58
|
-
isRead: false
|
|
59
|
-
};
|
|
60
|
-
if (this.configService.isCompanyFeatureEnabled() && companyId) {
|
|
61
|
-
entity.companyId = companyId;
|
|
62
|
-
}
|
|
40
|
+
const entity = this.buildEntity(options.userId, options);
|
|
63
41
|
const saved = await repo.save(entity);
|
|
64
42
|
await this.clearCache();
|
|
65
|
-
this.
|
|
43
|
+
this.emitToUser(saved, options.realtime !== false);
|
|
66
44
|
return saved;
|
|
67
45
|
}
|
|
68
46
|
async sendToMany(options) {
|
|
69
|
-
const { userIds, title, message = null, type = NotificationType.INFO, data = null, companyId } = options;
|
|
70
47
|
const repo = await this.getRepository();
|
|
71
|
-
const entities = userIds.map((userId)=>(
|
|
72
|
-
userId,
|
|
73
|
-
type,
|
|
74
|
-
title,
|
|
75
|
-
message,
|
|
76
|
-
data,
|
|
77
|
-
isRead: false,
|
|
78
|
-
...this.configService.isCompanyFeatureEnabled() && companyId ? {
|
|
79
|
-
companyId
|
|
80
|
-
} : {}
|
|
81
|
-
}));
|
|
48
|
+
const entities = options.userIds.map((userId)=>this.buildEntity(userId, options));
|
|
82
49
|
const saved = await repo.save(entities);
|
|
83
50
|
await this.clearCache();
|
|
84
|
-
|
|
85
|
-
|
|
51
|
+
if (options.realtime !== false) {
|
|
52
|
+
setImmediate(()=>{
|
|
53
|
+
for (const notification of saved){
|
|
54
|
+
this.emitToUser(notification, true);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
86
57
|
}
|
|
87
58
|
return saved;
|
|
88
59
|
}
|
|
89
|
-
async sendToCompany(companyId, title, message, type = NotificationType.INFO, data) {
|
|
90
|
-
if (!this.configService.isCompanyFeatureEnabled()) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
if (this.configService.isRealtimeEnabled() && this.gateway) {
|
|
94
|
-
const payload = {
|
|
95
|
-
id: `broadcast-${Date.now()}`,
|
|
96
|
-
type,
|
|
97
|
-
title,
|
|
98
|
-
message: message ?? null,
|
|
99
|
-
data: data ?? null,
|
|
100
|
-
createdAt: new Date()
|
|
101
|
-
};
|
|
102
|
-
this.gateway.emitToCompany(companyId, 'notification:new', payload);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
60
|
isUserOnline(userId) {
|
|
106
61
|
return this.gateway?.isUserOnline(userId) ?? false;
|
|
107
62
|
}
|
|
108
63
|
getOnlineUserCount() {
|
|
109
64
|
return this.gateway?.getOnlineUserCount() ?? 0;
|
|
110
65
|
}
|
|
111
|
-
|
|
112
|
-
if (!this.
|
|
66
|
+
async getDataSource() {
|
|
67
|
+
if (!this.dataSource) {
|
|
68
|
+
this.dataSource = await this.dataSourceProvider.getDataSource();
|
|
69
|
+
}
|
|
70
|
+
return this.dataSource;
|
|
71
|
+
}
|
|
72
|
+
async getRepository() {
|
|
73
|
+
const ds = await this.getDataSource();
|
|
74
|
+
const EntityClass = this.configService.isCompanyFeatureEnabled() ? NotificationWithCompany : Notification;
|
|
75
|
+
return ds.getRepository(EntityClass);
|
|
76
|
+
}
|
|
77
|
+
buildEntity(userId, content) {
|
|
78
|
+
const entity = {
|
|
79
|
+
userId,
|
|
80
|
+
type: content.type ?? NotificationType.INFO,
|
|
81
|
+
title: content.title,
|
|
82
|
+
message: content.message ?? null,
|
|
83
|
+
data: content.data ?? null,
|
|
84
|
+
isRead: false
|
|
85
|
+
};
|
|
86
|
+
if (this.configService.isCompanyFeatureEnabled() && content.companyId) {
|
|
87
|
+
entity.companyId = content.companyId;
|
|
88
|
+
}
|
|
89
|
+
return entity;
|
|
90
|
+
}
|
|
91
|
+
emitToUser(notification, realtime) {
|
|
92
|
+
if (!realtime || !this.gateway) {
|
|
113
93
|
return;
|
|
114
94
|
}
|
|
115
95
|
const ext = notification;
|
|
116
96
|
const payload = this.toPayload(notification);
|
|
117
97
|
if (this.configService.isCompanyFeatureEnabled() && ext.companyId) {
|
|
118
|
-
// Company feature enabled - emit only to sockets in matching company context
|
|
119
98
|
this.gateway.emitToUserInCompany(notification.userId, ext.companyId, 'notification:new', payload);
|
|
120
99
|
} else {
|
|
121
|
-
// No company feature or no companyId - emit to all user's sockets
|
|
122
100
|
this.gateway.emitToUser(notification.userId, 'notification:new', payload);
|
|
123
101
|
}
|
|
124
102
|
}
|
|
@@ -133,7 +111,7 @@ export class NotificationHelperService {
|
|
|
133
111
|
};
|
|
134
112
|
}
|
|
135
113
|
async clearCache() {
|
|
136
|
-
await this.utilsService.clearCache(
|
|
114
|
+
await this.utilsService.clearCache('notification', this.cacheManager);
|
|
137
115
|
}
|
|
138
116
|
constructor(cacheManager, utilsService, configService, dataSourceProvider, gateway){
|
|
139
117
|
_define_property(this, "cacheManager", void 0);
|
|
@@ -141,14 +119,12 @@ export class NotificationHelperService {
|
|
|
141
119
|
_define_property(this, "configService", void 0);
|
|
142
120
|
_define_property(this, "dataSourceProvider", void 0);
|
|
143
121
|
_define_property(this, "gateway", void 0);
|
|
144
|
-
_define_property(this, "entityName", void 0);
|
|
145
122
|
_define_property(this, "dataSource", void 0);
|
|
146
123
|
this.cacheManager = cacheManager;
|
|
147
124
|
this.utilsService = utilsService;
|
|
148
125
|
this.configService = configService;
|
|
149
126
|
this.dataSourceProvider = dataSourceProvider;
|
|
150
127
|
this.gateway = gateway;
|
|
151
|
-
this.entityName = 'notification';
|
|
152
128
|
this.dataSource = null;
|
|
153
129
|
}
|
|
154
130
|
}
|
|
@@ -159,7 +135,7 @@ _ts_decorate([
|
|
|
159
135
|
}),
|
|
160
136
|
_ts_metadata("design:type", Function),
|
|
161
137
|
_ts_metadata("design:paramtypes", [
|
|
162
|
-
typeof
|
|
138
|
+
typeof INotificationSendOptions === "undefined" ? Object : INotificationSendOptions
|
|
163
139
|
]),
|
|
164
140
|
_ts_metadata("design:returntype", Promise)
|
|
165
141
|
], NotificationHelperService.prototype, "send", null);
|
|
@@ -170,25 +146,10 @@ _ts_decorate([
|
|
|
170
146
|
}),
|
|
171
147
|
_ts_metadata("design:type", Function),
|
|
172
148
|
_ts_metadata("design:paramtypes", [
|
|
173
|
-
typeof
|
|
149
|
+
typeof INotificationBulkSendOptions === "undefined" ? Object : INotificationBulkSendOptions
|
|
174
150
|
]),
|
|
175
151
|
_ts_metadata("design:returntype", Promise)
|
|
176
152
|
], 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);
|
|
192
153
|
NotificationHelperService = _ts_decorate([
|
|
193
154
|
Injectable(),
|
|
194
155
|
_ts_param(0, Inject('CACHE_INSTANCE')),
|