@flusys/nestjs-task-manager 6.4.1 → 7.0.0-beta.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.
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Domain event actions published by the task manager module, alongside the CRUD
3
+ * lifecycle actions every ApiService emits.
4
+ */ "use strict";
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ function _export(target, all) {
9
+ for(var name in all)Object.defineProperty(target, name, {
10
+ enumerable: true,
11
+ get: Object.getOwnPropertyDescriptor(all, name).get
12
+ });
13
+ }
14
+ _export(exports, {
15
+ get TASK_MANAGER_EVENT_ACTIONS () {
16
+ return TASK_MANAGER_EVENT_ACTIONS;
17
+ },
18
+ get TASK_MANAGER_EVENT_ENTITIES () {
19
+ return TASK_MANAGER_EVENT_ENTITIES;
20
+ }
21
+ });
22
+ const TASK_MANAGER_EVENT_ACTIONS = {
23
+ MOVED: 'moved',
24
+ ASSIGNED: 'assigned',
25
+ REORDERED: 'reordered'
26
+ };
27
+ const TASK_MANAGER_EVENT_ENTITIES = {
28
+ TASK: 'task',
29
+ TASK_BOARD: 'task_board',
30
+ TASK_LIST: 'task_list',
31
+ TASK_LABEL: 'task_label',
32
+ TASK_COMMENT: 'task_comment'
33
+ };
@@ -2,8 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- _export_star(require("./task-manager.constants"), exports);
5
+ _export_star(require("./event-actions"), exports);
6
6
  _export_star(require("./message-keys"), exports);
7
+ _export_star(require("./task-manager.constants"), exports);
7
8
  function _export_star(from, to) {
8
9
  Object.keys(from).forEach(function(k) {
9
10
  if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
@@ -91,6 +91,7 @@ let TaskManagerModule = class TaskManagerModule {
91
91
  useValue: options
92
92
  });
93
93
  }
94
+ providers.push((0, _modules.createModuleEventsProvider)('task-manager', _taskmanagerconstants.TASK_MANAGER_MODULE_OPTIONS));
94
95
  return providers;
95
96
  }
96
97
  static createAsyncProviders(options) {
@@ -103,6 +103,12 @@ let TaskListService = class TaskListService extends _classes.ApiService {
103
103
  id
104
104
  })))
105
105
  ]);
106
+ await this.publishDomainAction(_config.TASK_MANAGER_EVENT_ACTIONS.REORDERED, {
107
+ ids: dto.orderedIds,
108
+ metadata: {
109
+ boardId: dto.boardId
110
+ }
111
+ });
106
112
  }
107
113
  constructor(cacheManager, utilsService, dataSourceProvider){
108
114
  super('task_list', cacheManager, utilsService, TaskListService.name, true, 'task-manager', _entities.TaskList, dataSourceProvider), _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;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
5
  const _testing = require("@nestjs/testing");
6
+ const _classes = require("@flusys/nestjs-shared/classes");
6
7
  const _modules = require("@flusys/nestjs-shared/modules");
7
8
  const _repositorymock = require("@test-utils/mocks/repository.mock");
8
9
  const _loggedusermock = require("@test-utils/mocks/logged-user.mock");
@@ -229,4 +230,55 @@ describe('TaskListService', ()=>{
229
230
  expect(mockRepo.update).not.toHaveBeenCalled();
230
231
  });
231
232
  });
233
+ describe('domain events', ()=>{
234
+ let publish;
235
+ beforeEach(()=>{
236
+ publish = jest.fn().mockResolvedValue(undefined);
237
+ _classes.EventBusRegistry.reset();
238
+ _classes.EventBusRegistry.setBus({
239
+ publish,
240
+ subscribe: jest.fn(),
241
+ close: jest.fn()
242
+ });
243
+ _classes.EventBusRegistry.configureModule('task-manager', {
244
+ enabled: true
245
+ });
246
+ });
247
+ afterEach(()=>{
248
+ _classes.EventBusRegistry.reset();
249
+ });
250
+ it('publishes task-manager.task_list.reordered with every list id', async ()=>{
251
+ await service.reorderLists({
252
+ boardId: 'board-1',
253
+ orderedIds: [
254
+ 'list-a',
255
+ 'list-b'
256
+ ]
257
+ });
258
+ expect(publish).toHaveBeenCalledWith(expect.objectContaining({
259
+ name: 'task-manager.task_list.reordered',
260
+ payload: expect.objectContaining({
261
+ ids: [
262
+ 'list-a',
263
+ 'list-b'
264
+ ],
265
+ metadata: {
266
+ boardId: 'board-1'
267
+ }
268
+ })
269
+ }));
270
+ });
271
+ it('does not publish when the task manager module has events disabled', async ()=>{
272
+ _classes.EventBusRegistry.configureModule('task-manager', {
273
+ enabled: false
274
+ });
275
+ await service.reorderLists({
276
+ boardId: 'board-1',
277
+ orderedIds: [
278
+ 'list-a'
279
+ ]
280
+ });
281
+ expect(publish).not.toHaveBeenCalled();
282
+ });
283
+ });
232
284
  });
