@sync-in/server 1.4.0 → 1.5.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/CHANGELOG.md +26 -0
- package/README.md +2 -1
- package/package.json +5 -5
- package/server/applications/comments/comments.controller.spec.js +103 -4
- package/server/applications/comments/comments.controller.spec.js.map +1 -1
- package/server/applications/comments/services/comments-manager.service.spec.js +409 -9
- package/server/applications/comments/services/comments-manager.service.spec.js.map +1 -1
- package/server/applications/files/adapters/files-indexer-mysql.service.spec.js +333 -0
- package/server/applications/files/adapters/files-indexer-mysql.service.spec.js.map +1 -0
- package/server/applications/files/constants/routes.js +6 -1
- package/server/applications/files/constants/routes.js.map +1 -1
- package/server/applications/files/files-only-office.controller.js +11 -0
- package/server/applications/files/files-only-office.controller.js.map +1 -1
- package/server/applications/files/files-only-office.controller.spec.js +97 -3
- package/server/applications/files/files-only-office.controller.spec.js.map +1 -1
- package/server/applications/files/files-tasks.controller.spec.js +91 -1
- package/server/applications/files/files-tasks.controller.spec.js.map +1 -1
- package/server/applications/files/files.controller.spec.js +268 -46
- package/server/applications/files/files.controller.spec.js.map +1 -1
- package/server/applications/files/guards/files-only-office.guard.spec.js +77 -1
- package/server/applications/files/guards/files-only-office.guard.spec.js.map +1 -1
- package/server/applications/files/services/files-only-office-manager.service.js +5 -0
- package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
- package/server/applications/links/links.controller.spec.js +91 -58
- package/server/applications/links/links.controller.spec.js.map +1 -1
- package/server/applications/links/services/links-manager.service.js +4 -6
- package/server/applications/links/services/links-manager.service.js.map +1 -1
- package/server/applications/links/services/links-manager.service.spec.js +378 -14
- package/server/applications/links/services/links-manager.service.spec.js.map +1 -1
- package/server/applications/links/services/links-queries.service.js +1 -1
- package/server/applications/links/services/links-queries.service.js.map +1 -1
- package/server/applications/notifications/notifications.controller.spec.js +56 -1
- package/server/applications/notifications/notifications.controller.spec.js.map +1 -1
- package/server/applications/notifications/services/notifications-manager.service.spec.js +461 -5
- package/server/applications/notifications/services/notifications-manager.service.spec.js.map +1 -1
- package/server/applications/shares/services/shares-manager.service.spec.js +590 -14
- package/server/applications/shares/services/shares-manager.service.spec.js.map +1 -1
- package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js +120 -0
- package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js.map +1 -0
- package/server/applications/sync/services/sync-clients-manager.service.spec.js +548 -8
- package/server/applications/sync/services/sync-clients-manager.service.spec.js.map +1 -1
- package/server/applications/sync/services/sync-manager.service.spec.js +837 -5
- package/server/applications/sync/services/sync-manager.service.spec.js.map +1 -1
- package/server/applications/sync/services/sync-paths-manager.service.spec.js +900 -7
- package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.js +22 -24
- package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.spec.js +763 -17
- package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/users-manager.service.js +1 -1
- package/server/applications/users/services/users-manager.service.js.map +1 -1
- package/server/applications/users/services/users-manager.service.spec.js +938 -49
- package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
- package/server/applications/webdav/decorators/if-header.decorator.js +4 -1
- package/server/applications/webdav/decorators/if-header.decorator.js.map +1 -1
- package/server/applications/webdav/filters/webdav.filter.spec.js +77 -0
- package/server/applications/webdav/filters/webdav.filter.spec.js.map +1 -0
- package/server/applications/webdav/guards/webdav-protocol.guard.js +3 -7
- package/server/applications/webdav/guards/webdav-protocol.guard.js.map +1 -1
- package/server/applications/webdav/guards/webdav-protocol.guard.spec.js +580 -0
- package/server/applications/webdav/guards/webdav-protocol.guard.spec.js.map +1 -0
- package/server/applications/webdav/services/webdav-methods.service.spec.js +1582 -3
- package/server/applications/webdav/services/webdav-methods.service.spec.js.map +1 -1
- package/server/applications/webdav/services/webdav-spaces.service.spec.js +390 -2
- package/server/applications/webdav/services/webdav-spaces.service.spec.js.map +1 -1
- package/server/applications/webdav/webdav.controller.js +2 -2
- package/server/applications/webdav/webdav.controller.js.map +1 -1
- package/server/authentication/guards/auth-basic.guard.js.map +1 -1
- package/server/authentication/guards/auth-digest.guard.js +1 -2
- package/server/authentication/guards/auth-digest.guard.js.map +1 -1
- package/server/authentication/guards/auth-local.guard.js.map +1 -1
- package/server/infrastructure/context/interceptors/context.interceptor.spec.js +135 -0
- package/server/infrastructure/context/interceptors/context.interceptor.spec.js.map +1 -0
- package/static/3rdpartylicenses.txt +26 -26
- package/static/assets/pdfjs/build/pdf.mjs +1177 -255
- package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
- package/static/assets/pdfjs/build/pdf.sandbox.mjs +25 -2
- package/static/assets/pdfjs/build/pdf.sandbox.mjs.map +1 -1
- package/static/assets/pdfjs/build/pdf.worker.mjs +140 -16
- package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
- package/static/assets/pdfjs/version +1 -1
- package/static/assets/pdfjs/web/debugger.css +31 -0
- package/static/assets/pdfjs/web/debugger.mjs +144 -2
- package/static/assets/pdfjs/web/images/comment-editButton.svg +6 -1
- package/static/assets/pdfjs/web/locale/ach/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/af/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/an/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ast/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/az/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/be/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/bg/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/bn/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/bo/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/br/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/brx/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/bs/viewer.ftl +22 -0
- package/static/assets/pdfjs/web/locale/ca/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/cak/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/ckb/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/cs/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/cy/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/da/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/de/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/el/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +25 -0
- package/static/assets/pdfjs/web/locale/eo/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -6
- package/static/assets/pdfjs/web/locale/et/viewer.ftl +0 -57
- package/static/assets/pdfjs/web/locale/fa/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/ff/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/fi/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/fr/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/ga-IE/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/gd/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/gl/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/gn/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/gu-IN/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/he/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hi-IN/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hu/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +0 -49
- package/static/assets/pdfjs/web/locale/hye/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/ia/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/is/viewer.ftl +0 -3
- package/static/assets/pdfjs/web/locale/it/viewer.ftl +31 -0
- package/static/assets/pdfjs/web/locale/ja/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/ka/viewer.ftl +48 -10
- package/static/assets/pdfjs/web/locale/kab/viewer.ftl +5 -0
- package/static/assets/pdfjs/web/locale/kk/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/km/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/kn/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/ko/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/lij/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/lo/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/lt/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/ltg/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/lv/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/meh/viewer.ftl +0 -75
- package/static/assets/pdfjs/web/locale/mk/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ml/viewer.ftl +0 -3
- package/static/assets/pdfjs/web/locale/mr/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ms/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/my/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +44 -6
- package/static/assets/pdfjs/web/locale/ne-NP/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/nl/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +45 -1
- package/static/assets/pdfjs/web/locale/oc/viewer.ftl +0 -31
- package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/pl/viewer.ftl +39 -1
- package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/ro/viewer.ftl +355 -1
- package/static/assets/pdfjs/web/locale/ru/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/sat/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/sc/viewer.ftl +0 -38
- package/static/assets/pdfjs/web/locale/scn/viewer.ftl +0 -92
- package/static/assets/pdfjs/web/locale/sco/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/si/viewer.ftl +0 -51
- package/static/assets/pdfjs/web/locale/sk/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/skr/viewer.ftl +0 -27
- package/static/assets/pdfjs/web/locale/sl/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/son/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/sr/viewer.ftl +0 -33
- package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/szl/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ta/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/te/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/tg/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/tl/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/tr/viewer.ftl +40 -2
- package/static/assets/pdfjs/web/locale/trs/viewer.ftl +0 -72
- package/static/assets/pdfjs/web/locale/ur/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/uz/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/vi/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/wo/viewer.ftl +0 -77
- package/static/assets/pdfjs/web/locale/xh/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/viewer.css +649 -120
- package/static/assets/pdfjs/web/viewer.html +19 -0
- package/static/assets/pdfjs/web/viewer.mjs +489 -38
- package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
- package/static/chunk-22EANI6R.js +1 -0
- package/static/{chunk-N2LYWNTC.js → chunk-2456KVFZ.js} +1 -1
- package/static/{chunk-YCINY2YI.js → chunk-2LVCLKCK.js} +1 -1
- package/static/{chunk-5YKWZT33.js → chunk-2V5S7DWD.js} +1 -1
- package/static/{chunk-3GC2BQZD.js → chunk-44YDXGNZ.js} +1 -1
- package/static/{chunk-W3QXNDI5.js → chunk-4LSJLWYV.js} +1 -1
- package/static/{chunk-T55FAU2O.js → chunk-4UT5VH7R.js} +1 -1
- package/static/{chunk-VMQMD36Z.js → chunk-5GOMMRRE.js} +1 -1
- package/static/{chunk-TXPODW5Q.js → chunk-5J4VRDKB.js} +1 -1
- package/static/{chunk-FQ4AFNGE.js → chunk-6PVKNZ7Q.js} +1 -1
- package/static/{chunk-XE5YHU5J.js → chunk-BIUNUYZ5.js} +1 -1
- package/static/{chunk-X43VWRFP.js → chunk-DFQKHCDR.js} +1 -1
- package/static/{chunk-TDQAEVZN.js → chunk-EE2TDTY4.js} +1 -1
- package/static/{chunk-MOVWEZ7J.js → chunk-ESNDJ5T6.js} +1 -1
- package/static/{chunk-TCFKH6K6.js → chunk-GDKKLLEU.js} +1 -1
- package/static/{chunk-VHYIXL7R.js → chunk-GSR2MCQG.js} +1 -1
- package/static/{chunk-LJIGRUEF.js → chunk-HR7KS5BR.js} +1 -1
- package/static/chunk-HW2H3ISM.js +559 -0
- package/static/{chunk-HZA7R43P.js → chunk-IMB3C547.js} +1 -1
- package/static/{chunk-B2Y2RNFP.js → chunk-J4ALHUDX.js} +1 -1
- package/static/{chunk-PF4K7MVG.js → chunk-KP6LSQTK.js} +1 -1
- package/static/{chunk-C23BPTJZ.js → chunk-LUZCOHFN.js} +1 -1
- package/static/{chunk-GBCYYDCI.js → chunk-MHSCCXVL.js} +1 -1
- package/static/{chunk-PY3BGNJN.js → chunk-OMRQYBXV.js} +1 -1
- package/static/chunk-P7CTJ5BG.js +27 -0
- package/static/{chunk-Y2CDUS4J.js → chunk-P7PX67IR.js} +4 -4
- package/static/{chunk-VMUOUCEI.js → chunk-PPO7DBVO.js} +1 -1
- package/static/{chunk-TTQ37MUV.js → chunk-RSS6GYNE.js} +1 -1
- package/static/{chunk-WWIC7UW3.js → chunk-SLGGINMR.js} +1 -1
- package/static/{chunk-KZQCFEPT.js → chunk-UHD5XD3G.js} +1 -1
- package/static/{chunk-TNW2CGK6.js → chunk-UPYYAJCJ.js} +1 -1
- package/static/{chunk-6F55D74O.js → chunk-VHYPQ3D4.js} +1 -1
- package/static/{chunk-DGVNNICG.js → chunk-YQSDS6BO.js} +1 -1
- package/static/{chunk-MTRNPGS4.js → chunk-ZC5NIT55.js} +1 -1
- package/static/index.html +1 -1
- package/static/main-FYD34UEC.js +7 -0
- package/static/chunk-RSNLYAN6.js +0 -560
- package/static/chunk-WHMS3PJ3.js +0 -24
- package/static/chunk-ZZ3LHYOY.js +0 -1
- package/static/main-7LDKYVXO.js +0 -10
|
@@ -11,6 +11,15 @@ const _notificationscontroller = require("./notifications.controller");
|
|
|
11
11
|
const _notificationsmanagerservice = require("./services/notifications-manager.service");
|
|
12
12
|
describe(_notificationscontroller.NotificationsController.name, ()=>{
|
|
13
13
|
let controller;
|
|
14
|
+
const notificationsManagerMock = {
|
|
15
|
+
list: jest.fn(),
|
|
16
|
+
wasRead: jest.fn(),
|
|
17
|
+
delete: jest.fn()
|
|
18
|
+
};
|
|
19
|
+
const user = {
|
|
20
|
+
id: 1,
|
|
21
|
+
login: 'john.doe'
|
|
22
|
+
};
|
|
14
23
|
beforeAll(async ()=>{
|
|
15
24
|
const module = await _testing.Test.createTestingModule({
|
|
16
25
|
controllers: [
|
|
@@ -19,15 +28,61 @@ describe(_notificationscontroller.NotificationsController.name, ()=>{
|
|
|
19
28
|
providers: [
|
|
20
29
|
{
|
|
21
30
|
provide: _notificationsmanagerservice.NotificationsManager,
|
|
22
|
-
useValue:
|
|
31
|
+
useValue: notificationsManagerMock
|
|
23
32
|
}
|
|
24
33
|
]
|
|
25
34
|
}).compile();
|
|
26
35
|
controller = module.get(_notificationscontroller.NotificationsController);
|
|
27
36
|
});
|
|
37
|
+
beforeEach(()=>{
|
|
38
|
+
jest.clearAllMocks();
|
|
39
|
+
});
|
|
28
40
|
it('should be defined', ()=>{
|
|
29
41
|
expect(controller).toBeDefined();
|
|
30
42
|
});
|
|
43
|
+
it('list() should return notifications and call manager.list with user', async ()=>{
|
|
44
|
+
const notifications = [
|
|
45
|
+
{
|
|
46
|
+
id: 10
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: 11
|
|
50
|
+
}
|
|
51
|
+
];
|
|
52
|
+
notificationsManagerMock.list.mockResolvedValueOnce(notifications);
|
|
53
|
+
await expect(controller.list(user)).resolves.toBe(notifications);
|
|
54
|
+
expect(notificationsManagerMock.list).toHaveBeenCalledTimes(1);
|
|
55
|
+
expect(notificationsManagerMock.list).toHaveBeenCalledWith(user);
|
|
56
|
+
});
|
|
57
|
+
it('listUnread() should return unread notifications and call manager.list with unread=true', async ()=>{
|
|
58
|
+
const notifications = [
|
|
59
|
+
{
|
|
60
|
+
id: 12
|
|
61
|
+
}
|
|
62
|
+
];
|
|
63
|
+
notificationsManagerMock.list.mockResolvedValueOnce(notifications);
|
|
64
|
+
await expect(controller.listUnread(user)).resolves.toBe(notifications);
|
|
65
|
+
expect(notificationsManagerMock.list).toHaveBeenCalledTimes(1);
|
|
66
|
+
expect(notificationsManagerMock.list).toHaveBeenCalledWith(user, true);
|
|
67
|
+
});
|
|
68
|
+
it('wasRead() should delegate to manager.wasRead with user and id', ()=>{
|
|
69
|
+
notificationsManagerMock.wasRead.mockReturnValueOnce(undefined);
|
|
70
|
+
controller.wasRead(user, 42);
|
|
71
|
+
expect(notificationsManagerMock.wasRead).toHaveBeenCalledTimes(1);
|
|
72
|
+
expect(notificationsManagerMock.wasRead).toHaveBeenCalledWith(user, 42);
|
|
73
|
+
});
|
|
74
|
+
it('deleteAll() should call manager.delete with user only', async ()=>{
|
|
75
|
+
notificationsManagerMock.delete.mockResolvedValueOnce(undefined);
|
|
76
|
+
await expect(controller.deleteAll(user)).resolves.toBeUndefined();
|
|
77
|
+
expect(notificationsManagerMock.delete).toHaveBeenCalledTimes(1);
|
|
78
|
+
expect(notificationsManagerMock.delete).toHaveBeenCalledWith(user);
|
|
79
|
+
});
|
|
80
|
+
it('delete(:id) should call manager.delete with user and id', async ()=>{
|
|
81
|
+
notificationsManagerMock.delete.mockResolvedValueOnce(undefined);
|
|
82
|
+
await expect(controller.delete(user, 7)).resolves.toBeUndefined();
|
|
83
|
+
expect(notificationsManagerMock.delete).toHaveBeenCalledTimes(1);
|
|
84
|
+
expect(notificationsManagerMock.delete).toHaveBeenCalledWith(user, 7);
|
|
85
|
+
});
|
|
31
86
|
});
|
|
32
87
|
|
|
33
88
|
//# sourceMappingURL=notifications.controller.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../backend/src/applications/notifications/notifications.controller.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { NotificationsController } from './notifications.controller'\nimport { NotificationsManager } from './services/notifications-manager.service'\n\ndescribe(NotificationsController.name, () => {\n let controller: NotificationsController\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n controllers: [NotificationsController],\n providers: [{ provide: NotificationsManager, useValue:
|
|
1
|
+
{"version":3,"sources":["../../../../backend/src/applications/notifications/notifications.controller.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { NotificationsController } from './notifications.controller'\nimport { NotificationsManager } from './services/notifications-manager.service'\n\ndescribe(NotificationsController.name, () => {\n let controller: NotificationsController\n const notificationsManagerMock: jest.Mocked<NotificationsManager> = {\n list: jest.fn(),\n wasRead: jest.fn(),\n delete: jest.fn()\n } as unknown as jest.Mocked<NotificationsManager>\n\n const user = { id: 1, login: 'john.doe' } as any\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n controllers: [NotificationsController],\n providers: [{ provide: NotificationsManager, useValue: notificationsManagerMock }]\n }).compile()\n\n controller = module.get<NotificationsController>(NotificationsController)\n })\n\n beforeEach(() => {\n jest.clearAllMocks()\n })\n\n it('should be defined', () => {\n expect(controller).toBeDefined()\n })\n\n it('list() should return notifications and call manager.list with user', async () => {\n const notifications = [{ id: 10 }, { id: 11 }] as any\n notificationsManagerMock.list.mockResolvedValueOnce(notifications)\n\n await expect(controller.list(user)).resolves.toBe(notifications)\n expect(notificationsManagerMock.list).toHaveBeenCalledTimes(1)\n expect(notificationsManagerMock.list).toHaveBeenCalledWith(user)\n })\n\n it('listUnread() should return unread notifications and call manager.list with unread=true', async () => {\n const notifications = [{ id: 12 }] as any\n notificationsManagerMock.list.mockResolvedValueOnce(notifications)\n\n await expect(controller.listUnread(user)).resolves.toBe(notifications)\n expect(notificationsManagerMock.list).toHaveBeenCalledTimes(1)\n expect(notificationsManagerMock.list).toHaveBeenCalledWith(user, true)\n })\n\n it('wasRead() should delegate to manager.wasRead with user and id', () => {\n notificationsManagerMock.wasRead.mockReturnValueOnce(undefined as unknown as void)\n\n controller.wasRead(user, 42)\n expect(notificationsManagerMock.wasRead).toHaveBeenCalledTimes(1)\n expect(notificationsManagerMock.wasRead).toHaveBeenCalledWith(user, 42)\n })\n\n it('deleteAll() should call manager.delete with user only', async () => {\n notificationsManagerMock.delete.mockResolvedValueOnce(undefined)\n\n await expect(controller.deleteAll(user)).resolves.toBeUndefined()\n expect(notificationsManagerMock.delete).toHaveBeenCalledTimes(1)\n expect(notificationsManagerMock.delete).toHaveBeenCalledWith(user)\n })\n\n it('delete(:id) should call manager.delete with user and id', async () => {\n notificationsManagerMock.delete.mockResolvedValueOnce(undefined)\n\n await expect(controller.delete(user, 7)).resolves.toBeUndefined()\n expect(notificationsManagerMock.delete).toHaveBeenCalledTimes(1)\n expect(notificationsManagerMock.delete).toHaveBeenCalledWith(user, 7)\n })\n})\n"],"names":["describe","NotificationsController","name","controller","notificationsManagerMock","list","jest","fn","wasRead","delete","user","id","login","beforeAll","module","Test","createTestingModule","controllers","providers","provide","NotificationsManager","useValue","compile","get","beforeEach","clearAllMocks","it","expect","toBeDefined","notifications","mockResolvedValueOnce","resolves","toBe","toHaveBeenCalledTimes","toHaveBeenCalledWith","listUnread","mockReturnValueOnce","undefined","deleteAll","toBeUndefined"],"mappings":"AAAA;;;;CAIC;;;;yBAEmC;yCACI;6CACH;AAErCA,SAASC,gDAAuB,CAACC,IAAI,EAAE;IACrC,IAAIC;IACJ,MAAMC,2BAA8D;QAClEC,MAAMC,KAAKC,EAAE;QACbC,SAASF,KAAKC,EAAE;QAChBE,QAAQH,KAAKC,EAAE;IACjB;IAEA,MAAMG,OAAO;QAAEC,IAAI;QAAGC,OAAO;IAAW;IAExCC,UAAU;QACR,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,aAAa;gBAAChB,gDAAuB;aAAC;YACtCiB,WAAW;gBAAC;oBAAEC,SAASC,iDAAoB;oBAAEC,UAAUjB;gBAAyB;aAAE;QACpF,GAAGkB,OAAO;QAEVnB,aAAaW,OAAOS,GAAG,CAA0BtB,gDAAuB;IAC1E;IAEAuB,WAAW;QACTlB,KAAKmB,aAAa;IACpB;IAEAC,GAAG,qBAAqB;QACtBC,OAAOxB,YAAYyB,WAAW;IAChC;IAEAF,GAAG,sEAAsE;QACvE,MAAMG,gBAAgB;YAAC;gBAAElB,IAAI;YAAG;YAAG;gBAAEA,IAAI;YAAG;SAAE;QAC9CP,yBAAyBC,IAAI,CAACyB,qBAAqB,CAACD;QAEpD,MAAMF,OAAOxB,WAAWE,IAAI,CAACK,OAAOqB,QAAQ,CAACC,IAAI,CAACH;QAClDF,OAAOvB,yBAAyBC,IAAI,EAAE4B,qBAAqB,CAAC;QAC5DN,OAAOvB,yBAAyBC,IAAI,EAAE6B,oBAAoB,CAACxB;IAC7D;IAEAgB,GAAG,0FAA0F;QAC3F,MAAMG,gBAAgB;YAAC;gBAAElB,IAAI;YAAG;SAAE;QAClCP,yBAAyBC,IAAI,CAACyB,qBAAqB,CAACD;QAEpD,MAAMF,OAAOxB,WAAWgC,UAAU,CAACzB,OAAOqB,QAAQ,CAACC,IAAI,CAACH;QACxDF,OAAOvB,yBAAyBC,IAAI,EAAE4B,qBAAqB,CAAC;QAC5DN,OAAOvB,yBAAyBC,IAAI,EAAE6B,oBAAoB,CAACxB,MAAM;IACnE;IAEAgB,GAAG,iEAAiE;QAClEtB,yBAAyBI,OAAO,CAAC4B,mBAAmB,CAACC;QAErDlC,WAAWK,OAAO,CAACE,MAAM;QACzBiB,OAAOvB,yBAAyBI,OAAO,EAAEyB,qBAAqB,CAAC;QAC/DN,OAAOvB,yBAAyBI,OAAO,EAAE0B,oBAAoB,CAACxB,MAAM;IACtE;IAEAgB,GAAG,yDAAyD;QAC1DtB,yBAAyBK,MAAM,CAACqB,qBAAqB,CAACO;QAEtD,MAAMV,OAAOxB,WAAWmC,SAAS,CAAC5B,OAAOqB,QAAQ,CAACQ,aAAa;QAC/DZ,OAAOvB,yBAAyBK,MAAM,EAAEwB,qBAAqB,CAAC;QAC9DN,OAAOvB,yBAAyBK,MAAM,EAAEyB,oBAAoB,CAACxB;IAC/D;IAEAgB,GAAG,2DAA2D;QAC5DtB,yBAAyBK,MAAM,CAACqB,qBAAqB,CAACO;QAEtD,MAAMV,OAAOxB,WAAWM,MAAM,CAACC,MAAM,IAAIqB,QAAQ,CAACQ,aAAa;QAC/DZ,OAAOvB,yBAAyBK,MAAM,EAAEwB,qBAAqB,CAAC;QAC9DN,OAAOvB,yBAAyBK,MAAM,EAAEyB,oBAAoB,CAACxB,MAAM;IACrE;AACF"}
|
|
@@ -8,31 +8,131 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
8
8
|
});
|
|
9
9
|
const _testing = require("@nestjs/testing");
|
|
10
10
|
const _mailerservice = require("../../../infrastructure/mailer/mailer.service");
|
|
11
|
+
const _user = require("../../users/constants/user");
|
|
11
12
|
const _usersmanagerservice = require("../../users/services/users-manager.service");
|
|
13
|
+
const _notifications = require("../constants/notifications");
|
|
14
|
+
const _websocket = require("../constants/websocket");
|
|
15
|
+
const _models = /*#__PURE__*/ _interop_require_wildcard(require("../mails/models"));
|
|
12
16
|
const _notificationsgateway = require("../notifications.gateway");
|
|
13
17
|
const _notificationsmanagerservice = require("./notifications-manager.service");
|
|
14
18
|
const _notificationsqueriesservice = require("./notifications-queries.service");
|
|
19
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
20
|
+
if (typeof WeakMap !== "function") return null;
|
|
21
|
+
var cacheBabelInterop = new WeakMap();
|
|
22
|
+
var cacheNodeInterop = new WeakMap();
|
|
23
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
24
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
25
|
+
})(nodeInterop);
|
|
26
|
+
}
|
|
27
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
28
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
29
|
+
return obj;
|
|
30
|
+
}
|
|
31
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
32
|
+
return {
|
|
33
|
+
default: obj
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
37
|
+
if (cache && cache.has(obj)) {
|
|
38
|
+
return cache.get(obj);
|
|
39
|
+
}
|
|
40
|
+
var newObj = {
|
|
41
|
+
__proto__: null
|
|
42
|
+
};
|
|
43
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
44
|
+
for(var key in obj){
|
|
45
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
46
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
47
|
+
if (desc && (desc.get || desc.set)) {
|
|
48
|
+
Object.defineProperty(newObj, key, desc);
|
|
49
|
+
} else {
|
|
50
|
+
newObj[key] = obj[key];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
newObj.default = obj;
|
|
55
|
+
if (cache) {
|
|
56
|
+
cache.set(obj, newObj);
|
|
57
|
+
}
|
|
58
|
+
return newObj;
|
|
59
|
+
}
|
|
60
|
+
// Compact mock for mail generators
|
|
61
|
+
jest.mock('../mails/models', ()=>({
|
|
62
|
+
commentMail: jest.fn(()=>[
|
|
63
|
+
'comment title',
|
|
64
|
+
'comment html'
|
|
65
|
+
]),
|
|
66
|
+
spaceMail: jest.fn(()=>[
|
|
67
|
+
'space title',
|
|
68
|
+
'space html'
|
|
69
|
+
]),
|
|
70
|
+
spaceRootMail: jest.fn(()=>[
|
|
71
|
+
'spaceRoot title',
|
|
72
|
+
'spaceRoot html'
|
|
73
|
+
]),
|
|
74
|
+
shareMail: jest.fn(()=>[
|
|
75
|
+
'share title',
|
|
76
|
+
'share html'
|
|
77
|
+
]),
|
|
78
|
+
linkMail: jest.fn(()=>[
|
|
79
|
+
'link title',
|
|
80
|
+
'link html'
|
|
81
|
+
]),
|
|
82
|
+
syncMail: jest.fn(()=>[
|
|
83
|
+
'sync title',
|
|
84
|
+
'sync html'
|
|
85
|
+
])
|
|
86
|
+
}));
|
|
15
87
|
describe(_notificationsmanagerservice.NotificationsManager.name, ()=>{
|
|
16
88
|
let service;
|
|
17
|
-
|
|
89
|
+
const usersManagerMock = {
|
|
90
|
+
getAvatarBase64: jest.fn()
|
|
91
|
+
};
|
|
92
|
+
const mailerMock = {
|
|
93
|
+
available: true,
|
|
94
|
+
sendMails: jest.fn()
|
|
95
|
+
};
|
|
96
|
+
const notificationsQueriesMock = {
|
|
97
|
+
list: jest.fn(),
|
|
98
|
+
usersNotifiedByEmail: jest.fn(),
|
|
99
|
+
create: jest.fn(),
|
|
100
|
+
wasRead: jest.fn(),
|
|
101
|
+
delete: jest.fn()
|
|
102
|
+
};
|
|
103
|
+
const webSocketNotificationsMock = {
|
|
104
|
+
sendMessageToUsers: jest.fn()
|
|
105
|
+
};
|
|
106
|
+
const flushPromises = ()=>new Promise((r)=>setImmediate(r));
|
|
107
|
+
const spyLogger = ()=>jest.spyOn(service.logger, 'error').mockImplementation(()=>undefined);
|
|
108
|
+
beforeEach(async ()=>{
|
|
109
|
+
jest.clearAllMocks();
|
|
110
|
+
mailerMock.available = true;
|
|
111
|
+
mailerMock.sendMails.mockResolvedValue(undefined);
|
|
112
|
+
notificationsQueriesMock.create.mockResolvedValue(undefined);
|
|
113
|
+
notificationsQueriesMock.wasRead.mockResolvedValue(undefined);
|
|
114
|
+
notificationsQueriesMock.delete.mockResolvedValue(undefined);
|
|
115
|
+
notificationsQueriesMock.list.mockResolvedValue([]);
|
|
116
|
+
notificationsQueriesMock.usersNotifiedByEmail.mockResolvedValue([]);
|
|
117
|
+
usersManagerMock.getAvatarBase64.mockResolvedValue('avatar-base64');
|
|
18
118
|
const module = await _testing.Test.createTestingModule({
|
|
19
119
|
providers: [
|
|
20
120
|
_notificationsmanagerservice.NotificationsManager,
|
|
21
121
|
{
|
|
22
122
|
provide: _usersmanagerservice.UsersManager,
|
|
23
|
-
useValue:
|
|
123
|
+
useValue: usersManagerMock
|
|
24
124
|
},
|
|
25
125
|
{
|
|
26
126
|
provide: _mailerservice.Mailer,
|
|
27
|
-
useValue:
|
|
127
|
+
useValue: mailerMock
|
|
28
128
|
},
|
|
29
129
|
{
|
|
30
130
|
provide: _notificationsgateway.WebSocketNotifications,
|
|
31
|
-
useValue:
|
|
131
|
+
useValue: webSocketNotificationsMock
|
|
32
132
|
},
|
|
33
133
|
{
|
|
34
134
|
provide: _notificationsqueriesservice.NotificationsQueries,
|
|
35
|
-
useValue:
|
|
135
|
+
useValue: notificationsQueriesMock
|
|
36
136
|
}
|
|
37
137
|
]
|
|
38
138
|
}).compile();
|
|
@@ -41,6 +141,362 @@ describe(_notificationsmanagerservice.NotificationsManager.name, ()=>{
|
|
|
41
141
|
it('should be defined', ()=>{
|
|
42
142
|
expect(service).toBeDefined();
|
|
43
143
|
});
|
|
144
|
+
describe('list', ()=>{
|
|
145
|
+
it.each`
|
|
146
|
+
userId | onlyUnread | expected
|
|
147
|
+
${42} | ${true} | ${true}
|
|
148
|
+
${1} | ${undefined} | ${false}
|
|
149
|
+
`('should list notifications (userId=$userId, onlyUnread=$onlyUnread)', async ({ userId, onlyUnread, expected })=>{
|
|
150
|
+
const expectedRes = [
|
|
151
|
+
{
|
|
152
|
+
id: userId
|
|
153
|
+
}
|
|
154
|
+
];
|
|
155
|
+
notificationsQueriesMock.list.mockResolvedValueOnce(expectedRes);
|
|
156
|
+
const res = await service.list({
|
|
157
|
+
id: userId
|
|
158
|
+
}, onlyUnread);
|
|
159
|
+
expect(notificationsQueriesMock.list).toHaveBeenCalledWith(userId, expected);
|
|
160
|
+
expect(res).toBe(expectedRes);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
describe('create', ()=>{
|
|
164
|
+
it('stores, sends WS and no email when filtered list empty (object input)', async ()=>{
|
|
165
|
+
const sendEmailSpy = jest.spyOn(service, 'sendEmailNotification').mockResolvedValue(undefined);
|
|
166
|
+
const toUsers = [
|
|
167
|
+
{
|
|
168
|
+
id: 10,
|
|
169
|
+
email: 'u1@test.tld',
|
|
170
|
+
language: 'en',
|
|
171
|
+
notification: _user.USER_NOTIFICATION.APPLICATION
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
id: 11,
|
|
175
|
+
email: 'u2@test.tld',
|
|
176
|
+
language: 'fr',
|
|
177
|
+
notification: _user.USER_NOTIFICATION.APPLICATION
|
|
178
|
+
}
|
|
179
|
+
];
|
|
180
|
+
await service.create(toUsers, {
|
|
181
|
+
app: _notifications.NOTIFICATION_APP.COMMENTS
|
|
182
|
+
}, {
|
|
183
|
+
author: {
|
|
184
|
+
id: 99,
|
|
185
|
+
login: 'john'
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
expect(notificationsQueriesMock.create).toHaveBeenCalledWith(99, [
|
|
189
|
+
10,
|
|
190
|
+
11
|
|
191
|
+
], {
|
|
192
|
+
app: _notifications.NOTIFICATION_APP.COMMENTS
|
|
193
|
+
});
|
|
194
|
+
expect(webSocketNotificationsMock.sendMessageToUsers).toHaveBeenCalledWith([
|
|
195
|
+
10,
|
|
196
|
+
11
|
|
197
|
+
], _websocket.NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check');
|
|
198
|
+
expect(sendEmailSpy).not.toHaveBeenCalled();
|
|
199
|
+
expect(notificationsQueriesMock.usersNotifiedByEmail).not.toHaveBeenCalled();
|
|
200
|
+
});
|
|
201
|
+
it('stores, sends WS and email for ids input', async ()=>{
|
|
202
|
+
const sendEmailSpy = jest.spyOn(service, 'sendEmailNotification').mockResolvedValue(undefined);
|
|
203
|
+
const toUserIds = [
|
|
204
|
+
1,
|
|
205
|
+
2,
|
|
206
|
+
3
|
|
207
|
+
];
|
|
208
|
+
const content = {
|
|
209
|
+
app: _notifications.NOTIFICATION_APP.SHARES
|
|
210
|
+
};
|
|
211
|
+
const emailUsers = [
|
|
212
|
+
{
|
|
213
|
+
id: 1,
|
|
214
|
+
email: 'a@test',
|
|
215
|
+
language: 'en'
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
id: 3,
|
|
219
|
+
email: 'c@test',
|
|
220
|
+
language: 'fr'
|
|
221
|
+
}
|
|
222
|
+
];
|
|
223
|
+
notificationsQueriesMock.usersNotifiedByEmail.mockResolvedValueOnce(emailUsers);
|
|
224
|
+
await service.create(toUserIds, content);
|
|
225
|
+
expect(notificationsQueriesMock.create).toHaveBeenCalledWith(null, toUserIds, content);
|
|
226
|
+
expect(webSocketNotificationsMock.sendMessageToUsers).toHaveBeenCalledWith(toUserIds, _websocket.NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check');
|
|
227
|
+
expect(notificationsQueriesMock.usersNotifiedByEmail).toHaveBeenCalledWith(toUserIds);
|
|
228
|
+
expect(sendEmailSpy).toHaveBeenCalledWith(emailUsers, content, undefined);
|
|
229
|
+
});
|
|
230
|
+
it('does not try email when mailer is unavailable', async ()=>{
|
|
231
|
+
mailerMock.available = false;
|
|
232
|
+
const sendEmailSpy = jest.spyOn(service, 'sendEmailNotification').mockResolvedValue(undefined);
|
|
233
|
+
await service.create([
|
|
234
|
+
7
|
|
235
|
+
], {
|
|
236
|
+
app: _notifications.NOTIFICATION_APP.SYNC
|
|
237
|
+
}, {
|
|
238
|
+
author: {
|
|
239
|
+
id: 12,
|
|
240
|
+
login: 'jane'
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
expect(notificationsQueriesMock.create).toHaveBeenCalledWith(12, [
|
|
244
|
+
7
|
|
245
|
+
], {
|
|
246
|
+
app: _notifications.NOTIFICATION_APP.SYNC
|
|
247
|
+
});
|
|
248
|
+
expect(webSocketNotificationsMock.sendMessageToUsers).toHaveBeenCalledWith([
|
|
249
|
+
7
|
|
250
|
+
], _websocket.NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check');
|
|
251
|
+
expect(notificationsQueriesMock.usersNotifiedByEmail).not.toHaveBeenCalled();
|
|
252
|
+
expect(sendEmailSpy).not.toHaveBeenCalled();
|
|
253
|
+
});
|
|
254
|
+
it('logs error when storeNotification internal try/catch catches create error', async ()=>{
|
|
255
|
+
const loggerSpy = spyLogger();
|
|
256
|
+
notificationsQueriesMock.create.mockRejectedValueOnce(new Error('DB fail'));
|
|
257
|
+
await service.create([
|
|
258
|
+
1
|
|
259
|
+
], {
|
|
260
|
+
app: _notifications.NOTIFICATION_APP.LINKS
|
|
261
|
+
});
|
|
262
|
+
await flushPromises();
|
|
263
|
+
expect(loggerSpy).toHaveBeenCalled();
|
|
264
|
+
expect(loggerSpy.mock.calls[0]?.[0]).toMatch(/create/i);
|
|
265
|
+
});
|
|
266
|
+
it('logs error when storeNotification promise rejects (create catch)', async ()=>{
|
|
267
|
+
const loggerSpy = spyLogger();
|
|
268
|
+
jest.spyOn(service, 'storeNotification').mockRejectedValueOnce(new Error('store reject'));
|
|
269
|
+
await service.create([
|
|
270
|
+
1,
|
|
271
|
+
2
|
|
272
|
+
], {
|
|
273
|
+
app: _notifications.NOTIFICATION_APP.SYNC
|
|
274
|
+
}, {
|
|
275
|
+
author: {
|
|
276
|
+
id: 5,
|
|
277
|
+
login: 'xx'
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
await flushPromises();
|
|
281
|
+
expect(loggerSpy).toHaveBeenCalled();
|
|
282
|
+
expect(loggerSpy.mock.calls[0]?.[0]).toMatch(/create/i);
|
|
283
|
+
});
|
|
284
|
+
it('logs error when sendEmailNotification rejects (create catch)', async ()=>{
|
|
285
|
+
const loggerSpy = spyLogger();
|
|
286
|
+
notificationsQueriesMock.usersNotifiedByEmail.mockResolvedValueOnce([
|
|
287
|
+
{
|
|
288
|
+
id: 1,
|
|
289
|
+
email: 'a@test',
|
|
290
|
+
language: 'en'
|
|
291
|
+
}
|
|
292
|
+
]);
|
|
293
|
+
jest.spyOn(service, 'sendEmailNotification').mockRejectedValueOnce(new Error('email reject'));
|
|
294
|
+
await service.create([
|
|
295
|
+
1
|
|
296
|
+
], {
|
|
297
|
+
app: _notifications.NOTIFICATION_APP.COMMENTS
|
|
298
|
+
});
|
|
299
|
+
await flushPromises();
|
|
300
|
+
expect(loggerSpy).toHaveBeenCalled();
|
|
301
|
+
expect(loggerSpy.mock.calls[0]?.[0]).toMatch(/create/i);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
describe('wasRead', ()=>{
|
|
305
|
+
it('calls queries.wasRead and logs on error', async ()=>{
|
|
306
|
+
service.wasRead({
|
|
307
|
+
id: 5
|
|
308
|
+
}, 123);
|
|
309
|
+
expect(notificationsQueriesMock.wasRead).toHaveBeenCalledWith(5, 123);
|
|
310
|
+
const loggerSpy = spyLogger();
|
|
311
|
+
notificationsQueriesMock.wasRead.mockRejectedValueOnce(new Error('fail'));
|
|
312
|
+
service.wasRead({
|
|
313
|
+
id: 8
|
|
314
|
+
}, undefined);
|
|
315
|
+
await flushPromises();
|
|
316
|
+
expect(loggerSpy).toHaveBeenCalled();
|
|
317
|
+
expect(loggerSpy.mock.calls[0]?.[0]).toMatch(/wasRead/i);
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
describe('delete', ()=>{
|
|
321
|
+
it('forwards to queries.delete', async ()=>{
|
|
322
|
+
await service.delete({
|
|
323
|
+
id: 77
|
|
324
|
+
}, 456);
|
|
325
|
+
expect(notificationsQueriesMock.delete).toHaveBeenCalledWith(77, 456);
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
describe('sendEmailNotification', ()=>{
|
|
329
|
+
it('returns early when mailer is not available', async ()=>{
|
|
330
|
+
mailerMock.available = false;
|
|
331
|
+
await service.sendEmailNotification([
|
|
332
|
+
{
|
|
333
|
+
id: 1,
|
|
334
|
+
email: 'a@test',
|
|
335
|
+
language: 'en'
|
|
336
|
+
}
|
|
337
|
+
], {
|
|
338
|
+
app: _notifications.NOTIFICATION_APP.COMMENTS
|
|
339
|
+
}, {
|
|
340
|
+
author: {
|
|
341
|
+
id: 1,
|
|
342
|
+
login: 'john'
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
expect(usersManagerMock.getAvatarBase64).not.toHaveBeenCalled();
|
|
346
|
+
expect(mailerMock.sendMails).not.toHaveBeenCalled();
|
|
347
|
+
});
|
|
348
|
+
it('enriches author avatar and sends mapped mails', async ()=>{
|
|
349
|
+
usersManagerMock.getAvatarBase64.mockResolvedValueOnce('base64-xxx');
|
|
350
|
+
const toUsers = [
|
|
351
|
+
{
|
|
352
|
+
id: 1,
|
|
353
|
+
email: 'a@test',
|
|
354
|
+
language: 'en'
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
id: 2,
|
|
358
|
+
email: 'b@test',
|
|
359
|
+
language: 'fr'
|
|
360
|
+
}
|
|
361
|
+
];
|
|
362
|
+
const options = {
|
|
363
|
+
author: {
|
|
364
|
+
id: 9,
|
|
365
|
+
login: 'jdoe'
|
|
366
|
+
},
|
|
367
|
+
content: 'hello',
|
|
368
|
+
currentUrl: 'https://app.test/path'
|
|
369
|
+
};
|
|
370
|
+
const content = {
|
|
371
|
+
app: _notifications.NOTIFICATION_APP.COMMENTS
|
|
372
|
+
};
|
|
373
|
+
await service.sendEmailNotification(toUsers, content, options);
|
|
374
|
+
expect(usersManagerMock.getAvatarBase64).toHaveBeenCalledWith('jdoe');
|
|
375
|
+
expect(options.author.avatarBase64).toBe('base64-xxx');
|
|
376
|
+
expect(mailerMock.sendMails).toHaveBeenCalledTimes(1);
|
|
377
|
+
expect(mailerMock.sendMails.mock.calls[0][0]).toEqual([
|
|
378
|
+
{
|
|
379
|
+
to: 'a@test',
|
|
380
|
+
subject: 'comment title',
|
|
381
|
+
html: 'comment html'
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
to: 'b@test',
|
|
385
|
+
subject: 'comment title',
|
|
386
|
+
html: 'comment html'
|
|
387
|
+
}
|
|
388
|
+
]);
|
|
389
|
+
});
|
|
390
|
+
it('logs error when sendMails rejects', async ()=>{
|
|
391
|
+
mailerMock.sendMails.mockRejectedValueOnce(new Error('smtp down'));
|
|
392
|
+
const loggerSpy = spyLogger();
|
|
393
|
+
await service.sendEmailNotification([
|
|
394
|
+
{
|
|
395
|
+
id: 1,
|
|
396
|
+
email: 'a@test',
|
|
397
|
+
language: 'en'
|
|
398
|
+
}
|
|
399
|
+
], {
|
|
400
|
+
app: _notifications.NOTIFICATION_APP.SYNC
|
|
401
|
+
}, {});
|
|
402
|
+
expect(loggerSpy).toHaveBeenCalled();
|
|
403
|
+
expect(loggerSpy.mock.calls[0]?.[0]).toMatch(/sendEmailNotification/i);
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
describe('genMail (private) - switch coverage', ()=>{
|
|
407
|
+
const cases = [
|
|
408
|
+
{
|
|
409
|
+
name: 'COMMENTS',
|
|
410
|
+
app: _notifications.NOTIFICATION_APP.COMMENTS,
|
|
411
|
+
fn: 'commentMail',
|
|
412
|
+
options: {
|
|
413
|
+
content: 'c',
|
|
414
|
+
currentUrl: 'u',
|
|
415
|
+
author: {
|
|
416
|
+
id: 1,
|
|
417
|
+
login: 'x'
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
name: 'SPACES',
|
|
423
|
+
app: _notifications.NOTIFICATION_APP.SPACES,
|
|
424
|
+
fn: 'spaceMail',
|
|
425
|
+
options: {
|
|
426
|
+
currentUrl: 'u',
|
|
427
|
+
action: 'A'
|
|
428
|
+
}
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
name: 'SPACE_ROOTS',
|
|
432
|
+
app: _notifications.NOTIFICATION_APP.SPACE_ROOTS,
|
|
433
|
+
fn: 'spaceRootMail',
|
|
434
|
+
options: {
|
|
435
|
+
currentUrl: 'u',
|
|
436
|
+
author: {
|
|
437
|
+
id: 2,
|
|
438
|
+
login: 'y'
|
|
439
|
+
},
|
|
440
|
+
action: 'B'
|
|
441
|
+
}
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
name: 'SHARES',
|
|
445
|
+
app: _notifications.NOTIFICATION_APP.SHARES,
|
|
446
|
+
fn: 'shareMail',
|
|
447
|
+
options: {
|
|
448
|
+
currentUrl: 'u',
|
|
449
|
+
author: {
|
|
450
|
+
id: 3,
|
|
451
|
+
login: 'z'
|
|
452
|
+
},
|
|
453
|
+
action: 'C'
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
name: 'LINKS',
|
|
458
|
+
app: _notifications.NOTIFICATION_APP.LINKS,
|
|
459
|
+
fn: 'linkMail',
|
|
460
|
+
options: {
|
|
461
|
+
currentUrl: 'u',
|
|
462
|
+
author: {
|
|
463
|
+
id: 4,
|
|
464
|
+
login: 'w'
|
|
465
|
+
},
|
|
466
|
+
linkUUID: 'uuid',
|
|
467
|
+
action: 'D'
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
name: 'SYNC',
|
|
472
|
+
app: _notifications.NOTIFICATION_APP.SYNC,
|
|
473
|
+
fn: 'syncMail',
|
|
474
|
+
options: {
|
|
475
|
+
currentUrl: 'u',
|
|
476
|
+
action: 'E'
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
];
|
|
480
|
+
it.each(cases)('uses $fn for $name', ({ app, fn, options })=>{
|
|
481
|
+
const res = service.genMail('en', {
|
|
482
|
+
app
|
|
483
|
+
}, options);
|
|
484
|
+
expect(res).toEqual([
|
|
485
|
+
`${fn.replace('Mail', '')} title`.replace('spaceRoot', 'spaceRoot'),
|
|
486
|
+
`${fn.replace('Mail', '')} html`.replace('spaceRoot', 'spaceRoot')
|
|
487
|
+
]);
|
|
488
|
+
expect(_models[fn]).toHaveBeenCalled();
|
|
489
|
+
});
|
|
490
|
+
it('logs error for unhandled app', ()=>{
|
|
491
|
+
const loggerSpy = spyLogger();
|
|
492
|
+
const result = service.genMail('en', {
|
|
493
|
+
app: 99999
|
|
494
|
+
}, {});
|
|
495
|
+
expect(result).toBeUndefined();
|
|
496
|
+
expect(loggerSpy).toHaveBeenCalled();
|
|
497
|
+
expect(loggerSpy.mock.calls[0]?.[0]).toMatch(/case not handled/i);
|
|
498
|
+
});
|
|
499
|
+
});
|
|
44
500
|
});
|
|
45
501
|
|
|
46
502
|
//# sourceMappingURL=notifications-manager.service.spec.js.map
|
package/server/applications/notifications/services/notifications-manager.service.spec.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/notifications/services/notifications-manager.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { Mailer } from '../../../infrastructure/mailer/mailer.service'\nimport { UsersManager } from '../../users/services/users-manager.service'\nimport { WebSocketNotifications } from '../notifications.gateway'\nimport { NotificationsManager } from './notifications-manager.service'\nimport { NotificationsQueries } from './notifications-queries.service'\n\ndescribe(NotificationsManager.name, () => {\n let service: NotificationsManager\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n NotificationsManager,\n { provide: UsersManager, useValue: {} },\n {\n provide: Mailer,\n useValue: {}\n },\n { provide: WebSocketNotifications, useValue: {} },\n { provide: NotificationsQueries, useValue: {} }\n ]\n }).compile()\n\n service = module.get<NotificationsManager>(NotificationsManager)\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n})\n"],"names":["describe","NotificationsManager","name","service","beforeAll","module","Test","createTestingModule","providers","provide","UsersManager","useValue","Mailer","WebSocketNotifications","NotificationsQueries","compile","get","it","expect","toBeDefined"],"mappings":"AAAA;;;;CAIC;;;;yBAEmC;+BACb;qCACM;sCACU;6CACF;6CACA;AAErCA,SAASC,iDAAoB,CAACC,IAAI,EAAE;IAClC,IAAIC;IAEJC,UAAU;QACR,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBACTP,iDAAoB;gBACpB;oBAAEQ,SAASC,iCAAY;oBAAEC,UAAU,CAAC;gBAAE;gBACtC;oBACEF,SAASG,qBAAM;oBACfD,UAAU,CAAC;gBACb;gBACA;oBAAEF,SAASI,4CAAsB;oBAAEF,UAAU,CAAC;gBAAE;gBAChD;oBAAEF,SAASK,iDAAoB;oBAAEH,UAAU,CAAC;gBAAE;aAC/C;QACH,GAAGI,OAAO;QAEVZ,UAAUE,OAAOW,GAAG,CAAuBf,iDAAoB;IACjE;IAEAgB,GAAG,qBAAqB;QACtBC,OAAOf,SAASgB,WAAW;IAC7B;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/notifications/services/notifications-manager.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { Mailer } from '../../../infrastructure/mailer/mailer.service'\nimport { USER_NOTIFICATION } from '../../users/constants/user'\nimport { UsersManager } from '../../users/services/users-manager.service'\nimport { NOTIFICATION_APP } from '../constants/notifications'\nimport { NOTIFICATIONS_WS } from '../constants/websocket'\nimport * as mailModels from '../mails/models'\nimport { WebSocketNotifications } from '../notifications.gateway'\nimport { NotificationsManager } from './notifications-manager.service'\nimport { NotificationsQueries } from './notifications-queries.service'\n\n// Compact mock for mail generators\njest.mock('../mails/models', () => ({\n commentMail: jest.fn(() => ['comment title', 'comment html']),\n spaceMail: jest.fn(() => ['space title', 'space html']),\n spaceRootMail: jest.fn(() => ['spaceRoot title', 'spaceRoot html']),\n shareMail: jest.fn(() => ['share title', 'share html']),\n linkMail: jest.fn(() => ['link title', 'link html']),\n syncMail: jest.fn(() => ['sync title', 'sync html'])\n}))\n\ndescribe(NotificationsManager.name, () => {\n let service: NotificationsManager\n\n const usersManagerMock = { getAvatarBase64: jest.fn() }\n const mailerMock = { available: true, sendMails: jest.fn() }\n const notificationsQueriesMock = {\n list: jest.fn(),\n usersNotifiedByEmail: jest.fn(),\n create: jest.fn(),\n wasRead: jest.fn(),\n delete: jest.fn()\n }\n const webSocketNotificationsMock = { sendMessageToUsers: jest.fn() }\n\n const flushPromises = () => new Promise<void>((r) => setImmediate(r))\n const spyLogger = () => jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined as any)\n\n beforeEach(async () => {\n jest.clearAllMocks()\n mailerMock.available = true\n mailerMock.sendMails.mockResolvedValue(undefined)\n notificationsQueriesMock.create.mockResolvedValue(undefined)\n notificationsQueriesMock.wasRead.mockResolvedValue(undefined)\n notificationsQueriesMock.delete.mockResolvedValue(undefined)\n notificationsQueriesMock.list.mockResolvedValue([])\n notificationsQueriesMock.usersNotifiedByEmail.mockResolvedValue([])\n usersManagerMock.getAvatarBase64.mockResolvedValue('avatar-base64')\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n NotificationsManager,\n { provide: UsersManager, useValue: usersManagerMock },\n { provide: Mailer, useValue: mailerMock },\n { provide: WebSocketNotifications, useValue: webSocketNotificationsMock },\n { provide: NotificationsQueries, useValue: notificationsQueriesMock }\n ]\n }).compile()\n service = module.get<NotificationsManager>(NotificationsManager)\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n\n describe('list', () => {\n it.each`\n userId | onlyUnread | expected\n ${42} | ${true} | ${true}\n ${1} | ${undefined} | ${false}\n `('should list notifications (userId=$userId, onlyUnread=$onlyUnread)', async ({ userId, onlyUnread, expected }) => {\n const expectedRes = [{ id: userId }] as any\n notificationsQueriesMock.list.mockResolvedValueOnce(expectedRes)\n const res = await service.list({ id: userId } as any, onlyUnread as any)\n expect(notificationsQueriesMock.list).toHaveBeenCalledWith(userId, expected)\n expect(res).toBe(expectedRes)\n })\n })\n\n describe('create', () => {\n it('stores, sends WS and no email when filtered list empty (object input)', async () => {\n const sendEmailSpy = jest.spyOn(service, 'sendEmailNotification').mockResolvedValue(undefined)\n const toUsers = [\n { id: 10, email: 'u1@test.tld', language: 'en', notification: USER_NOTIFICATION.APPLICATION },\n { id: 11, email: 'u2@test.tld', language: 'fr', notification: USER_NOTIFICATION.APPLICATION }\n ]\n await service.create(toUsers as any, { app: NOTIFICATION_APP.COMMENTS } as any, { author: { id: 99, login: 'john' } } as any)\n expect(notificationsQueriesMock.create).toHaveBeenCalledWith(99, [10, 11], { app: NOTIFICATION_APP.COMMENTS })\n expect(webSocketNotificationsMock.sendMessageToUsers).toHaveBeenCalledWith([10, 11], NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check')\n expect(sendEmailSpy).not.toHaveBeenCalled()\n expect(notificationsQueriesMock.usersNotifiedByEmail).not.toHaveBeenCalled()\n })\n\n it('stores, sends WS and email for ids input', async () => {\n const sendEmailSpy = jest.spyOn(service, 'sendEmailNotification').mockResolvedValue(undefined)\n const toUserIds = [1, 2, 3]\n const content = { app: NOTIFICATION_APP.SHARES } as any\n const emailUsers = [\n { id: 1, email: 'a@test', language: 'en' },\n { id: 3, email: 'c@test', language: 'fr' }\n ]\n notificationsQueriesMock.usersNotifiedByEmail.mockResolvedValueOnce(emailUsers as any)\n await service.create(toUserIds, content)\n expect(notificationsQueriesMock.create).toHaveBeenCalledWith(null, toUserIds, content)\n expect(webSocketNotificationsMock.sendMessageToUsers).toHaveBeenCalledWith(toUserIds, NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check')\n expect(notificationsQueriesMock.usersNotifiedByEmail).toHaveBeenCalledWith(toUserIds)\n expect(sendEmailSpy).toHaveBeenCalledWith(emailUsers as any, content, undefined)\n })\n\n it('does not try email when mailer is unavailable', async () => {\n mailerMock.available = false\n const sendEmailSpy = jest.spyOn(service, 'sendEmailNotification').mockResolvedValue(undefined)\n await service.create([7], { app: NOTIFICATION_APP.SYNC } as any, { author: { id: 12, login: 'jane' } } as any)\n expect(notificationsQueriesMock.create).toHaveBeenCalledWith(12, [7], { app: NOTIFICATION_APP.SYNC })\n expect(webSocketNotificationsMock.sendMessageToUsers).toHaveBeenCalledWith([7], NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check')\n expect(notificationsQueriesMock.usersNotifiedByEmail).not.toHaveBeenCalled()\n expect(sendEmailSpy).not.toHaveBeenCalled()\n })\n\n it('logs error when storeNotification internal try/catch catches create error', async () => {\n const loggerSpy = spyLogger()\n notificationsQueriesMock.create.mockRejectedValueOnce(new Error('DB fail'))\n await service.create([1], { app: NOTIFICATION_APP.LINKS } as any)\n await flushPromises()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/create/i)\n })\n\n it('logs error when storeNotification promise rejects (create catch)', async () => {\n const loggerSpy = spyLogger()\n jest.spyOn<any, any>(service as any, 'storeNotification').mockRejectedValueOnce(new Error('store reject'))\n await service.create([1, 2], { app: NOTIFICATION_APP.SYNC } as any, { author: { id: 5, login: 'xx' } } as any)\n await flushPromises()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/create/i)\n })\n\n it('logs error when sendEmailNotification rejects (create catch)', async () => {\n const loggerSpy = spyLogger()\n notificationsQueriesMock.usersNotifiedByEmail.mockResolvedValueOnce([{ id: 1, email: 'a@test', language: 'en' }] as any)\n jest.spyOn(service, 'sendEmailNotification').mockRejectedValueOnce(new Error('email reject'))\n await service.create([1], { app: NOTIFICATION_APP.COMMENTS } as any)\n await flushPromises()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/create/i)\n })\n })\n\n describe('wasRead', () => {\n it('calls queries.wasRead and logs on error', async () => {\n service.wasRead({ id: 5 } as any, 123)\n expect(notificationsQueriesMock.wasRead).toHaveBeenCalledWith(5, 123)\n const loggerSpy = spyLogger()\n notificationsQueriesMock.wasRead.mockRejectedValueOnce(new Error('fail'))\n service.wasRead({ id: 8 } as any, undefined)\n await flushPromises()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/wasRead/i)\n })\n })\n\n describe('delete', () => {\n it('forwards to queries.delete', async () => {\n await service.delete({ id: 77 } as any, 456)\n expect(notificationsQueriesMock.delete).toHaveBeenCalledWith(77, 456)\n })\n })\n\n describe('sendEmailNotification', () => {\n it('returns early when mailer is not available', async () => {\n mailerMock.available = false\n await service.sendEmailNotification(\n [{ id: 1, email: 'a@test', language: 'en' }] as any,\n { app: NOTIFICATION_APP.COMMENTS } as any,\n {\n author: { id: 1, login: 'john' }\n } as any\n )\n expect(usersManagerMock.getAvatarBase64).not.toHaveBeenCalled()\n expect(mailerMock.sendMails).not.toHaveBeenCalled()\n })\n\n it('enriches author avatar and sends mapped mails', async () => {\n usersManagerMock.getAvatarBase64.mockResolvedValueOnce('base64-xxx')\n const toUsers = [\n { id: 1, email: 'a@test', language: 'en' },\n { id: 2, email: 'b@test', language: 'fr' }\n ]\n const options: any = { author: { id: 9, login: 'jdoe' }, content: 'hello', currentUrl: 'https://app.test/path' }\n const content = { app: NOTIFICATION_APP.COMMENTS } as any\n await service.sendEmailNotification(toUsers as any, content, options)\n expect(usersManagerMock.getAvatarBase64).toHaveBeenCalledWith('jdoe')\n expect(options.author.avatarBase64).toBe('base64-xxx')\n expect(mailerMock.sendMails).toHaveBeenCalledTimes(1)\n expect((mailerMock.sendMails as jest.Mock).mock.calls[0][0]).toEqual([\n { to: 'a@test', subject: 'comment title', html: 'comment html' },\n { to: 'b@test', subject: 'comment title', html: 'comment html' }\n ])\n })\n\n it('logs error when sendMails rejects', async () => {\n mailerMock.sendMails.mockRejectedValueOnce(new Error('smtp down'))\n const loggerSpy = spyLogger()\n await service.sendEmailNotification([{ id: 1, email: 'a@test', language: 'en' }] as any, { app: NOTIFICATION_APP.SYNC } as any, {} as any)\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/sendEmailNotification/i)\n })\n })\n\n describe('genMail (private) - switch coverage', () => {\n const cases = [\n {\n name: 'COMMENTS',\n app: NOTIFICATION_APP.COMMENTS,\n fn: 'commentMail',\n options: { content: 'c', currentUrl: 'u', author: { id: 1, login: 'x' } }\n },\n { name: 'SPACES', app: NOTIFICATION_APP.SPACES, fn: 'spaceMail', options: { currentUrl: 'u', action: 'A' } },\n {\n name: 'SPACE_ROOTS',\n app: NOTIFICATION_APP.SPACE_ROOTS,\n fn: 'spaceRootMail',\n options: { currentUrl: 'u', author: { id: 2, login: 'y' }, action: 'B' }\n },\n { name: 'SHARES', app: NOTIFICATION_APP.SHARES, fn: 'shareMail', options: { currentUrl: 'u', author: { id: 3, login: 'z' }, action: 'C' } },\n {\n name: 'LINKS',\n app: NOTIFICATION_APP.LINKS,\n fn: 'linkMail',\n options: { currentUrl: 'u', author: { id: 4, login: 'w' }, linkUUID: 'uuid', action: 'D' }\n },\n { name: 'SYNC', app: NOTIFICATION_APP.SYNC, fn: 'syncMail', options: { currentUrl: 'u', action: 'E' } }\n ] as const\n\n it.each(cases)('uses $fn for $name', ({ app, fn, options }) => {\n const res = (service as any).genMail('en', { app } as any, options as any)\n expect(res).toEqual([\n `${fn.replace('Mail', '')} title`.replace('spaceRoot', 'spaceRoot'),\n `${fn.replace('Mail', '')} html`.replace('spaceRoot', 'spaceRoot')\n ])\n expect((mailModels as any)[fn]).toHaveBeenCalled()\n })\n\n it('logs error for unhandled app', () => {\n const loggerSpy = spyLogger()\n const result = (service as any).genMail('en', { app: 99999 } as any, {} as any)\n expect(result).toBeUndefined()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/case not handled/i)\n })\n })\n})\n"],"names":["jest","mock","commentMail","fn","spaceMail","spaceRootMail","shareMail","linkMail","syncMail","describe","NotificationsManager","name","service","usersManagerMock","getAvatarBase64","mailerMock","available","sendMails","notificationsQueriesMock","list","usersNotifiedByEmail","create","wasRead","delete","webSocketNotificationsMock","sendMessageToUsers","flushPromises","Promise","r","setImmediate","spyLogger","spyOn","logger","mockImplementation","undefined","beforeEach","clearAllMocks","mockResolvedValue","module","Test","createTestingModule","providers","provide","UsersManager","useValue","Mailer","WebSocketNotifications","NotificationsQueries","compile","get","it","expect","toBeDefined","each","userId","onlyUnread","expected","expectedRes","id","mockResolvedValueOnce","res","toHaveBeenCalledWith","toBe","sendEmailSpy","toUsers","email","language","notification","USER_NOTIFICATION","APPLICATION","app","NOTIFICATION_APP","COMMENTS","author","login","NOTIFICATIONS_WS","EVENTS","NOTIFICATION","not","toHaveBeenCalled","toUserIds","content","SHARES","emailUsers","SYNC","loggerSpy","mockRejectedValueOnce","Error","LINKS","calls","toMatch","sendEmailNotification","options","currentUrl","avatarBase64","toHaveBeenCalledTimes","toEqual","to","subject","html","cases","SPACES","action","SPACE_ROOTS","linkUUID","genMail","replace","mailModels","result","toBeUndefined"],"mappings":"AAAA;;;;CAIC;;;;yBAEmC;+BACb;sBACW;qCACL;+BACI;2BACA;gEACL;sCACW;6CACF;6CACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAErC,mCAAmC;AACnCA,KAAKC,IAAI,CAAC,mBAAmB,IAAO,CAAA;QAClCC,aAAaF,KAAKG,EAAE,CAAC,IAAM;gBAAC;gBAAiB;aAAe;QAC5DC,WAAWJ,KAAKG,EAAE,CAAC,IAAM;gBAAC;gBAAe;aAAa;QACtDE,eAAeL,KAAKG,EAAE,CAAC,IAAM;gBAAC;gBAAmB;aAAiB;QAClEG,WAAWN,KAAKG,EAAE,CAAC,IAAM;gBAAC;gBAAe;aAAa;QACtDI,UAAUP,KAAKG,EAAE,CAAC,IAAM;gBAAC;gBAAc;aAAY;QACnDK,UAAUR,KAAKG,EAAE,CAAC,IAAM;gBAAC;gBAAc;aAAY;IACrD,CAAA;AAEAM,SAASC,iDAAoB,CAACC,IAAI,EAAE;IAClC,IAAIC;IAEJ,MAAMC,mBAAmB;QAAEC,iBAAiBd,KAAKG,EAAE;IAAG;IACtD,MAAMY,aAAa;QAAEC,WAAW;QAAMC,WAAWjB,KAAKG,EAAE;IAAG;IAC3D,MAAMe,2BAA2B;QAC/BC,MAAMnB,KAAKG,EAAE;QACbiB,sBAAsBpB,KAAKG,EAAE;QAC7BkB,QAAQrB,KAAKG,EAAE;QACfmB,SAAStB,KAAKG,EAAE;QAChBoB,QAAQvB,KAAKG,EAAE;IACjB;IACA,MAAMqB,6BAA6B;QAAEC,oBAAoBzB,KAAKG,EAAE;IAAG;IAEnE,MAAMuB,gBAAgB,IAAM,IAAIC,QAAc,CAACC,IAAMC,aAAaD;IAClE,MAAME,YAAY,IAAM9B,KAAK+B,KAAK,CAAC,AAACnB,QAAgBoB,MAAM,EAAE,SAASC,kBAAkB,CAAC,IAAMC;IAE9FC,WAAW;QACTnC,KAAKoC,aAAa;QAClBrB,WAAWC,SAAS,GAAG;QACvBD,WAAWE,SAAS,CAACoB,iBAAiB,CAACH;QACvChB,yBAAyBG,MAAM,CAACgB,iBAAiB,CAACH;QAClDhB,yBAAyBI,OAAO,CAACe,iBAAiB,CAACH;QACnDhB,yBAAyBK,MAAM,CAACc,iBAAiB,CAACH;QAClDhB,yBAAyBC,IAAI,CAACkB,iBAAiB,CAAC,EAAE;QAClDnB,yBAAyBE,oBAAoB,CAACiB,iBAAiB,CAAC,EAAE;QAClExB,iBAAiBC,eAAe,CAACuB,iBAAiB,CAAC;QAEnD,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBACT/B,iDAAoB;gBACpB;oBAAEgC,SAASC,iCAAY;oBAAEC,UAAU/B;gBAAiB;gBACpD;oBAAE6B,SAASG,qBAAM;oBAAED,UAAU7B;gBAAW;gBACxC;oBAAE2B,SAASI,4CAAsB;oBAAEF,UAAUpB;gBAA2B;gBACxE;oBAAEkB,SAASK,iDAAoB;oBAAEH,UAAU1B;gBAAyB;aACrE;QACH,GAAG8B,OAAO;QACVpC,UAAU0B,OAAOW,GAAG,CAAuBvC,iDAAoB;IACjE;IAEAwC,GAAG,qBAAqB;QACtBC,OAAOvC,SAASwC,WAAW;IAC7B;IAEA3C,SAAS,QAAQ;QACfyC,GAAGG,IAAI,CAAC;;MAEN,EAAE,GAAG,IAAI,EAAE,KAAK,QAAQ,EAAE,KAAK;MAC/B,EAAE,EAAE,KAAK,EAAEnB,UAAU,GAAG,EAAE,MAAM;IAClC,CAAC,CAAC,sEAAsE,OAAO,EAAEoB,MAAM,EAAEC,UAAU,EAAEC,QAAQ,EAAE;YAC7G,MAAMC,cAAc;gBAAC;oBAAEC,IAAIJ;gBAAO;aAAE;YACpCpC,yBAAyBC,IAAI,CAACwC,qBAAqB,CAACF;YACpD,MAAMG,MAAM,MAAMhD,QAAQO,IAAI,CAAC;gBAAEuC,IAAIJ;YAAO,GAAUC;YACtDJ,OAAOjC,yBAAyBC,IAAI,EAAE0C,oBAAoB,CAACP,QAAQE;YACnEL,OAAOS,KAAKE,IAAI,CAACL;QACnB;IACF;IAEAhD,SAAS,UAAU;QACjByC,GAAG,yEAAyE;YAC1E,MAAMa,eAAe/D,KAAK+B,KAAK,CAACnB,SAAS,yBAAyByB,iBAAiB,CAACH;YACpF,MAAM8B,UAAU;gBACd;oBAAEN,IAAI;oBAAIO,OAAO;oBAAeC,UAAU;oBAAMC,cAAcC,uBAAiB,CAACC,WAAW;gBAAC;gBAC5F;oBAAEX,IAAI;oBAAIO,OAAO;oBAAeC,UAAU;oBAAMC,cAAcC,uBAAiB,CAACC,WAAW;gBAAC;aAC7F;YACD,MAAMzD,QAAQS,MAAM,CAAC2C,SAAgB;gBAAEM,KAAKC,+BAAgB,CAACC,QAAQ;YAAC,GAAU;gBAAEC,QAAQ;oBAAEf,IAAI;oBAAIgB,OAAO;gBAAO;YAAE;YACpHvB,OAAOjC,yBAAyBG,MAAM,EAAEwC,oBAAoB,CAAC,IAAI;gBAAC;gBAAI;aAAG,EAAE;gBAAES,KAAKC,+BAAgB,CAACC,QAAQ;YAAC;YAC5GrB,OAAO3B,2BAA2BC,kBAAkB,EAAEoC,oBAAoB,CAAC;gBAAC;gBAAI;aAAG,EAAEc,2BAAgB,CAACC,MAAM,CAACC,YAAY,EAAE;YAC3H1B,OAAOY,cAAce,GAAG,CAACC,gBAAgB;YACzC5B,OAAOjC,yBAAyBE,oBAAoB,EAAE0D,GAAG,CAACC,gBAAgB;QAC5E;QAEA7B,GAAG,4CAA4C;YAC7C,MAAMa,eAAe/D,KAAK+B,KAAK,CAACnB,SAAS,yBAAyByB,iBAAiB,CAACH;YACpF,MAAM8C,YAAY;gBAAC;gBAAG;gBAAG;aAAE;YAC3B,MAAMC,UAAU;gBAAEX,KAAKC,+BAAgB,CAACW,MAAM;YAAC;YAC/C,MAAMC,aAAa;gBACjB;oBAAEzB,IAAI;oBAAGO,OAAO;oBAAUC,UAAU;gBAAK;gBACzC;oBAAER,IAAI;oBAAGO,OAAO;oBAAUC,UAAU;gBAAK;aAC1C;YACDhD,yBAAyBE,oBAAoB,CAACuC,qBAAqB,CAACwB;YACpE,MAAMvE,QAAQS,MAAM,CAAC2D,WAAWC;YAChC9B,OAAOjC,yBAAyBG,MAAM,EAAEwC,oBAAoB,CAAC,MAAMmB,WAAWC;YAC9E9B,OAAO3B,2BAA2BC,kBAAkB,EAAEoC,oBAAoB,CAACmB,WAAWL,2BAAgB,CAACC,MAAM,CAACC,YAAY,EAAE;YAC5H1B,OAAOjC,yBAAyBE,oBAAoB,EAAEyC,oBAAoB,CAACmB;YAC3E7B,OAAOY,cAAcF,oBAAoB,CAACsB,YAAmBF,SAAS/C;QACxE;QAEAgB,GAAG,iDAAiD;YAClDnC,WAAWC,SAAS,GAAG;YACvB,MAAM+C,eAAe/D,KAAK+B,KAAK,CAACnB,SAAS,yBAAyByB,iBAAiB,CAACH;YACpF,MAAMtB,QAAQS,MAAM,CAAC;gBAAC;aAAE,EAAE;gBAAEiD,KAAKC,+BAAgB,CAACa,IAAI;YAAC,GAAU;gBAAEX,QAAQ;oBAAEf,IAAI;oBAAIgB,OAAO;gBAAO;YAAE;YACrGvB,OAAOjC,yBAAyBG,MAAM,EAAEwC,oBAAoB,CAAC,IAAI;gBAAC;aAAE,EAAE;gBAAES,KAAKC,+BAAgB,CAACa,IAAI;YAAC;YACnGjC,OAAO3B,2BAA2BC,kBAAkB,EAAEoC,oBAAoB,CAAC;gBAAC;aAAE,EAAEc,2BAAgB,CAACC,MAAM,CAACC,YAAY,EAAE;YACtH1B,OAAOjC,yBAAyBE,oBAAoB,EAAE0D,GAAG,CAACC,gBAAgB;YAC1E5B,OAAOY,cAAce,GAAG,CAACC,gBAAgB;QAC3C;QAEA7B,GAAG,6EAA6E;YAC9E,MAAMmC,YAAYvD;YAClBZ,yBAAyBG,MAAM,CAACiE,qBAAqB,CAAC,IAAIC,MAAM;YAChE,MAAM3E,QAAQS,MAAM,CAAC;gBAAC;aAAE,EAAE;gBAAEiD,KAAKC,+BAAgB,CAACiB,KAAK;YAAC;YACxD,MAAM9D;YACNyB,OAAOkC,WAAWN,gBAAgB;YAClC5B,OAAOkC,UAAUpF,IAAI,CAACwF,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,EAAYC,OAAO,CAAC;QACzD;QAEAxC,GAAG,oEAAoE;YACrE,MAAMmC,YAAYvD;YAClB9B,KAAK+B,KAAK,CAAWnB,SAAgB,qBAAqB0E,qBAAqB,CAAC,IAAIC,MAAM;YAC1F,MAAM3E,QAAQS,MAAM,CAAC;gBAAC;gBAAG;aAAE,EAAE;gBAAEiD,KAAKC,+BAAgB,CAACa,IAAI;YAAC,GAAU;gBAAEX,QAAQ;oBAAEf,IAAI;oBAAGgB,OAAO;gBAAK;YAAE;YACrG,MAAMhD;YACNyB,OAAOkC,WAAWN,gBAAgB;YAClC5B,OAAOkC,UAAUpF,IAAI,CAACwF,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,EAAYC,OAAO,CAAC;QACzD;QAEAxC,GAAG,gEAAgE;YACjE,MAAMmC,YAAYvD;YAClBZ,yBAAyBE,oBAAoB,CAACuC,qBAAqB,CAAC;gBAAC;oBAAED,IAAI;oBAAGO,OAAO;oBAAUC,UAAU;gBAAK;aAAE;YAChHlE,KAAK+B,KAAK,CAACnB,SAAS,yBAAyB0E,qBAAqB,CAAC,IAAIC,MAAM;YAC7E,MAAM3E,QAAQS,MAAM,CAAC;gBAAC;aAAE,EAAE;gBAAEiD,KAAKC,+BAAgB,CAACC,QAAQ;YAAC;YAC3D,MAAM9C;YACNyB,OAAOkC,WAAWN,gBAAgB;YAClC5B,OAAOkC,UAAUpF,IAAI,CAACwF,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,EAAYC,OAAO,CAAC;QACzD;IACF;IAEAjF,SAAS,WAAW;QAClByC,GAAG,2CAA2C;YAC5CtC,QAAQU,OAAO,CAAC;gBAAEoC,IAAI;YAAE,GAAU;YAClCP,OAAOjC,yBAAyBI,OAAO,EAAEuC,oBAAoB,CAAC,GAAG;YACjE,MAAMwB,YAAYvD;YAClBZ,yBAAyBI,OAAO,CAACgE,qBAAqB,CAAC,IAAIC,MAAM;YACjE3E,QAAQU,OAAO,CAAC;gBAAEoC,IAAI;YAAE,GAAUxB;YAClC,MAAMR;YACNyB,OAAOkC,WAAWN,gBAAgB;YAClC5B,OAAOkC,UAAUpF,IAAI,CAACwF,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,EAAYC,OAAO,CAAC;QACzD;IACF;IAEAjF,SAAS,UAAU;QACjByC,GAAG,8BAA8B;YAC/B,MAAMtC,QAAQW,MAAM,CAAC;gBAAEmC,IAAI;YAAG,GAAU;YACxCP,OAAOjC,yBAAyBK,MAAM,EAAEsC,oBAAoB,CAAC,IAAI;QACnE;IACF;IAEApD,SAAS,yBAAyB;QAChCyC,GAAG,8CAA8C;YAC/CnC,WAAWC,SAAS,GAAG;YACvB,MAAMJ,QAAQ+E,qBAAqB,CACjC;gBAAC;oBAAEjC,IAAI;oBAAGO,OAAO;oBAAUC,UAAU;gBAAK;aAAE,EAC5C;gBAAEI,KAAKC,+BAAgB,CAACC,QAAQ;YAAC,GACjC;gBACEC,QAAQ;oBAAEf,IAAI;oBAAGgB,OAAO;gBAAO;YACjC;YAEFvB,OAAOtC,iBAAiBC,eAAe,EAAEgE,GAAG,CAACC,gBAAgB;YAC7D5B,OAAOpC,WAAWE,SAAS,EAAE6D,GAAG,CAACC,gBAAgB;QACnD;QAEA7B,GAAG,iDAAiD;YAClDrC,iBAAiBC,eAAe,CAAC6C,qBAAqB,CAAC;YACvD,MAAMK,UAAU;gBACd;oBAAEN,IAAI;oBAAGO,OAAO;oBAAUC,UAAU;gBAAK;gBACzC;oBAAER,IAAI;oBAAGO,OAAO;oBAAUC,UAAU;gBAAK;aAC1C;YACD,MAAM0B,UAAe;gBAAEnB,QAAQ;oBAAEf,IAAI;oBAAGgB,OAAO;gBAAO;gBAAGO,SAAS;gBAASY,YAAY;YAAwB;YAC/G,MAAMZ,UAAU;gBAAEX,KAAKC,+BAAgB,CAACC,QAAQ;YAAC;YACjD,MAAM5D,QAAQ+E,qBAAqB,CAAC3B,SAAgBiB,SAASW;YAC7DzC,OAAOtC,iBAAiBC,eAAe,EAAE+C,oBAAoB,CAAC;YAC9DV,OAAOyC,QAAQnB,MAAM,CAACqB,YAAY,EAAEhC,IAAI,CAAC;YACzCX,OAAOpC,WAAWE,SAAS,EAAE8E,qBAAqB,CAAC;YACnD5C,OAAO,AAACpC,WAAWE,SAAS,CAAehB,IAAI,CAACwF,KAAK,CAAC,EAAE,CAAC,EAAE,EAAEO,OAAO,CAAC;gBACnE;oBAAEC,IAAI;oBAAUC,SAAS;oBAAiBC,MAAM;gBAAe;gBAC/D;oBAAEF,IAAI;oBAAUC,SAAS;oBAAiBC,MAAM;gBAAe;aAChE;QACH;QAEAjD,GAAG,qCAAqC;YACtCnC,WAAWE,SAAS,CAACqE,qBAAqB,CAAC,IAAIC,MAAM;YACrD,MAAMF,YAAYvD;YAClB,MAAMlB,QAAQ+E,qBAAqB,CAAC;gBAAC;oBAAEjC,IAAI;oBAAGO,OAAO;oBAAUC,UAAU;gBAAK;aAAE,EAAS;gBAAEI,KAAKC,+BAAgB,CAACa,IAAI;YAAC,GAAU,CAAC;YACjIjC,OAAOkC,WAAWN,gBAAgB;YAClC5B,OAAOkC,UAAUpF,IAAI,CAACwF,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,EAAYC,OAAO,CAAC;QACzD;IACF;IAEAjF,SAAS,uCAAuC;QAC9C,MAAM2F,QAAQ;YACZ;gBACEzF,MAAM;gBACN2D,KAAKC,+BAAgB,CAACC,QAAQ;gBAC9BrE,IAAI;gBACJyF,SAAS;oBAAEX,SAAS;oBAAKY,YAAY;oBAAKpB,QAAQ;wBAAEf,IAAI;wBAAGgB,OAAO;oBAAI;gBAAE;YAC1E;YACA;gBAAE/D,MAAM;gBAAU2D,KAAKC,+BAAgB,CAAC8B,MAAM;gBAAElG,IAAI;gBAAayF,SAAS;oBAAEC,YAAY;oBAAKS,QAAQ;gBAAI;YAAE;YAC3G;gBACE3F,MAAM;gBACN2D,KAAKC,+BAAgB,CAACgC,WAAW;gBACjCpG,IAAI;gBACJyF,SAAS;oBAAEC,YAAY;oBAAKpB,QAAQ;wBAAEf,IAAI;wBAAGgB,OAAO;oBAAI;oBAAG4B,QAAQ;gBAAI;YACzE;YACA;gBAAE3F,MAAM;gBAAU2D,KAAKC,+BAAgB,CAACW,MAAM;gBAAE/E,IAAI;gBAAayF,SAAS;oBAAEC,YAAY;oBAAKpB,QAAQ;wBAAEf,IAAI;wBAAGgB,OAAO;oBAAI;oBAAG4B,QAAQ;gBAAI;YAAE;YAC1I;gBACE3F,MAAM;gBACN2D,KAAKC,+BAAgB,CAACiB,KAAK;gBAC3BrF,IAAI;gBACJyF,SAAS;oBAAEC,YAAY;oBAAKpB,QAAQ;wBAAEf,IAAI;wBAAGgB,OAAO;oBAAI;oBAAG8B,UAAU;oBAAQF,QAAQ;gBAAI;YAC3F;YACA;gBAAE3F,MAAM;gBAAQ2D,KAAKC,+BAAgB,CAACa,IAAI;gBAAEjF,IAAI;gBAAYyF,SAAS;oBAAEC,YAAY;oBAAKS,QAAQ;gBAAI;YAAE;SACvG;QAEDpD,GAAGG,IAAI,CAAC+C,OAAO,sBAAsB,CAAC,EAAE9B,GAAG,EAAEnE,EAAE,EAAEyF,OAAO,EAAE;YACxD,MAAMhC,MAAM,AAAChD,QAAgB6F,OAAO,CAAC,MAAM;gBAAEnC;YAAI,GAAUsB;YAC3DzC,OAAOS,KAAKoC,OAAO,CAAC;gBAClB,GAAG7F,GAAGuG,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,CAACA,OAAO,CAAC,aAAa;gBACvD,GAAGvG,GAAGuG,OAAO,CAAC,QAAQ,IAAI,KAAK,CAAC,CAACA,OAAO,CAAC,aAAa;aACvD;YACDvD,OAAO,AAACwD,OAAkB,CAACxG,GAAG,EAAE4E,gBAAgB;QAClD;QAEA7B,GAAG,gCAAgC;YACjC,MAAMmC,YAAYvD;YAClB,MAAM8E,SAAS,AAAChG,QAAgB6F,OAAO,CAAC,MAAM;gBAAEnC,KAAK;YAAM,GAAU,CAAC;YACtEnB,OAAOyD,QAAQC,aAAa;YAC5B1D,OAAOkC,WAAWN,gBAAgB;YAClC5B,OAAOkC,UAAUpF,IAAI,CAACwF,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,EAAYC,OAAO,CAAC;QACzD;IACF;AACF"}
|