@flusys/nestjs-task-manager 7.1.0 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/config/index.d.ts +3 -3
  2. package/controllers/index.d.ts +5 -5
  3. package/controllers/task-board.controller.d.ts +3 -3
  4. package/controllers/task-comment.controller.d.ts +2 -2
  5. package/controllers/task-label.controller.d.ts +2 -2
  6. package/controllers/task-list.controller.d.ts +3 -3
  7. package/controllers/task.controller.d.ts +4 -4
  8. package/docs/index.d.ts +1 -1
  9. package/docs/task-manager-swagger.config.d.ts +1 -1
  10. package/dtos/index.d.ts +5 -5
  11. package/dtos/task-board.dto.d.ts +1 -1
  12. package/dtos/task.dto.d.ts +2 -2
  13. package/entities/index.d.ts +19 -19
  14. package/entities/task-board-with-company.entity.d.ts +1 -1
  15. package/fesm/234.js +1393 -0
  16. package/fesm/431.js +981 -0
  17. package/fesm/827.js +1054 -0
  18. package/fesm/988.js +881 -0
  19. package/fesm/config/index.js +156 -3
  20. package/fesm/controllers/index.js +21 -5
  21. package/fesm/docs/index.js +58 -1
  22. package/fesm/dtos/index.js +280 -5
  23. package/fesm/entities/index.js +26 -46
  24. package/fesm/gateways/index.js +288 -1
  25. package/fesm/index.js +440 -9
  26. package/fesm/interfaces/index.js +16 -2
  27. package/fesm/modules/index.js +210 -1
  28. package/fesm/runtime.js +85 -0
  29. package/fesm/services/index.js +53 -8
  30. package/gateways/index.d.ts +1 -1
  31. package/gateways/task-board.gateway.d.ts +3 -3
  32. package/index.d.ts +9 -9
  33. package/interfaces/index.d.ts +2 -2
  34. package/interfaces/task-manager-module.interface.d.ts +3 -3
  35. package/interfaces/task.interface.d.ts +2 -2
  36. package/modules/index.d.ts +1 -1
  37. package/modules/task-manager.module.d.ts +2 -2
  38. package/package.json +26 -36
  39. package/services/index.d.ts +8 -8
  40. package/services/task-activity.service.d.ts +1 -1
  41. package/services/task-board.service.d.ts +5 -5
  42. package/services/task-comment.service.d.ts +4 -4
  43. package/services/task-label.service.d.ts +4 -4
  44. package/services/task-list.service.d.ts +4 -4
  45. package/services/task-manager-config.service.d.ts +3 -3
  46. package/services/task-manager-datasource.provider.d.ts +3 -3
  47. package/services/task.service.d.ts +7 -7
  48. package/cjs/config/event-actions.js +0 -37
  49. package/cjs/config/index.js +0 -20
  50. package/cjs/config/message-keys.js +0 -92
  51. package/cjs/config/task-manager.constants.js +0 -11
  52. package/cjs/controllers/index.js +0 -22
  53. package/cjs/controllers/task-board.controller.js +0 -219
  54. package/cjs/controllers/task-board.controller.spec.js +0 -132
  55. package/cjs/controllers/task-comment.controller.js +0 -103
  56. package/cjs/controllers/task-comment.controller.spec.js +0 -86
  57. package/cjs/controllers/task-label.controller.js +0 -112
  58. package/cjs/controllers/task-label.controller.spec.js +0 -88
  59. package/cjs/controllers/task-list.controller.js +0 -158
  60. package/cjs/controllers/task-list.controller.spec.js +0 -112
  61. package/cjs/controllers/task.controller.js +0 -199
  62. package/cjs/controllers/task.controller.spec.js +0 -131
  63. package/cjs/docs/index.js +0 -18
  64. package/cjs/docs/task-manager-swagger.config.js +0 -43
  65. package/cjs/docs/task-manager-swagger.config.spec.js +0 -28
  66. package/cjs/dtos/index.js +0 -22
  67. package/cjs/dtos/task-board.dto.js +0 -310
  68. package/cjs/dtos/task-comment.dto.js +0 -131
  69. package/cjs/dtos/task-label.dto.js +0 -120
  70. package/cjs/dtos/task-list.dto.js +0 -198
  71. package/cjs/dtos/task.dto.js +0 -367
  72. package/cjs/entities/index.js +0 -72
  73. package/cjs/entities/index.spec.js +0 -30
  74. package/cjs/entities/task-activity.entity.js +0 -98
  75. package/cjs/entities/task-assignee.entity.js +0 -67
  76. package/cjs/entities/task-board-member.entity.js +0 -94
  77. package/cjs/entities/task-board-with-company.entity.js +0 -57
  78. package/cjs/entities/task-board.entity.js +0 -88
  79. package/cjs/entities/task-comment.entity.js +0 -80
  80. package/cjs/entities/task-label.entity.js +0 -72
  81. package/cjs/entities/task-list.entity.js +0 -104
  82. package/cjs/entities/task-task-label.entity.js +0 -67
  83. package/cjs/entities/task.entity.js +0 -151
  84. package/cjs/gateways/index.js +0 -18
  85. package/cjs/gateways/task-board.gateway.js +0 -167
  86. package/cjs/gateways/task-board.gateway.spec.js +0 -243
  87. package/cjs/index.js +0 -26
  88. package/cjs/interfaces/index.js +0 -19
  89. package/cjs/interfaces/task-manager-module.interface.js +0 -4
  90. package/cjs/interfaces/task.interface.js +0 -4
  91. package/cjs/modules/index.js +0 -18
  92. package/cjs/modules/task-manager.module.js +0 -135
  93. package/cjs/modules/task-manager.module.spec.js +0 -144
  94. package/cjs/services/index.js +0 -25
  95. package/cjs/services/task-activity.service.js +0 -76
  96. package/cjs/services/task-activity.service.spec.js +0 -125
  97. package/cjs/services/task-board.service.js +0 -247
  98. package/cjs/services/task-board.service.spec.js +0 -465
  99. package/cjs/services/task-comment.service.js +0 -103
  100. package/cjs/services/task-comment.service.spec.js +0 -160
  101. package/cjs/services/task-label.service.js +0 -97
  102. package/cjs/services/task-label.service.spec.js +0 -138
  103. package/cjs/services/task-list.service.js +0 -130
  104. package/cjs/services/task-list.service.spec.js +0 -284
  105. package/cjs/services/task-manager-config.service.js +0 -69
  106. package/cjs/services/task-manager-config.service.spec.js +0 -98
  107. package/cjs/services/task-manager-datasource.provider.js +0 -84
  108. package/cjs/services/task-manager-datasource.provider.spec.js +0 -131
  109. package/cjs/services/task.service.js +0 -398
  110. package/cjs/services/task.service.spec.js +0 -700
  111. package/fesm/config/event-actions.js +0 -16
  112. package/fesm/config/message-keys.js +0 -65
  113. package/fesm/config/task-manager.constants.js +0 -1
  114. package/fesm/controllers/task-board.controller.js +0 -209
  115. package/fesm/controllers/task-board.controller.spec.js +0 -128
  116. package/fesm/controllers/task-comment.controller.js +0 -93
  117. package/fesm/controllers/task-comment.controller.spec.js +0 -82
  118. package/fesm/controllers/task-label.controller.js +0 -102
  119. package/fesm/controllers/task-label.controller.spec.js +0 -84
  120. package/fesm/controllers/task-list.controller.js +0 -148
  121. package/fesm/controllers/task-list.controller.spec.js +0 -108
  122. package/fesm/controllers/task.controller.js +0 -189
  123. package/fesm/controllers/task.controller.spec.js +0 -127
  124. package/fesm/docs/task-manager-swagger.config.js +0 -33
  125. package/fesm/docs/task-manager-swagger.config.spec.js +0 -24
  126. package/fesm/dtos/task-board.dto.js +0 -277
  127. package/fesm/dtos/task-comment.dto.js +0 -110
  128. package/fesm/dtos/task-label.dto.js +0 -99
  129. package/fesm/dtos/task-list.dto.js +0 -174
  130. package/fesm/dtos/task.dto.js +0 -337
  131. package/fesm/entities/index.spec.js +0 -26
  132. package/fesm/entities/task-activity.entity.js +0 -88
  133. package/fesm/entities/task-assignee.entity.js +0 -57
  134. package/fesm/entities/task-board-member.entity.js +0 -76
  135. package/fesm/entities/task-board-with-company.entity.js +0 -47
  136. package/fesm/entities/task-board.entity.js +0 -78
  137. package/fesm/entities/task-comment.entity.js +0 -70
  138. package/fesm/entities/task-label.entity.js +0 -62
  139. package/fesm/entities/task-list.entity.js +0 -94
  140. package/fesm/entities/task-task-label.entity.js +0 -57
  141. package/fesm/entities/task.entity.js +0 -133
  142. package/fesm/gateways/task-board.gateway.js +0 -157
  143. package/fesm/gateways/task-board.gateway.spec.js +0 -239
  144. package/fesm/interfaces/task-manager-module.interface.js +0 -1
  145. package/fesm/interfaces/task.interface.js +0 -1
  146. package/fesm/modules/task-manager.module.js +0 -125
  147. package/fesm/modules/task-manager.module.spec.js +0 -140
  148. package/fesm/services/task-activity.service.js +0 -66
  149. package/fesm/services/task-activity.service.spec.js +0 -121
  150. package/fesm/services/task-board.service.js +0 -237
  151. package/fesm/services/task-board.service.spec.js +0 -461
  152. package/fesm/services/task-comment.service.js +0 -93
  153. package/fesm/services/task-comment.service.spec.js +0 -156
  154. package/fesm/services/task-label.service.js +0 -87
  155. package/fesm/services/task-label.service.spec.js +0 -134
  156. package/fesm/services/task-list.service.js +0 -120
  157. package/fesm/services/task-list.service.spec.js +0 -280
  158. package/fesm/services/task-manager-config.service.js +0 -59
  159. package/fesm/services/task-manager-config.service.spec.js +0 -94
  160. package/fesm/services/task-manager-datasource.provider.js +0 -74
  161. package/fesm/services/task-manager-datasource.provider.spec.js +0 -127
  162. package/fesm/services/task.service.js +0 -388
  163. package/fesm/services/task.service.spec.js +0 -696