@@ -195,6 +195,18 @@ let TaskService = class TaskService extends _classes.ApiService {
195
195
  saved
196
196
  ])
197
197
  ]);
198
+ await this.publishDomainAction(_config.TASK_MANAGER_EVENT_ACTIONS.MOVED, {
199
+ ids: [
200
+ saved.id
201
+ ],
202
+ metadata: {
203
+ boardId: saved.boardId,
204
+ fromListId: oldListId,
205
+ toListId: dto.targetListId,
206
+ position: saved.position
207
+ },
208
+ user
209
+ });
198
210
  return saved;
199
211
  }
200
212
  async assignTask(dto, user) {
@@ -238,6 +250,17 @@ let TaskService = class TaskService extends _classes.ApiService {
238
250
  ])
239
251
  ]);
240
252
  saved.assignees = await this.loadAssigneesForTask(saved.id);
253
+ await this.publishDomainAction(_config.TASK_MANAGER_EVENT_ACTIONS.ASSIGNED, {
254
+ ids: [
255
+ saved.id
256
+ ],
257
+ metadata: {
258
+ boardId: saved.boardId,
259
+ previousAssigneeIds: oldIds,
260
+ assigneeIds: dto.assigneeIds
261
+ },
262
+ user
263
+ });
241
264
  return saved;
242
265
  }
243
266
  async syncAssignees(taskId, userIds) {
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
5
  const _testing = require("@nestjs/testing");
6
+ const _classes = require("@flusys/nestjs-shared/classes");
6
7
  const _modules = require("@flusys/nestjs-shared/modules");
7
8
  const _repositorymock = require("@test-utils/mocks/repository.mock");
8
9
  const _loggedusermock = require("@test-utils/mocks/logged-user.mock");
@@ -631,4 +632,69 @@ describe('TaskService', ()=>{
631
632
  superGetAllSpy.mockRestore();
632
633
  });
633
634
  });
635
+ describe('domain events', ()=>{
636
+ let publish;
637
+ beforeEach(()=>{
638
+ publish = jest.fn().mockResolvedValue(undefined);
639
+ _classes.EventBusRegistry.reset();
640
+ _classes.EventBusRegistry.setBus({
641
+ publish,
642
+ subscribe: jest.fn(),
643
+ close: jest.fn()
644
+ });
645
+ _classes.EventBusRegistry.configureModule('task-manager', {
646
+ enabled: true
647
+ });
648
+ });
649
+ afterEach(()=>{
650
+ _classes.EventBusRegistry.reset();
651
+ });
652
+ it('publishes task-manager.task.moved with the source and target lists', async ()=>{
653
+ const task = buildTask({
654
+ id: 'task-1',
655
+ listId: 'list-old',
656
+ boardId: 'board-1',
657
+ position: 0
658
+ });
659
+ mockRepo.findOne.mockResolvedValue(task);
660
+ mockRepo.save.mockImplementation((t)=>Promise.resolve(t));
661
+ await service.moveTask({
662
+ taskId: 'task-1',
663
+ targetListId: 'list-new',
664
+ position: 3
665
+ }, (0, _loggedusermock.buildMockUser)({
666
+ id: 'mover-1'
667
+ }));
668
+ expect(publish).toHaveBeenCalledWith(expect.objectContaining({
669
+ name: 'task-manager.task.moved',
670
+ payload: expect.objectContaining({
671
+ ids: [
672
+ 'task-1'
673
+ ],
674
+ metadata: expect.objectContaining({
675
+ boardId: 'board-1',
676
+ fromListId: 'list-old',
677
+ toListId: 'list-new'
678
+ })
679
+ })
680
+ }));
681
+ });
682
+ it('does not publish when the task manager module has events disabled', async ()=>{
683
+ _classes.EventBusRegistry.configureModule('task-manager', {
684
+ enabled: false
685
+ });
686
+ const task = buildTask({
687
+ id: 'task-1',
688
+ listId: 'list-old',
689
+ boardId: 'board-1'
690
+ });
691
+ mockRepo.findOne.mockResolvedValue(task);
692
+ mockRepo.save.mockImplementation((t)=>Promise.resolve(t));
693
+ await service.moveTask({
694
+ taskId: 'task-1',
695
+ targetListId: 'list-new'
696
+ }, (0, _loggedusermock.buildMockUser)());
697
+ expect(publish).not.toHaveBeenCalled();
698
+ });
699
+ });
634
700
  });
