@flusys/nestjs-notification 3.0.1
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/README.md +998 -0
- package/adapters/index.d.ts +1 -0
- package/adapters/notification.adapter.d.ts +10 -0
- package/cjs/adapters/index.js +18 -0
- package/cjs/adapters/notification.adapter.js +79 -0
- package/cjs/config/index.js +18 -0
- package/cjs/config/notification.constants.js +11 -0
- package/cjs/controllers/index.js +18 -0
- package/cjs/controllers/notification.controller.js +278 -0
- package/cjs/docs/index.js +18 -0
- package/cjs/docs/notification-swagger.config.js +61 -0
- package/cjs/dtos/index.js +18 -0
- package/cjs/dtos/notification.dto.js +244 -0
- package/cjs/entities/index.js +48 -0
- package/cjs/entities/notification-with-company.entity.js +57 -0
- package/cjs/entities/notification.entity.js +111 -0
- package/cjs/gateways/index.js +18 -0
- package/cjs/gateways/notification.gateway.js +226 -0
- package/cjs/index.js +28 -0
- package/cjs/interfaces/index.js +19 -0
- package/cjs/interfaces/notification-module.interface.js +4 -0
- package/cjs/interfaces/notification.interface.js +4 -0
- package/cjs/modules/index.js +18 -0
- package/cjs/modules/notification.module.js +139 -0
- package/cjs/services/index.js +21 -0
- package/cjs/services/notification-config.service.js +72 -0
- package/cjs/services/notification-datasource.provider.js +174 -0
- package/cjs/services/notification-helper.service.js +186 -0
- package/cjs/services/notification.service.js +220 -0
- package/config/index.d.ts +1 -0
- package/config/notification.constants.d.ts +1 -0
- package/controllers/index.d.ts +1 -0
- package/controllers/notification.controller.d.ts +26 -0
- package/docs/index.d.ts +1 -0
- package/docs/notification-swagger.config.d.ts +2 -0
- package/dtos/index.d.ts +1 -0
- package/dtos/notification.dto.d.ts +47 -0
- package/entities/index.d.ts +8 -0
- package/entities/notification-with-company.entity.d.ts +4 -0
- package/entities/notification.entity.d.ts +10 -0
- package/fesm/adapters/index.js +1 -0
- package/fesm/adapters/notification.adapter.js +69 -0
- package/fesm/config/index.js +1 -0
- package/fesm/config/notification.constants.js +1 -0
- package/fesm/controllers/index.js +1 -0
- package/fesm/controllers/notification.controller.js +268 -0
- package/fesm/docs/index.js +1 -0
- package/fesm/docs/notification-swagger.config.js +51 -0
- package/fesm/dtos/index.js +1 -0
- package/fesm/dtos/notification.dto.js +211 -0
- package/fesm/entities/index.js +14 -0
- package/fesm/entities/notification-with-company.entity.js +47 -0
- package/fesm/entities/notification.entity.js +101 -0
- package/fesm/gateways/index.js +1 -0
- package/fesm/gateways/notification.gateway.js +175 -0
- package/fesm/index.js +20 -0
- package/fesm/interfaces/index.js +2 -0
- package/fesm/interfaces/notification-module.interface.js +1 -0
- package/fesm/interfaces/notification.interface.js +1 -0
- package/fesm/modules/index.js +1 -0
- package/fesm/modules/notification.module.js +129 -0
- package/fesm/services/index.js +4 -0
- package/fesm/services/notification-config.service.js +62 -0
- package/fesm/services/notification-datasource.provider.js +123 -0
- package/fesm/services/notification-helper.service.js +176 -0
- package/fesm/services/notification.service.js +210 -0
- package/gateways/index.d.ts +1 -0
- package/gateways/notification.gateway.d.ts +21 -0
- package/index.d.ts +10 -0
- package/interfaces/index.d.ts +2 -0
- package/interfaces/notification-module.interface.d.ts +20 -0
- package/interfaces/notification.interface.d.ts +19 -0
- package/modules/index.d.ts +1 -0
- package/modules/notification.module.d.ts +8 -0
- package/package.json +98 -0
- package/services/index.d.ts +4 -0
- package/services/notification-config.service.d.ts +13 -0
- package/services/notification-datasource.provider.d.ts +23 -0
- package/services/notification-helper.service.d.ts +44 -0
- package/services/notification.service.d.ts +35 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "NotificationDataSourceProvider", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return NotificationDataSourceProvider;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _modules = require("@flusys/nestjs-shared/modules");
|
|
12
|
+
const _common = require("@nestjs/common");
|
|
13
|
+
const _core = require("@nestjs/core");
|
|
14
|
+
const _express = require("express");
|
|
15
|
+
const _notificationconfigservice = require("./notification-config.service");
|
|
16
|
+
function _define_property(obj, key, value) {
|
|
17
|
+
if (key in obj) {
|
|
18
|
+
Object.defineProperty(obj, key, {
|
|
19
|
+
value: value,
|
|
20
|
+
enumerable: true,
|
|
21
|
+
configurable: true,
|
|
22
|
+
writable: true
|
|
23
|
+
});
|
|
24
|
+
} else {
|
|
25
|
+
obj[key] = value;
|
|
26
|
+
}
|
|
27
|
+
return obj;
|
|
28
|
+
}
|
|
29
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
30
|
+
if (typeof WeakMap !== "function") return null;
|
|
31
|
+
var cacheBabelInterop = new WeakMap();
|
|
32
|
+
var cacheNodeInterop = new WeakMap();
|
|
33
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
34
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
35
|
+
})(nodeInterop);
|
|
36
|
+
}
|
|
37
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
38
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
39
|
+
return obj;
|
|
40
|
+
}
|
|
41
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
42
|
+
return {
|
|
43
|
+
default: obj
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
47
|
+
if (cache && cache.has(obj)) {
|
|
48
|
+
return cache.get(obj);
|
|
49
|
+
}
|
|
50
|
+
var newObj = {
|
|
51
|
+
__proto__: null
|
|
52
|
+
};
|
|
53
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
54
|
+
for(var key in obj){
|
|
55
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
56
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
57
|
+
if (desc && (desc.get || desc.set)) {
|
|
58
|
+
Object.defineProperty(newObj, key, desc);
|
|
59
|
+
} else {
|
|
60
|
+
newObj[key] = obj[key];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
newObj.default = obj;
|
|
65
|
+
if (cache) {
|
|
66
|
+
cache.set(obj, newObj);
|
|
67
|
+
}
|
|
68
|
+
return newObj;
|
|
69
|
+
}
|
|
70
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
71
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
72
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
73
|
+
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;
|
|
74
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
75
|
+
}
|
|
76
|
+
function _ts_metadata(k, v) {
|
|
77
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
78
|
+
}
|
|
79
|
+
function _ts_param(paramIndex, decorator) {
|
|
80
|
+
return function(target, key) {
|
|
81
|
+
decorator(target, key, paramIndex);
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
let NotificationDataSourceProvider = class NotificationDataSourceProvider extends _modules.MultiTenantDataSourceService {
|
|
85
|
+
static buildParentOptions(options) {
|
|
86
|
+
return {
|
|
87
|
+
bootstrapAppConfig: options.bootstrapAppConfig,
|
|
88
|
+
defaultDatabaseConfig: options.config?.defaultDatabaseConfig,
|
|
89
|
+
tenantDefaultDatabaseConfig: options.config?.tenantDefaultDatabaseConfig,
|
|
90
|
+
tenants: options.config?.tenants
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
getEnableCompanyFeatureForTenant(tenant) {
|
|
94
|
+
return tenant?.enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
|
|
95
|
+
}
|
|
96
|
+
async getNotificationEntities(enableCompanyFeature) {
|
|
97
|
+
const enable = enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
|
|
98
|
+
const entities = await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")));
|
|
99
|
+
return enable ? [
|
|
100
|
+
entities.NotificationWithCompany
|
|
101
|
+
] : [
|
|
102
|
+
entities.Notification
|
|
103
|
+
];
|
|
104
|
+
}
|
|
105
|
+
async createDataSourceFromConfig(config) {
|
|
106
|
+
const currentTenant = this.getCurrentTenant();
|
|
107
|
+
const enableCompanyFeature = this.getEnableCompanyFeatureForTenant(currentTenant ?? undefined);
|
|
108
|
+
const entities = await this.getNotificationEntities(enableCompanyFeature);
|
|
109
|
+
return super.createDataSourceFromConfig(config, entities);
|
|
110
|
+
}
|
|
111
|
+
async getSingleDataSource() {
|
|
112
|
+
if (NotificationDataSourceProvider.singleDataSource?.isInitialized) {
|
|
113
|
+
return NotificationDataSourceProvider.singleDataSource;
|
|
114
|
+
}
|
|
115
|
+
if (NotificationDataSourceProvider.singleConnectionLock) {
|
|
116
|
+
return NotificationDataSourceProvider.singleConnectionLock;
|
|
117
|
+
}
|
|
118
|
+
const config = this.getDefaultDatabaseConfig();
|
|
119
|
+
if (!config) {
|
|
120
|
+
throw new _common.InternalServerErrorException('No database config available. Provide defaultDatabaseConfig or tenantDefaultDatabaseConfig.');
|
|
121
|
+
}
|
|
122
|
+
const connectionPromise = this.createDataSourceFromConfig(config);
|
|
123
|
+
NotificationDataSourceProvider.singleConnectionLock = connectionPromise;
|
|
124
|
+
try {
|
|
125
|
+
const dataSource = await connectionPromise;
|
|
126
|
+
NotificationDataSourceProvider.singleDataSource = dataSource;
|
|
127
|
+
return dataSource;
|
|
128
|
+
} finally{
|
|
129
|
+
NotificationDataSourceProvider.singleConnectionLock = null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async getOrCreateTenantConnection(tenant) {
|
|
133
|
+
const existing = NotificationDataSourceProvider.tenantConnections.get(tenant.id);
|
|
134
|
+
if (existing?.isInitialized) {
|
|
135
|
+
return existing;
|
|
136
|
+
}
|
|
137
|
+
const pendingConnection = NotificationDataSourceProvider.connectionLocks.get(tenant.id);
|
|
138
|
+
if (pendingConnection) {
|
|
139
|
+
return pendingConnection;
|
|
140
|
+
}
|
|
141
|
+
const config = this.buildTenantDatabaseConfig(tenant);
|
|
142
|
+
const connectionPromise = this.createDataSourceFromConfig(config);
|
|
143
|
+
NotificationDataSourceProvider.connectionLocks.set(tenant.id, connectionPromise);
|
|
144
|
+
try {
|
|
145
|
+
const dataSource = await connectionPromise;
|
|
146
|
+
NotificationDataSourceProvider.tenantConnections.set(tenant.id, dataSource);
|
|
147
|
+
return dataSource;
|
|
148
|
+
} finally{
|
|
149
|
+
NotificationDataSourceProvider.connectionLocks.delete(tenant.id);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
constructor(configService, request){
|
|
153
|
+
super(NotificationDataSourceProvider.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0), _define_property(this, "logger", void 0), this.configService = configService, this.logger = new _common.Logger(NotificationDataSourceProvider.name);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
_define_property(NotificationDataSourceProvider, "tenantConnections", new Map());
|
|
157
|
+
_define_property(NotificationDataSourceProvider, "singleDataSource", null);
|
|
158
|
+
_define_property(NotificationDataSourceProvider, "tenantsRegistry", new Map());
|
|
159
|
+
_define_property(NotificationDataSourceProvider, "initialized", false);
|
|
160
|
+
_define_property(NotificationDataSourceProvider, "connectionLocks", new Map());
|
|
161
|
+
_define_property(NotificationDataSourceProvider, "singleConnectionLock", null);
|
|
162
|
+
NotificationDataSourceProvider = _ts_decorate([
|
|
163
|
+
(0, _common.Injectable)({
|
|
164
|
+
scope: _common.Scope.REQUEST
|
|
165
|
+
}),
|
|
166
|
+
_ts_param(0, (0, _common.Inject)(_notificationconfigservice.NotificationConfigService)),
|
|
167
|
+
_ts_param(1, (0, _common.Optional)()),
|
|
168
|
+
_ts_param(1, (0, _common.Inject)(_core.REQUEST)),
|
|
169
|
+
_ts_metadata("design:type", Function),
|
|
170
|
+
_ts_metadata("design:paramtypes", [
|
|
171
|
+
typeof _notificationconfigservice.NotificationConfigService === "undefined" ? Object : _notificationconfigservice.NotificationConfigService,
|
|
172
|
+
typeof _express.Request === "undefined" ? Object : _express.Request
|
|
173
|
+
])
|
|
174
|
+
], NotificationDataSourceProvider);
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "NotificationHelperService", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return NotificationHelperService;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _common = require("@nestjs/common");
|
|
12
|
+
const _classes = require("@flusys/nestjs-shared/classes");
|
|
13
|
+
const _modules = require("@flusys/nestjs-shared/modules");
|
|
14
|
+
const _notificationconfigservice = require("./notification-config.service");
|
|
15
|
+
const _notificationdatasourceprovider = require("./notification-datasource.provider");
|
|
16
|
+
const _gateways = require("../gateways");
|
|
17
|
+
const _entities = require("../entities");
|
|
18
|
+
const _enums = require("@flusys/nestjs-shared/enums");
|
|
19
|
+
function _define_property(obj, key, value) {
|
|
20
|
+
if (key in obj) {
|
|
21
|
+
Object.defineProperty(obj, key, {
|
|
22
|
+
value: value,
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true
|
|
26
|
+
});
|
|
27
|
+
} else {
|
|
28
|
+
obj[key] = value;
|
|
29
|
+
}
|
|
30
|
+
return obj;
|
|
31
|
+
}
|
|
32
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
33
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
34
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
35
|
+
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;
|
|
36
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
37
|
+
}
|
|
38
|
+
function _ts_metadata(k, v) {
|
|
39
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
40
|
+
}
|
|
41
|
+
function _ts_param(paramIndex, decorator) {
|
|
42
|
+
return function(target, key) {
|
|
43
|
+
decorator(target, key, paramIndex);
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
let NotificationHelperService = class NotificationHelperService {
|
|
47
|
+
async getDataSource() {
|
|
48
|
+
if (!this.dataSource) {
|
|
49
|
+
this.dataSource = await this.dataSourceProvider.getDataSource();
|
|
50
|
+
}
|
|
51
|
+
return this.dataSource;
|
|
52
|
+
}
|
|
53
|
+
async getRepository() {
|
|
54
|
+
const ds = await this.getDataSource();
|
|
55
|
+
const EntityClass = this.configService.isCompanyFeatureEnabled() ? _entities.NotificationWithCompany : _entities.Notification;
|
|
56
|
+
return ds.getRepository(EntityClass);
|
|
57
|
+
}
|
|
58
|
+
async send(options) {
|
|
59
|
+
const { userId, title, message = null, type = _enums.NotificationType.INFO, data = null, companyId } = options;
|
|
60
|
+
const repo = await this.getRepository();
|
|
61
|
+
const entity = {
|
|
62
|
+
userId,
|
|
63
|
+
type,
|
|
64
|
+
title,
|
|
65
|
+
message,
|
|
66
|
+
data,
|
|
67
|
+
isRead: false
|
|
68
|
+
};
|
|
69
|
+
if (this.configService.isCompanyFeatureEnabled() && companyId) {
|
|
70
|
+
entity.companyId = companyId;
|
|
71
|
+
}
|
|
72
|
+
const saved = await repo.save(entity);
|
|
73
|
+
await this.clearCache();
|
|
74
|
+
this.emitRealtime(saved);
|
|
75
|
+
this.logger.debug(`Notification sent to user ${userId}: ${title}`);
|
|
76
|
+
return saved;
|
|
77
|
+
}
|
|
78
|
+
async sendToMany(options) {
|
|
79
|
+
const { userIds, title, message = null, type = _enums.NotificationType.INFO, data = null, companyId } = options;
|
|
80
|
+
const repo = await this.getRepository();
|
|
81
|
+
const entities = userIds.map((userId)=>({
|
|
82
|
+
userId,
|
|
83
|
+
type,
|
|
84
|
+
title,
|
|
85
|
+
message,
|
|
86
|
+
data,
|
|
87
|
+
isRead: false,
|
|
88
|
+
...this.configService.isCompanyFeatureEnabled() && companyId ? {
|
|
89
|
+
companyId
|
|
90
|
+
} : {}
|
|
91
|
+
}));
|
|
92
|
+
const saved = await repo.save(entities);
|
|
93
|
+
await this.clearCache();
|
|
94
|
+
for (const notification of saved){
|
|
95
|
+
this.emitRealtime(notification);
|
|
96
|
+
}
|
|
97
|
+
this.logger.debug(`Notification sent to ${userIds.length} users: ${title}`);
|
|
98
|
+
return saved;
|
|
99
|
+
}
|
|
100
|
+
async sendToCompany(companyId, title, message, type = _enums.NotificationType.INFO, data) {
|
|
101
|
+
if (!this.configService.isCompanyFeatureEnabled()) {
|
|
102
|
+
this.logger.warn('sendToCompany called but company feature is disabled');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (this.configService.isRealtimeEnabled() && this.gateway) {
|
|
106
|
+
const payload = {
|
|
107
|
+
id: `broadcast-${Date.now()}`,
|
|
108
|
+
type,
|
|
109
|
+
title,
|
|
110
|
+
message: message ?? null,
|
|
111
|
+
data: data ?? null,
|
|
112
|
+
createdAt: new Date()
|
|
113
|
+
};
|
|
114
|
+
this.gateway.emitToCompany(companyId, 'notification:new', payload);
|
|
115
|
+
this.logger.debug(`Broadcast notification sent to company ${companyId}: ${title}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
isUserOnline(userId) {
|
|
119
|
+
return this.gateway?.isUserOnline(userId) ?? false;
|
|
120
|
+
}
|
|
121
|
+
getOnlineUserCount() {
|
|
122
|
+
return this.gateway?.getOnlineUserCount() ?? 0;
|
|
123
|
+
}
|
|
124
|
+
emitRealtime(notification) {
|
|
125
|
+
if (!this.configService.isRealtimeEnabled() || !this.gateway) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const ext = notification;
|
|
129
|
+
const payload = this.toPayload(notification);
|
|
130
|
+
if (this.configService.isCompanyFeatureEnabled() && ext.companyId) {
|
|
131
|
+
// Company feature enabled - emit only to sockets in matching company context
|
|
132
|
+
this.gateway.emitToUserInCompany(notification.userId, ext.companyId, 'notification:new', payload);
|
|
133
|
+
} else {
|
|
134
|
+
// No company feature or no companyId - emit to all user's sockets
|
|
135
|
+
this.gateway.emitToUser(notification.userId, 'notification:new', payload);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
toPayload(notification) {
|
|
139
|
+
return {
|
|
140
|
+
id: notification.id,
|
|
141
|
+
type: notification.type,
|
|
142
|
+
title: notification.title,
|
|
143
|
+
message: notification.message,
|
|
144
|
+
data: notification.data,
|
|
145
|
+
createdAt: notification.createdAt
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
async clearCache() {
|
|
149
|
+
await this.utilsService.clearCache(this.entityName, this.cacheManager);
|
|
150
|
+
}
|
|
151
|
+
constructor(cacheManager, utilsService, configService, dataSourceProvider, gateway){
|
|
152
|
+
_define_property(this, "cacheManager", void 0);
|
|
153
|
+
_define_property(this, "utilsService", void 0);
|
|
154
|
+
_define_property(this, "configService", void 0);
|
|
155
|
+
_define_property(this, "dataSourceProvider", void 0);
|
|
156
|
+
_define_property(this, "gateway", void 0);
|
|
157
|
+
_define_property(this, "logger", void 0);
|
|
158
|
+
_define_property(this, "entityName", void 0);
|
|
159
|
+
_define_property(this, "dataSource", void 0);
|
|
160
|
+
this.cacheManager = cacheManager;
|
|
161
|
+
this.utilsService = utilsService;
|
|
162
|
+
this.configService = configService;
|
|
163
|
+
this.dataSourceProvider = dataSourceProvider;
|
|
164
|
+
this.gateway = gateway;
|
|
165
|
+
this.logger = new _common.Logger(NotificationHelperService.name);
|
|
166
|
+
this.entityName = 'notification';
|
|
167
|
+
this.dataSource = null;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
NotificationHelperService = _ts_decorate([
|
|
171
|
+
(0, _common.Injectable)(),
|
|
172
|
+
_ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
|
|
173
|
+
_ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
|
|
174
|
+
_ts_param(2, (0, _common.Inject)(_notificationconfigservice.NotificationConfigService)),
|
|
175
|
+
_ts_param(3, (0, _common.Inject)(_notificationdatasourceprovider.NotificationDataSourceProvider)),
|
|
176
|
+
_ts_param(4, (0, _common.Optional)()),
|
|
177
|
+
_ts_param(4, (0, _common.Inject)(_gateways.NotificationGateway)),
|
|
178
|
+
_ts_metadata("design:type", Function),
|
|
179
|
+
_ts_metadata("design:paramtypes", [
|
|
180
|
+
typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
|
|
181
|
+
typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
|
|
182
|
+
typeof _notificationconfigservice.NotificationConfigService === "undefined" ? Object : _notificationconfigservice.NotificationConfigService,
|
|
183
|
+
typeof _notificationdatasourceprovider.NotificationDataSourceProvider === "undefined" ? Object : _notificationdatasourceprovider.NotificationDataSourceProvider,
|
|
184
|
+
typeof _gateways.NotificationGateway === "undefined" ? Object : _gateways.NotificationGateway
|
|
185
|
+
])
|
|
186
|
+
], NotificationHelperService);
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "NotificationService", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return NotificationService;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _classes = require("@flusys/nestjs-shared/classes");
|
|
12
|
+
const _modules = require("@flusys/nestjs-shared/modules");
|
|
13
|
+
const _utils = require("@flusys/nestjs-shared/utils");
|
|
14
|
+
const _common = require("@nestjs/common");
|
|
15
|
+
const _entities = require("../entities");
|
|
16
|
+
const _gateways = require("../gateways");
|
|
17
|
+
const _notificationconfigservice = require("./notification-config.service");
|
|
18
|
+
const _notificationdatasourceprovider = require("./notification-datasource.provider");
|
|
19
|
+
function _define_property(obj, key, value) {
|
|
20
|
+
if (key in obj) {
|
|
21
|
+
Object.defineProperty(obj, key, {
|
|
22
|
+
value: value,
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true
|
|
26
|
+
});
|
|
27
|
+
} else {
|
|
28
|
+
obj[key] = value;
|
|
29
|
+
}
|
|
30
|
+
return obj;
|
|
31
|
+
}
|
|
32
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
33
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
34
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
35
|
+
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;
|
|
36
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
37
|
+
}
|
|
38
|
+
function _ts_metadata(k, v) {
|
|
39
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
40
|
+
}
|
|
41
|
+
function _ts_param(paramIndex, decorator) {
|
|
42
|
+
return function(target, key) {
|
|
43
|
+
decorator(target, key, paramIndex);
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
let NotificationService = class NotificationService extends _classes.RequestScopedApiService {
|
|
47
|
+
resolveEntity() {
|
|
48
|
+
return this.notificationConfig.isCompanyFeatureEnabled() ? _entities.NotificationWithCompany : _entities.Notification;
|
|
49
|
+
}
|
|
50
|
+
getDataSourceProvider() {
|
|
51
|
+
return this.dataSourceProvider;
|
|
52
|
+
}
|
|
53
|
+
async convertSingleDtoToEntity(dto, user) {
|
|
54
|
+
let entity = {};
|
|
55
|
+
if ('id' in dto && dto.id) {
|
|
56
|
+
const existing = await this.repository.findOne({
|
|
57
|
+
where: {
|
|
58
|
+
id: dto.id
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
if (!existing) throw new _common.NotFoundException('Notification not found');
|
|
62
|
+
entity = existing;
|
|
63
|
+
}
|
|
64
|
+
const merged = {
|
|
65
|
+
...entity,
|
|
66
|
+
userId: user?.id ?? entity.userId,
|
|
67
|
+
type: dto.type ?? entity.type ?? 'info',
|
|
68
|
+
title: dto.title ?? entity.title,
|
|
69
|
+
message: dto.message ?? entity.message,
|
|
70
|
+
data: dto.data ?? entity.data,
|
|
71
|
+
isRead: entity.isRead ?? false,
|
|
72
|
+
readAt: entity.readAt
|
|
73
|
+
};
|
|
74
|
+
if (this.notificationConfig.isCompanyFeatureEnabled()) {
|
|
75
|
+
merged.companyId = dto.companyId ?? user?.companyId ?? entity.companyId ?? null;
|
|
76
|
+
}
|
|
77
|
+
return merged;
|
|
78
|
+
}
|
|
79
|
+
async getFilterQuery(query, filter, _user) {
|
|
80
|
+
for (const [key, value] of Object.entries(filter)){
|
|
81
|
+
if (key === 'isRead' && typeof value === 'boolean') {
|
|
82
|
+
query.andWhere(`${this.entityName}.isRead = :isRead`, {
|
|
83
|
+
isRead: value
|
|
84
|
+
});
|
|
85
|
+
} else if (key === 'type' && value) {
|
|
86
|
+
query.andWhere(`${this.entityName}.type = :type`, {
|
|
87
|
+
type: value
|
|
88
|
+
});
|
|
89
|
+
} else if (key === 'userId' && value) {
|
|
90
|
+
query.andWhere(`${this.entityName}.userId = :userId`, {
|
|
91
|
+
userId: value
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
query,
|
|
97
|
+
isRaw: false
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
async getExtraManipulateQuery(query, filterDto, user) {
|
|
101
|
+
const result = await super.getExtraManipulateQuery(query, filterDto, user);
|
|
102
|
+
if (user?.id) {
|
|
103
|
+
query.andWhere(`${this.entityName}.userId = :currentUserId`, {
|
|
104
|
+
currentUserId: user.id
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
(0, _utils.applyCompanyFilter)(query, {
|
|
108
|
+
isCompanyFeatureEnabled: this.notificationConfig.isCompanyFeatureEnabled(),
|
|
109
|
+
entityAlias: this.entityName
|
|
110
|
+
}, user);
|
|
111
|
+
if (!filterDto?.sort || Object.keys(filterDto.sort).length === 0) {
|
|
112
|
+
query.orderBy(`${this.entityName}.createdAt`, 'DESC');
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
async afterInsertOperation(entities, _user, _qr) {
|
|
117
|
+
for (const entity of entities){
|
|
118
|
+
const ext = entity;
|
|
119
|
+
this.emitToUserInCompanyIfRealtime(entity.userId, ext.companyId, 'notification:new', this.toPayload(entity));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async markAsRead(id, user) {
|
|
123
|
+
await this.ensureRepositoryInitialized();
|
|
124
|
+
const notification = await this.repository.findOne({
|
|
125
|
+
where: {
|
|
126
|
+
id,
|
|
127
|
+
userId: user.id
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
if (!notification) {
|
|
131
|
+
throw new _common.NotFoundException('Notification not found');
|
|
132
|
+
}
|
|
133
|
+
notification.isRead = true;
|
|
134
|
+
notification.readAt = new Date();
|
|
135
|
+
await this.repository.save(notification);
|
|
136
|
+
await Promise.all([
|
|
137
|
+
this.clearCacheForAll(),
|
|
138
|
+
this.clearCacheForId([
|
|
139
|
+
notification
|
|
140
|
+
])
|
|
141
|
+
]);
|
|
142
|
+
// Emit to user's sockets in the same company context
|
|
143
|
+
const ext = notification;
|
|
144
|
+
this.emitToUserInCompanyIfRealtime(user.id, ext.companyId ?? user.companyId, 'notification:read', {
|
|
145
|
+
id
|
|
146
|
+
});
|
|
147
|
+
return notification;
|
|
148
|
+
}
|
|
149
|
+
async markAllAsRead(user) {
|
|
150
|
+
await this.ensureRepositoryInitialized();
|
|
151
|
+
const result = await this.repository.update({
|
|
152
|
+
userId: user.id,
|
|
153
|
+
isRead: false
|
|
154
|
+
}, {
|
|
155
|
+
isRead: true,
|
|
156
|
+
readAt: new Date()
|
|
157
|
+
});
|
|
158
|
+
await this.clearCacheForAll();
|
|
159
|
+
// Emit to user's sockets in the current company context
|
|
160
|
+
this.emitToUserInCompanyIfRealtime(user.id, user.companyId, 'notification:read-all', {});
|
|
161
|
+
return result.affected ?? 0;
|
|
162
|
+
}
|
|
163
|
+
async getUnreadCount(user) {
|
|
164
|
+
await this.ensureRepositoryInitialized();
|
|
165
|
+
return this.repository.count({
|
|
166
|
+
where: {
|
|
167
|
+
userId: user.id,
|
|
168
|
+
isRead: false
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
toPayload(entity) {
|
|
173
|
+
return {
|
|
174
|
+
id: entity.id,
|
|
175
|
+
type: entity.type,
|
|
176
|
+
title: entity.title,
|
|
177
|
+
message: entity.message,
|
|
178
|
+
data: entity.data,
|
|
179
|
+
createdAt: entity.createdAt
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Emit to user's sockets within a specific company context.
|
|
184
|
+
* If company feature is enabled and companyId is provided, only sockets
|
|
185
|
+
* connected with that company will receive the event.
|
|
186
|
+
*/ emitToUserInCompanyIfRealtime(userId, companyId, event, payload) {
|
|
187
|
+
if (!this.notificationConfig.isRealtimeEnabled() || !this.gateway) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (this.notificationConfig.isCompanyFeatureEnabled() && companyId) {
|
|
191
|
+
// Company feature enabled - emit only to sockets in matching company context
|
|
192
|
+
this.gateway.emitToUserInCompany(userId, companyId, event, payload);
|
|
193
|
+
} else {
|
|
194
|
+
// No company feature or no companyId - emit to all user's sockets
|
|
195
|
+
this.gateway.emitToUser(userId, event, payload);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
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;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
NotificationService = _ts_decorate([
|
|
203
|
+
(0, _common.Injectable)({
|
|
204
|
+
scope: _common.Scope.REQUEST
|
|
205
|
+
}),
|
|
206
|
+
_ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
|
|
207
|
+
_ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
|
|
208
|
+
_ts_param(2, (0, _common.Inject)(_notificationconfigservice.NotificationConfigService)),
|
|
209
|
+
_ts_param(3, (0, _common.Inject)(_notificationdatasourceprovider.NotificationDataSourceProvider)),
|
|
210
|
+
_ts_param(4, (0, _common.Optional)()),
|
|
211
|
+
_ts_param(4, (0, _common.Inject)(_gateways.NotificationGateway)),
|
|
212
|
+
_ts_metadata("design:type", Function),
|
|
213
|
+
_ts_metadata("design:paramtypes", [
|
|
214
|
+
typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
|
|
215
|
+
typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
|
|
216
|
+
typeof _notificationconfigservice.NotificationConfigService === "undefined" ? Object : _notificationconfigservice.NotificationConfigService,
|
|
217
|
+
typeof _notificationdatasourceprovider.NotificationDataSourceProvider === "undefined" ? Object : _notificationdatasourceprovider.NotificationDataSourceProvider,
|
|
218
|
+
typeof _gateways.NotificationGateway === "undefined" ? Object : _gateways.NotificationGateway
|
|
219
|
+
])
|
|
220
|
+
], NotificationService);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './notification.constants';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const NOTIFICATION_MODULE_OPTIONS = "NOTIFICATION_MODULE_OPTIONS";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './notification.controller';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { BulkResponseDto, MessageResponseDto, SingleResponseDto } from '@flusys/nestjs-shared/dtos';
|
|
2
|
+
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
3
|
+
import { CreateNotificationDto, MarkReadDto, NotificationResponseDto, SendBulkNotificationDto, SendNotificationDto, UnreadCountResponseDto, UpdateNotificationDto } from '../dtos';
|
|
4
|
+
import { NotificationHelperService } from '../services/notification-helper.service';
|
|
5
|
+
import { NotificationService } from '../services/notification.service';
|
|
6
|
+
declare const NotificationController_base: abstract new (service: NotificationService) => {
|
|
7
|
+
service: NotificationService;
|
|
8
|
+
insert(addDto: CreateNotificationDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<NotificationResponseDto>>;
|
|
9
|
+
insertMany(addDto: CreateNotificationDto[], user: ILoggedUserInfo | null): Promise<BulkResponseDto<NotificationResponseDto>>;
|
|
10
|
+
getById(id: string, body: import("@flusys/nestjs-shared/dtos").GetByIdBodyDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<NotificationResponseDto>>;
|
|
11
|
+
update(updateDto: UpdateNotificationDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<NotificationResponseDto>>;
|
|
12
|
+
updateMany(updateDtos: UpdateNotificationDto[], user: ILoggedUserInfo | null): Promise<BulkResponseDto<NotificationResponseDto>>;
|
|
13
|
+
getAll(filterAndPaginationDto: import("@flusys/nestjs-shared/dtos").FilterAndPaginationDto, user: ILoggedUserInfo | null, search?: string): Promise<import("@flusys/nestjs-shared/dtos").ListResponseDto<NotificationResponseDto>>;
|
|
14
|
+
delete(deleteDto: import("@flusys/nestjs-shared/dtos").DeleteDto, user: ILoggedUserInfo | null): Promise<MessageResponseDto>;
|
|
15
|
+
};
|
|
16
|
+
export declare class NotificationController extends NotificationController_base {
|
|
17
|
+
service: NotificationService;
|
|
18
|
+
private readonly notificationHelper;
|
|
19
|
+
constructor(service: NotificationService, notificationHelper: NotificationHelperService);
|
|
20
|
+
markAsRead(dto: MarkReadDto, user: ILoggedUserInfo): Promise<SingleResponseDto<NotificationResponseDto>>;
|
|
21
|
+
markAllAsRead(user: ILoggedUserInfo): Promise<MessageResponseDto>;
|
|
22
|
+
getUnreadCount(user: ILoggedUserInfo): Promise<SingleResponseDto<UnreadCountResponseDto>>;
|
|
23
|
+
sendNotification(dto: SendNotificationDto): Promise<SingleResponseDto<NotificationResponseDto>>;
|
|
24
|
+
sendBulkNotification(dto: SendBulkNotificationDto): Promise<BulkResponseDto<NotificationResponseDto>>;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
package/docs/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './notification-swagger.config';
|
package/dtos/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './notification.dto';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { NotificationType } from '@flusys/nestjs-shared/enums';
|
|
2
|
+
declare class NotificationContentDto {
|
|
3
|
+
title: string;
|
|
4
|
+
message?: string;
|
|
5
|
+
type?: NotificationType;
|
|
6
|
+
data?: Record<string, unknown>;
|
|
7
|
+
companyId?: string;
|
|
8
|
+
}
|
|
9
|
+
declare class UserIdDto {
|
|
10
|
+
userId: string;
|
|
11
|
+
}
|
|
12
|
+
declare class UserIdsDto {
|
|
13
|
+
userIds: string[];
|
|
14
|
+
}
|
|
15
|
+
declare const CreateNotificationDto_base: import("@nestjs/common").Type<NotificationContentDto & UserIdDto>;
|
|
16
|
+
export declare class CreateNotificationDto extends CreateNotificationDto_base {
|
|
17
|
+
}
|
|
18
|
+
declare const UpdateNotificationDto_base: import("@nestjs/common").Type<Partial<Omit<CreateNotificationDto, "userId">>>;
|
|
19
|
+
export declare class UpdateNotificationDto extends UpdateNotificationDto_base {
|
|
20
|
+
id: string;
|
|
21
|
+
}
|
|
22
|
+
export declare class MarkReadDto {
|
|
23
|
+
id: string;
|
|
24
|
+
}
|
|
25
|
+
export declare class NotificationResponseDto {
|
|
26
|
+
id: string;
|
|
27
|
+
userId: string;
|
|
28
|
+
type: string;
|
|
29
|
+
title: string;
|
|
30
|
+
message?: string | null;
|
|
31
|
+
data?: Record<string, unknown> | null;
|
|
32
|
+
isRead: boolean;
|
|
33
|
+
readAt?: Date | null;
|
|
34
|
+
companyId?: string | null;
|
|
35
|
+
createdAt: Date;
|
|
36
|
+
updatedAt: Date;
|
|
37
|
+
}
|
|
38
|
+
export declare class UnreadCountResponseDto {
|
|
39
|
+
count: number;
|
|
40
|
+
}
|
|
41
|
+
declare const SendNotificationDto_base: import("@nestjs/common").Type<NotificationContentDto & UserIdDto>;
|
|
42
|
+
export declare class SendNotificationDto extends SendNotificationDto_base {
|
|
43
|
+
}
|
|
44
|
+
declare const SendBulkNotificationDto_base: import("@nestjs/common").Type<NotificationContentDto & UserIdsDto>;
|
|
45
|
+
export declare class SendBulkNotificationDto extends SendBulkNotificationDto_base {
|
|
46
|
+
}
|
|
47
|
+
export {};
|