@@ -1,465 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- const _testing = require("@nestjs/testing");
6
- const _modules = require("@flusys/nestjs-shared/modules");
7
- const _repositorymock = require("@test-utils/mocks/repository.mock");
8
- const _loggedusermock = require("@test-utils/mocks/logged-user.mock");
9
- const _entities = require("../entities");
10
- const _taskboardservice = require("./task-board.service");
11
- const _taskmanagerconfigservice = require("./task-manager-config.service");
12
- const _taskmanagerdatasourceprovider = require("./task-manager-datasource.provider");
13
- function buildBoard(overrides = {}) {
14
- return {
15
- id: 'board-uuid-1',
16
- name: 'Sprint Board',
17
- description: null,
18
- color: '#3B82F6',
19
- isActive: true,
20
- settings: null,
21
- createdAt: new Date(),
22
- updatedAt: new Date(),
23
- deletedAt: null,
24
- createdById: null,
25
- updatedById: null,
26
- deletedById: null,
27
- ...overrides
28
- };
29
- }
30
- function buildMember(overrides = {}) {
31
- return {
32
- id: 'member-uuid-1',
33
- boardId: 'board-uuid-1',
34
- userId: 'user-uuid-1',
35
- role: _entities.BoardMemberRole.MEMBER,
36
- createdAt: new Date(),
37
- updatedAt: new Date(),
38
- deletedAt: null,
39
- createdById: null,
40
- updatedById: null,
41
- deletedById: null,
42
- ...overrides
43
- };
44
- }
45
- function mockQueryRunner(repo) {
46
- const qr = {
47
- connect: jest.fn().mockResolvedValue(undefined),
48
- startTransaction: jest.fn().mockResolvedValue(undefined),
49
- commitTransaction: jest.fn().mockResolvedValue(undefined),
50
- rollbackTransaction: jest.fn().mockResolvedValue(undefined),
51
- release: jest.fn().mockResolvedValue(undefined),
52
- manager: {
53
- save: jest.fn((_target, entities)=>Promise.resolve(entities))
54
- }
55
- };
56
- repo.manager.connection.createQueryRunner.mockReturnValue(qr);
57
- return qr;
58
- }
59
- describe('TaskBoardService', ()=>{
60
- const mockUtilsService = {
61
- clearCache: jest.fn(),
62
- getCacheKey: jest.fn().mockReturnValue('cache-key'),
63
- trackCacheKey: jest.fn()
64
- };
65
- // Call history is shared across tests in this file; reset it so each cache assertion is exact.
66
- beforeEach(()=>{
67
- mockUtilsService.clearCache.mockClear();
68
- });
69
- let service;
70
- let module;
71
- let mockRepo;
72
- let mockMemberRepo;
73
- let mockConfig;
74
- let mockDataSourceProvider;
75
- beforeEach(async ()=>{
76
- mockRepo = (0, _repositorymock.createMockRepository)();
77
- mockMemberRepo = (0, _repositorymock.createMockRepository)();
78
- mockConfig = {
79
- isCompanyFeatureEnabled: jest.fn().mockReturnValue(false)
80
- };
81
- mockDataSourceProvider = {
82
- getRepository: jest.fn((entity)=>{
83
- if (entity === _entities.TaskBoardMember) return Promise.resolve(mockMemberRepo);
84
- return Promise.resolve(mockRepo);
85
- }),
86
- getDataSource: jest.fn()
87
- };
88
- module = await _testing.Test.createTestingModule({
89
- providers: [
90
- _taskboardservice.TaskBoardService,
91
- {
92
- provide: 'CACHE_INSTANCE',
93
- useValue: {}
94
- },
95
- {
96
- provide: _modules.UtilsService,
97
- useValue: mockUtilsService
98
- },
99
- {
100
- provide: _taskmanagerconfigservice.TaskManagerConfigService,
101
- useValue: mockConfig
102
- },
103
- {
104
- provide: _taskmanagerdatasourceprovider.TaskManagerDataSourceProvider,
105
- useValue: mockDataSourceProvider
106
- }
107
- ]
108
- }).compile();
109
- service = await module.resolve(_taskboardservice.TaskBoardService);
110
- });
111
- describe('entity selection', ()=>{
112
- it('uses TaskBoard when the company feature is disabled', async ()=>{
113
- mockConfig.isCompanyFeatureEnabled.mockReturnValue(false);
114
- const built = await module.resolve(_taskboardservice.TaskBoardService);
115
- expect(built['_entity']).toBe(_entities.TaskBoard);
116
- });
117
- it('uses TaskBoardWithCompany when the company feature is enabled', async ()=>{
118
- mockConfig.isCompanyFeatureEnabled.mockReturnValue(true);
119
- const built = await module.resolve(_taskboardservice.TaskBoardService);
120
- expect(built['_entity']).toBe(_entities.TaskBoardWithCompany);
121
- });
122
- });
123
- describe('convertSingleDtoToEntity (via insert/update)', ()=>{
124
- it('creates a board applying default color and active flag', async ()=>{
125
- mockQueryRunner(mockRepo);
126
- const result = await service.insert({
127
- name: 'New Board'
128
- }, (0, _loggedusermock.buildMockUser)());
129
- expect(result).toEqual(expect.objectContaining({
130
- name: 'New Board',
131
- color: '#3B82F6',
132
- isActive: true
133
- }));
134
- expect(result.companyId).toBeUndefined();
135
- });
136
- it('stamps companyId from the user when the company feature is enabled', async ()=>{
137
- mockConfig.isCompanyFeatureEnabled.mockReturnValue(true);
138
- mockQueryRunner(mockRepo);
139
- const result = await service.insert({
140
- name: 'Company Board'
141
- }, (0, _loggedusermock.buildMockUser)({
142
- companyId: 'company-9'
143
- }));
144
- expect(result.companyId).toBe('company-9');
145
- });
146
- it('throws NotFoundException when updating a non-existent board', async ()=>{
147
- mockQueryRunner(mockRepo);
148
- mockRepo.findOne.mockResolvedValue(null);
149
- await expect(service.update({
150
- id: 'missing',
151
- name: 'Renamed'
152
- }, (0, _loggedusermock.buildMockUser)())).rejects.toThrow();
153
- });
154
- it('merges update fields, preserving description as null when explicitly cleared', async ()=>{
155
- mockQueryRunner(mockRepo);
156
- const existing = buildBoard({
157
- id: 'board-1',
158
- description: 'Old description'
159
- });
160
- mockRepo.findOne.mockResolvedValue(existing);
161
- const result = await service.update({
162
- id: 'board-1',
163
- description: null
164
- }, (0, _loggedusermock.buildMockUser)());
165
- expect(result.description).toBeNull();
166
- });
167
- });
168
- describe('afterInsertOperation', ()=>{
169
- it('adds the creating user as an OWNER member of every newly created board', async ()=>{
170
- mockQueryRunner(mockRepo);
171
- mockMemberRepo.create.mockImplementation((data)=>data);
172
- mockMemberRepo.save.mockResolvedValue([]);
173
- await service.insert({
174
- name: 'New Board'
175
- }, (0, _loggedusermock.buildMockUser)({
176
- id: 'creator-1'
177
- }));
178
- expect(mockMemberRepo.save).toHaveBeenCalledWith([
179
- expect.objectContaining({
180
- userId: 'creator-1',
181
- role: _entities.BoardMemberRole.OWNER,
182
- createdById: 'creator-1'
183
- })
184
- ]);
185
- });
186
- it('does nothing when no user is present (system-created board)', async ()=>{
187
- mockQueryRunner(mockRepo);
188
- await service.insert({
189
- name: 'System Board'
190
- }, null);
191
- expect(mockMemberRepo.save).not.toHaveBeenCalled();
192
- });
193
- });
194
- describe('getExtraManipulateQuery', ()=>{
195
- it('applies the company filter, current-user membership join, and aggregate subselects', async ()=>{
196
- const qb = (0, _repositorymock.createMockQueryBuilder)();
197
- qb.innerJoin = jest.fn().mockReturnThis();
198
- qb.addSelect = jest.fn().mockReturnThis();
199
- mockConfig.isCompanyFeatureEnabled.mockReturnValue(true);
200
- const user = (0, _loggedusermock.buildMockUser)({
201
- id: 'user-1',
202
- companyId: 'company-1'
203
- });
204
- const { isRaw } = await service.getExtraManipulateQuery(qb, {}, user);
205
- expect(qb.andWhere).toHaveBeenCalledWith('task_board.companyId = :companyId', {
206
- companyId: 'company-1'
207
- });
208
- expect(qb.innerJoin).toHaveBeenCalledWith('task_board_member', 'tbm_filter', expect.stringContaining('tbm_filter.user_id = :currentUserId'), {
209
- currentUserId: 'user-1'
210
- });
211
- expect(qb.addSelect).toHaveBeenCalledWith(expect.stringContaining('task_board_member'), 'total_members');
212
- expect(qb.addSelect).toHaveBeenCalledWith(expect.stringContaining('task_list'), 'total_lists');
213
- expect(qb.addSelect).toHaveBeenCalledWith(expect.stringContaining('FROM task t'), 'total_tasks');
214
- expect(isRaw).toBe(true);
215
- });
216
- it('skips the membership join when no user is provided', async ()=>{
217
- const qb = (0, _repositorymock.createMockQueryBuilder)();
218
- qb.innerJoin = jest.fn().mockReturnThis();
219
- qb.addSelect = jest.fn().mockReturnThis();
220
- await service.getExtraManipulateQuery(qb, {}, null);
221
- expect(qb.innerJoin).not.toHaveBeenCalled();
222
- });
223
- });
224
- describe('convertEntityToResponseDto', ()=>{
225
- it('passes through non-raw entities unchanged (default behavior)', ()=>{
226
- const board = buildBoard();
227
- const result = service.convertEntityToResponseDto(board, false);
228
- expect(result).toEqual(board);
229
- });
230
- it('strips the entity-name prefix and camelCases raw aggregate columns, converting numeric strings', ()=>{
231
- const raw = {
232
- task_board_id: 'board-1',
233
- task_board_name: 'Sprint Board',
234
- total_members: '3',
235
- total_lists: '2'
236
- };
237
- const result = service.convertEntityToResponseDto(raw, true);
238
- expect(result).toEqual({
239
- id: 'board-1',
240
- name: 'Sprint Board',
241
- totalMembers: 3,
242
- totalLists: 2
243
- });
244
- });
245
- });
246
- describe('addMember', ()=>{
247
- it('adds a new member with the requested role', async ()=>{
248
- mockRepo.findOne.mockResolvedValue(buildBoard({
249
- id: 'board-1'
250
- }));
251
- mockMemberRepo.findOne.mockResolvedValueOnce(null); // no active existing member
252
- mockMemberRepo.findOne.mockResolvedValueOnce(null); // no soft-deleted member either
253
- mockMemberRepo.create.mockImplementation((data)=>data);
254
- const created = buildMember({
255
- boardId: 'board-1',
256
- userId: 'user-2',
257
- role: _entities.BoardMemberRole.ADMIN
258
- });
259
- mockMemberRepo.save.mockResolvedValue(created);
260
- const result = await service.addMember({
261
- boardId: 'board-1',
262
- userId: 'user-2',
263
- role: _entities.BoardMemberRole.ADMIN
264
- }, (0, _loggedusermock.buildMockUser)({
265
- id: 'owner-1'
266
- }));
267
- expect(mockMemberRepo.create).toHaveBeenCalledWith(expect.objectContaining({
268
- boardId: 'board-1',
269
- userId: 'user-2',
270
- role: _entities.BoardMemberRole.ADMIN,
271
- createdById: 'owner-1'
272
- }));
273
- expect(result).toEqual(created);
274
- });
275
- it('invalidates the board list cache and the board entry (membership drives visibility and total_members)', async ()=>{
276
- mockRepo.findOne.mockResolvedValue(buildBoard({
277
- id: 'board-1'
278
- }));
279
- mockMemberRepo.findOne.mockResolvedValueOnce(null);
280
- mockMemberRepo.findOne.mockResolvedValueOnce(null);
281
- mockMemberRepo.create.mockImplementation((data)=>data);
282
- mockMemberRepo.save.mockResolvedValue(buildMember({
283
- boardId: 'board-1'
284
- }));
285
- await service.addMember({
286
- boardId: 'board-1',
287
- userId: 'user-2'
288
- }, (0, _loggedusermock.buildMockUser)());
289
- expect(mockUtilsService.clearCache).toHaveBeenCalledWith('task_board', expect.anything());
290
- expect(mockUtilsService.clearCache).toHaveBeenCalledWith('task_board', expect.anything(), 'board-1');
291
- });
292
- it('defaults the role to MEMBER when none is given', async ()=>{
293
- mockRepo.findOne.mockResolvedValue(buildBoard({
294
- id: 'board-1'
295
- }));
296
- mockMemberRepo.findOne.mockResolvedValueOnce(null);
297
- mockMemberRepo.findOne.mockResolvedValueOnce(null);
298
- mockMemberRepo.create.mockImplementation((data)=>data);
299
- mockMemberRepo.save.mockResolvedValue(buildMember());
300
- await service.addMember({
301
- boardId: 'board-1',
302
- userId: 'user-2'
303
- }, (0, _loggedusermock.buildMockUser)());
304
- expect(mockMemberRepo.create).toHaveBeenCalledWith(expect.objectContaining({
305
- role: _entities.BoardMemberRole.MEMBER
306
- }));
307
- });
308
- it('throws NotFoundException when the board does not exist', async ()=>{
309
- mockRepo.findOne.mockResolvedValue(null);
310
- await expect(service.addMember({
311
- boardId: 'missing-board',
312
- userId: 'user-2'
313
- }, (0, _loggedusermock.buildMockUser)())).rejects.toThrow();
314
- });
315
- it('throws BadRequestException when the user is already an active member', async ()=>{
316
- mockRepo.findOne.mockResolvedValue(buildBoard({
317
- id: 'board-1'
318
- }));
319
- mockMemberRepo.findOne.mockResolvedValueOnce(buildMember());
320
- await expect(service.addMember({
321
- boardId: 'board-1',
322
- userId: 'user-uuid-1'
323
- }, (0, _loggedusermock.buildMockUser)())).rejects.toThrow();
324
- });
325
- it('restores a soft-deleted membership instead of creating a duplicate row', async ()=>{
326
- mockRepo.findOne.mockResolvedValue(buildBoard({
327
- id: 'board-1'
328
- }));
329
- mockMemberRepo.findOne.mockResolvedValueOnce(null); // no active member
330
- const softDeleted = buildMember({
331
- id: 'member-old',
332
- deletedAt: new Date()
333
- });
334
- mockMemberRepo.findOne.mockResolvedValueOnce(softDeleted); // soft-deleted row found
335
- mockMemberRepo.restore.mockResolvedValue(undefined);
336
- mockMemberRepo.update.mockResolvedValue(undefined);
337
- const restored = buildMember({
338
- id: 'member-old',
339
- role: _entities.BoardMemberRole.ADMIN
340
- });
341
- mockMemberRepo.findOne.mockResolvedValueOnce(restored); // re-fetch after restore
342
- const result = await service.addMember({
343
- boardId: 'board-1',
344
- userId: 'user-uuid-1',
345
- role: _entities.BoardMemberRole.ADMIN
346
- }, (0, _loggedusermock.buildMockUser)());
347
- expect(mockMemberRepo.restore).toHaveBeenCalledWith({
348
- id: 'member-old'
349
- });
350
- expect(mockMemberRepo.update).toHaveBeenCalledWith({
351
- id: 'member-old'
352
- }, {
353
- role: _entities.BoardMemberRole.ADMIN
354
- });
355
- expect(mockMemberRepo.create).not.toHaveBeenCalled();
356
- expect(result).toEqual(restored);
357
- });
358
- });
359
- describe('removeMember', ()=>{
360
- it('soft-deletes an existing member', async ()=>{
361
- const member = buildMember({
362
- id: 'member-1'
363
- });
364
- mockMemberRepo.findOne.mockResolvedValue(member);
365
- await service.removeMember({
366
- boardId: 'board-1',
367
- userId: 'user-uuid-1'
368
- });
369
- expect(mockMemberRepo.update).toHaveBeenCalledWith({
370
- id: 'member-1'
371
- }, {
372
- deletedAt: expect.any(Date)
373
- });
374
- });
375
- it('invalidates the board list cache and the board entry', async ()=>{
376
- mockMemberRepo.findOne.mockResolvedValue(buildMember({
377
- id: 'member-1'
378
- }));
379
- await service.removeMember({
380
- boardId: 'board-1',
381
- userId: 'user-uuid-1'
382
- });
383
- expect(mockUtilsService.clearCache).toHaveBeenCalledWith('task_board', expect.anything());
384
- expect(mockUtilsService.clearCache).toHaveBeenCalledWith('task_board', expect.anything(), 'board-1');
385
- });
386
- it('throws NotFoundException when the member is not found', async ()=>{
387
- mockMemberRepo.findOne.mockResolvedValue(null);
388
- await expect(service.removeMember({
389
- boardId: 'board-1',
390
- userId: 'unknown-user'
391
- })).rejects.toThrow();
392
- });
393
- });
394
- function buildMembersQueryBuilder() {
395
- const qb = (0, _repositorymock.createMockQueryBuilder)();
396
- qb.leftJoin = jest.fn().mockReturnThis();
397
- qb.addSelect = jest.fn().mockReturnThis();
398
- qb.getRawAndEntities = jest.fn();
399
- return qb;
400
- }
401
- describe('getMembers', ()=>{
402
- it('returns members enriched with joined user name/email', async ()=>{
403
- const qb = buildMembersQueryBuilder();
404
- qb.getRawAndEntities.mockResolvedValue({
405
- entities: [
406
- buildMember({
407
- id: 'member-1',
408
- userId: 'user-1'
409
- })
410
- ],
411
- raw: [
412
- {
413
- userName: 'Alice',
414
- userEmail: 'alice@example.com'
415
- }
416
- ]
417
- });
418
- mockMemberRepo.createQueryBuilder.mockReturnValue(qb);
419
- const result = await service.getMembers('board-1');
420
- expect(result).toEqual([
421
- expect.objectContaining({
422
- id: 'member-1',
423
- userName: 'Alice',
424
- userEmail: 'alice@example.com'
425
- })
426
- ]);
427
- });
428
- it('defaults userName/userEmail to null when the joined user row is missing', async ()=>{
429
- const qb = buildMembersQueryBuilder();
430
- qb.getRawAndEntities.mockResolvedValue({
431
- entities: [
432
- buildMember({
433
- id: 'member-1'
434
- })
435
- ],
436
- raw: [
437
- {}
438
- ]
439
- });
440
- mockMemberRepo.createQueryBuilder.mockReturnValue(qb);
441
- const result = await service.getMembers('board-1');
442
- expect(result[0].userName).toBeNull();
443
- expect(result[0].userEmail).toBeNull();
444
- });
445
- });
446
- describe('isBoardMember', ()=>{
447
- it('returns true when an active membership row exists', async ()=>{
448
- mockMemberRepo.count.mockResolvedValue(1);
449
- const result = await service.isBoardMember('board-1', 'user-1');
450
- expect(result).toBe(true);
451
- expect(mockMemberRepo.count).toHaveBeenCalledWith({
452
- where: {
453
- boardId: 'board-1',
454
- userId: 'user-1',
455
- deletedAt: expect.anything()
456
- }
457
- });
458
- });
459
- it('returns false when no membership row exists', async ()=>{
460
- mockMemberRepo.count.mockResolvedValue(0);
461
- const result = await service.isBoardMember('board-1', 'stranger');
462
- expect(result).toBe(false);
463
- });
464
- });
465
- });
@@ -1,103 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "TaskCommentService", {
6
- enumerable: true,
7
- get: function() {
8
- return TaskCommentService;
9
- }
10
- });
11
- const _classes = require("@flusys/nestjs-shared/classes");
12
- const _modules = require("@flusys/nestjs-shared/modules");
13
- const _common = require("@nestjs/common");
14
- const _config = require("../config");
15
- const _entities = require("../entities");
16
- const _taskmanagerdatasourceprovider = require("./task-manager-datasource.provider");
17
- function _define_property(obj, key, value) {
18
- if (key in obj) {
19
- Object.defineProperty(obj, key, {
20
- value: value,
21
- enumerable: true,
22
- configurable: true,
23
- writable: true
24
- });
25
- } else {
26
- obj[key] = value;
27
- }
28
- return obj;
29
- }
30
- function _ts_decorate(decorators, target, key, desc) {
31
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
32
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
33
- 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;
34
- return c > 3 && r && Object.defineProperty(target, key, r), r;
35
- }
36
- function _ts_metadata(k, v) {
37
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
38
- }
39
- function _ts_param(paramIndex, decorator) {
40
- return function(target, key) {
41
- decorator(target, key, paramIndex);
42
- };
43
- }
44
- let TaskCommentService = class TaskCommentService extends _classes.ApiService {
45
- async convertSingleDtoToEntity(dto, user) {
46
- await this.ensureDataSourceRepository();
47
- let entity = {};
48
- if ('id' in dto && dto.id) {
49
- const existing = await this.repository.findOne({
50
- where: {
51
- id: dto.id
52
- }
53
- });
54
- if (!existing) throw new _common.NotFoundException({
55
- message: 'Comment not found',
56
- messageKey: _config.TASK_COMMENT_MESSAGES.NOT_FOUND
57
- });
58
- if (existing.userId !== user?.id) throw new _common.ForbiddenException({
59
- message: 'Cannot edit another user comment',
60
- messageKey: _config.TASK_COMMENT_MESSAGES.FORBIDDEN
61
- });
62
- entity = existing;
63
- }
64
- const taskId = ('taskId' in dto ? dto.taskId : undefined) ?? entity.taskId;
65
- return {
66
- ...entity,
67
- taskId,
68
- userId: entity.userId !== undefined ? entity.userId : user?.id ?? null,
69
- content: dto.content,
70
- parentCommentId: 'parentCommentId' in dto ? dto.parentCommentId ?? null : entity.parentCommentId ?? null
71
- };
72
- }
73
- async getFilterQuery(query, filter, _user) {
74
- for (const [key, value] of Object.entries(filter)){
75
- if (key === 'taskId') {
76
- query.andWhere('task_comment.taskId = :taskId', {
77
- taskId: value
78
- });
79
- }
80
- }
81
- return {
82
- query,
83
- isRaw: false
84
- };
85
- }
86
- constructor(cacheManager, utilsService, dataSourceProvider){
87
- super(_config.TASK_MANAGER_EVENT_ENTITIES.TASK_COMMENT, cacheManager, utilsService, TaskCommentService.name, false, _config.TASK_MANAGER_EVENT_MODULE, dataSourceProvider, _entities.TaskComment), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider;
88
- }
89
- };
90
- TaskCommentService = _ts_decorate([
91
- (0, _common.Injectable)({
92
- scope: _common.Scope.REQUEST
93
- }),
94
- _ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
95
- _ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
96
- _ts_param(2, (0, _common.Inject)(_taskmanagerdatasourceprovider.TaskManagerDataSourceProvider)),
97
- _ts_metadata("design:type", Function),
98
- _ts_metadata("design:paramtypes", [
99
- typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
100
- typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
101
- typeof _taskmanagerdatasourceprovider.TaskManagerDataSourceProvider === "undefined" ? Object : _taskmanagerdatasourceprovider.TaskManagerDataSourceProvider
102
- ])
103
- ], TaskCommentService);