@@ -0,0 +1,12 @@
1
+ export declare const TASK_MANAGER_EVENT_ACTIONS: {
2
+ readonly MOVED: "moved";
3
+ readonly ASSIGNED: "assigned";
4
+ readonly REORDERED: "reordered";
5
+ };
6
+ export declare const TASK_MANAGER_EVENT_ENTITIES: {
7
+ readonly TASK: "task";
8
+ readonly TASK_BOARD: "task_board";
9
+ readonly TASK_LIST: "task_list";
10
+ readonly TASK_LABEL: "task_label";
11
+ readonly TASK_COMMENT: "task_comment";
12
+ };
package/config/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- export * from './task-manager.constants';
1
+ export * from './event-actions';
2
2
  export * from './message-keys';
3
+ export * from './task-manager.constants';
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Domain event actions published by the task manager module, alongside the CRUD
3
+ * lifecycle actions every ApiService emits.
4
+ */ export const TASK_MANAGER_EVENT_ACTIONS = {
5
+ MOVED: 'moved',
6
+ ASSIGNED: 'assigned',
7
+ REORDERED: 'reordered'
8
+ };
9
+ /** Every entity the task manager module publishes under */ export const TASK_MANAGER_EVENT_ENTITIES = {
10
+ TASK: 'task',
11
+ TASK_BOARD: 'task_board',
12
+ TASK_LIST: 'task_list',
13
+ TASK_LABEL: 'task_label',
14
+ TASK_COMMENT: 'task_comment'
15
+ };
@@ -1,2 +1,3 @@
1
- export * from './task-manager.constants';
1
+ export * from './event-actions';
2
2
  export * from './message-keys';
3
+ export * from './task-manager.constants';
@@ -4,7 +4,7 @@ function _ts_decorate(decorators, target, key, desc) {
4
4
  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;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  }
7
- import { CacheModule, UtilsModule } from '@flusys/nestjs-shared/modules';
7
+ import { CacheModule, UtilsModule, createModuleEventsProvider } from '@flusys/nestjs-shared/modules';
8
8
  import { Module } from '@nestjs/common';
9
9
  import { JwtService } from '@nestjs/jwt';
10
10
  import { TASK_MANAGER_MODULE_OPTIONS } from '../config/task-manager.constants';
@@ -81,6 +81,7 @@ export class TaskManagerModule {
81
81
  useValue: options
82
82
  });
83
83
  }
84
+ providers.push(createModuleEventsProvider('task-manager', TASK_MANAGER_MODULE_OPTIONS));
84
85
  return providers;
85
86
  }
86
87
  static createAsyncProviders(options) {
@@ -28,7 +28,7 @@ function _ts_param(paramIndex, decorator) {
28
28
  import { ApiService, HybridCache } from '@flusys/nestjs-shared/classes';
29
29
  import { UtilsService } from '@flusys/nestjs-shared/modules';
30
30
  import { Inject, Injectable, NotFoundException, Scope } from '@nestjs/common';
31
- import { TASK_LIST_MESSAGES } from '../config';
31
+ import { TASK_LIST_MESSAGES, TASK_MANAGER_EVENT_ACTIONS } from '../config';
32
32
  import { TaskList } from '../entities';
33
33
  import { TaskManagerDataSourceProvider } from './task-manager-datasource.provider';
34
34
  export class TaskListService extends ApiService {
@@ -93,6 +93,12 @@ export class TaskListService extends ApiService {
93
93
  id
94
94
  })))
95
95
  ]);
96
+ await this.publishDomainAction(TASK_MANAGER_EVENT_ACTIONS.REORDERED, {
97
+ ids: dto.orderedIds,
98
+ metadata: {
99
+ boardId: dto.boardId
100
+ }
101
+ });
96
102
  }
97
103
  constructor(cacheManager, utilsService, dataSourceProvider){
98
104
  super('task_list', cacheManager, utilsService, TaskListService.name, true, 'task-manager', TaskList, dataSourceProvider), _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;
@@ -1,4 +1,5 @@
1
1
  import { Test } from '@nestjs/testing';
2
+ import { EventBusRegistry } from '@flusys/nestjs-shared/classes';
2
3
  import { UtilsService } from '@flusys/nestjs-shared/modules';
3
4
  import { createMockDataSourceProvider, createMockQueryBuilder, createMockRepository } from '@test-utils/mocks/repository.mock';
4
5
  import { buildMockUser } from '@test-utils/mocks/logged-user.mock';
@@ -225,4 +226,55 @@ describe('TaskListService', ()=>{
225
226
  expect(mockRepo.update).not.toHaveBeenCalled();
226
227
  });
227
228
  });
229
+ describe('domain events', ()=>{
230
+ let publish;
231
+ beforeEach(()=>{
232
+ publish = jest.fn().mockResolvedValue(undefined);
233
+ EventBusRegistry.reset();
234
+ EventBusRegistry.setBus({
235
+ publish,
236
+ subscribe: jest.fn(),
237
+ close: jest.fn()
238
+ });
239
+ EventBusRegistry.configureModule('task-manager', {
240
+ enabled: true
241
+ });
242
+ });
243
+ afterEach(()=>{
244
+ EventBusRegistry.reset();
245
+ });
246
+ it('publishes task-manager.task_list.reordered with every list id', async ()=>{
247
+ await service.reorderLists({
248
+ boardId: 'board-1',
249
+ orderedIds: [
250
+ 'list-a',
251
+ 'list-b'
252
+ ]
253
+ });
254
+ expect(publish).toHaveBeenCalledWith(expect.objectContaining({
255
+ name: 'task-manager.task_list.reordered',
256
+ payload: expect.objectContaining({
257
+ ids: [
258
+ 'list-a',
259
+ 'list-b'
260
+ ],
261
+ metadata: {
262
+ boardId: 'board-1'
263
+ }
264
+ })
265
+ }));
266
+ });
267
+ it('does not publish when the task manager module has events disabled', async ()=>{
268
+ EventBusRegistry.configureModule('task-manager', {
269
+ enabled: false
270
+ });
271
+ await service.reorderLists({
272
+ boardId: 'board-1',
273
+ orderedIds: [
274
+ 'list-a'
275
+ ]
276
+ });
277
+ expect(publish).not.toHaveBeenCalled();
278
+ });
279
+ });
228
280
  });
@@ -29,7 +29,7 @@ import { ApiService, HybridCache } from '@flusys/nestjs-shared/classes';
29
29
  import { UtilsService } from '@flusys/nestjs-shared/modules';
30
30
  import { BadRequestException, Inject, Injectable, NotFoundException, Scope } from '@nestjs/common';
31
31
  import { In, IsNull } from 'typeorm';
32
- import { TASK_MESSAGES } from '../config';
32
+ import { TASK_MANAGER_EVENT_ACTIONS, TASK_MESSAGES } from '../config';
33
33
  import { Task, TaskAssignee, TaskLabel, TaskTaskLabel } from '../entities';
34
34
  import { TaskActivityService } from './task-activity.service';
35
35
  import { TaskBoardService } from './task-board.service';
@@ -185,6 +185,18 @@ export class TaskService extends ApiService {
185
185
  saved
186
186
  ])
187
187
  ]);
188
+ await this.publishDomainAction(TASK_MANAGER_EVENT_ACTIONS.MOVED, {
189
+ ids: [
190
+ saved.id
191
+ ],
192
+ metadata: {
193
+ boardId: saved.boardId,
194
+ fromListId: oldListId,
195
+ toListId: dto.targetListId,
196
+ position: saved.position
197
+ },
198
+ user
199
+ });
188
200
  return saved;
189
201
  }
190
202
  async assignTask(dto, user) {
@@ -228,6 +240,17 @@ export class TaskService extends ApiService {
228
240
  ])
229
241
  ]);
230
242
  saved.assignees = await this.loadAssigneesForTask(saved.id);
243
+ await this.publishDomainAction(TASK_MANAGER_EVENT_ACTIONS.ASSIGNED, {
244
+ ids: [
245
+ saved.id
246
+ ],
247
+ metadata: {
248
+ boardId: saved.boardId,
249
+ previousAssigneeIds: oldIds,
250
+ assigneeIds: dto.assigneeIds
251
+ },
252
+ user
253
+ });
231
254
  return saved;
232
255
  }
233
256
  async syncAssignees(taskId, userIds) {
@@ -1,4 +1,5 @@
1
1
  import { Test } from '@nestjs/testing';
2
+ import { EventBusRegistry } from '@flusys/nestjs-shared/classes';
2
3
  import { UtilsService } from '@flusys/nestjs-shared/modules';
3
4
  import { createMockQueryBuilder, createMockRepository } from '@test-utils/mocks/repository.mock';
4
5
  import { buildMockUser } from '@test-utils/mocks/logged-user.mock';
@@ -627,4 +628,69 @@ describe('TaskService', ()=>{
627
628
  superGetAllSpy.mockRestore();
628
629
  });
629
630
  });
631
+ describe('domain events', ()=>{
632
+ let publish;
633
+ beforeEach(()=>{
634
+ publish = jest.fn().mockResolvedValue(undefined);
635
+ EventBusRegistry.reset();
636
+ EventBusRegistry.setBus({
637
+ publish,
638
+ subscribe: jest.fn(),
639
+ close: jest.fn()
640
+ });
641
+ EventBusRegistry.configureModule('task-manager', {
642
+ enabled: true
643
+ });
644
+ });
645
+ afterEach(()=>{
646
+ EventBusRegistry.reset();
647
+ });
648
+ it('publishes task-manager.task.moved with the source and target lists', async ()=>{
649
+ const task = buildTask({
650
+ id: 'task-1',
651
+ listId: 'list-old',
652
+ boardId: 'board-1',
653
+ position: 0
654
+ });
655
+ mockRepo.findOne.mockResolvedValue(task);
656
+ mockRepo.save.mockImplementation((t)=>Promise.resolve(t));
657
+ await service.moveTask({
658
+ taskId: 'task-1',
659
+ targetListId: 'list-new',
660
+ position: 3
661
+ }, buildMockUser({
662
+ id: 'mover-1'
663
+ }));
664
+ expect(publish).toHaveBeenCalledWith(expect.objectContaining({
665
+ name: 'task-manager.task.moved',
666
+ payload: expect.objectContaining({
667
+ ids: [
668
+ 'task-1'
669
+ ],
670
+ metadata: expect.objectContaining({
671
+ boardId: 'board-1',
672
+ fromListId: 'list-old',
673
+ toListId: 'list-new'
674
+ })
675
+ })
676
+ }));
677
+ });
678
+ it('does not publish when the task manager module has events disabled', async ()=>{
679
+ EventBusRegistry.configureModule('task-manager', {
680
+ enabled: false
681
+ });
682
+ const task = buildTask({
683
+ id: 'task-1',
684
+ listId: 'list-old',
685
+ boardId: 'board-1'
686
+ });
687
+ mockRepo.findOne.mockResolvedValue(task);
688
+ mockRepo.save.mockImplementation((t)=>Promise.resolve(t));
689
+ await service.moveTask({
690
+ taskId: 'task-1',
691
+ targetListId: 'list-new'
692
+ }, buildMockUser());
693
+ expect(publish).not.toHaveBeenCalled();
694
+ });
695
+ });
630
696
  });
@@ -1,7 +1,9 @@
1
1
  import { IBootstrapAppConfig, IDataSourceServiceOptions, IDynamicModuleConfig, IModuleOptionsFactory } from '@flusys/nestjs-core';
2
+ import { IModuleEventsConfig } from '@flusys/nestjs-shared/interfaces';
2
3
  import { ModuleMetadata, Type } from '@nestjs/common';
3
4
  export interface ITaskManagerModuleConfig extends IDataSourceServiceOptions {
4
5
  jwtSecret?: string;
6
+ events?: IModuleEventsConfig;
5
7
  }
6
8
  export interface TaskManagerModuleOptions extends IDynamicModuleConfig {
7
9
  bootstrapAppConfig?: IBootstrapAppConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-task-manager",
3
- "version": "6.4.1",
3
+ "version": "7.0.0-beta.1",
4
4
  "description": "Task management module with dynamic boards and real-time collaboration",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -85,7 +85,7 @@
85
85
  "socket.io": "^4.8.0"
86
86
  },
87
87
  "dependencies": {
88
- "@flusys/nestjs-core": "6.4.1",
89
- "@flusys/nestjs-shared": "6.4.1"
88
+ "@flusys/nestjs-core": "7.0.0-beta.1",
89
+ "@flusys/nestjs-shared": "7.0.0-beta.1"
90
90
  }
91
91
  }