@flusys/nestjs-task-manager 5.3.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 (137) hide show
  1. package/README.md +245 -0
  2. package/cjs/config/index.js +19 -0
  3. package/cjs/config/message-keys.js +92 -0
  4. package/cjs/config/task-manager.constants.js +11 -0
  5. package/cjs/controllers/index.js +22 -0
  6. package/cjs/controllers/task-board.controller.js +219 -0
  7. package/cjs/controllers/task-comment.controller.js +103 -0
  8. package/cjs/controllers/task-label.controller.js +112 -0
  9. package/cjs/controllers/task-list.controller.js +158 -0
  10. package/cjs/controllers/task.controller.js +199 -0
  11. package/cjs/docs/index.js +18 -0
  12. package/cjs/docs/task-manager-swagger.config.js +43 -0
  13. package/cjs/dtos/index.js +22 -0
  14. package/cjs/dtos/task-board.dto.js +310 -0
  15. package/cjs/dtos/task-comment.dto.js +131 -0
  16. package/cjs/dtos/task-label.dto.js +120 -0
  17. package/cjs/dtos/task-list.dto.js +198 -0
  18. package/cjs/dtos/task.dto.js +367 -0
  19. package/cjs/entities/index.js +72 -0
  20. package/cjs/entities/task-activity.entity.js +98 -0
  21. package/cjs/entities/task-assignee.entity.js +67 -0
  22. package/cjs/entities/task-board-member.entity.js +94 -0
  23. package/cjs/entities/task-board-with-company.entity.js +57 -0
  24. package/cjs/entities/task-board.entity.js +88 -0
  25. package/cjs/entities/task-comment.entity.js +80 -0
  26. package/cjs/entities/task-label.entity.js +72 -0
  27. package/cjs/entities/task-list.entity.js +104 -0
  28. package/cjs/entities/task-task-label.entity.js +67 -0
  29. package/cjs/entities/task.entity.js +151 -0
  30. package/cjs/gateways/index.js +18 -0
  31. package/cjs/gateways/task-board.gateway.js +199 -0
  32. package/cjs/index.js +26 -0
  33. package/cjs/interfaces/index.js +19 -0
  34. package/cjs/interfaces/task-manager-module.interface.js +4 -0
  35. package/cjs/interfaces/task.interface.js +4 -0
  36. package/cjs/modules/index.js +18 -0
  37. package/cjs/modules/task-manager.module.js +131 -0
  38. package/cjs/services/index.js +25 -0
  39. package/cjs/services/task-activity.service.js +76 -0
  40. package/cjs/services/task-board.service.js +235 -0
  41. package/cjs/services/task-comment.service.js +103 -0
  42. package/cjs/services/task-label.service.js +97 -0
  43. package/cjs/services/task-list.service.js +115 -0
  44. package/cjs/services/task-manager-config.service.js +69 -0
  45. package/cjs/services/task-manager-datasource.provider.js +84 -0
  46. package/cjs/services/task.service.js +359 -0
  47. package/config/index.d.ts +2 -0
  48. package/config/message-keys.d.ts +65 -0
  49. package/config/task-manager.constants.d.ts +1 -0
  50. package/controllers/index.d.ts +5 -0
  51. package/controllers/task-board.controller.d.ts +27 -0
  52. package/controllers/task-comment.controller.d.ts +22 -0
  53. package/controllers/task-label.controller.d.ts +22 -0
  54. package/controllers/task-list.controller.d.ts +26 -0
  55. package/controllers/task.controller.d.ts +28 -0
  56. package/docs/index.d.ts +1 -0
  57. package/docs/task-manager-swagger.config.d.ts +2 -0
  58. package/dtos/index.d.ts +5 -0
  59. package/dtos/task-board.dto.d.ts +44 -0
  60. package/dtos/task-comment.dto.d.ts +16 -0
  61. package/dtos/task-label.dto.d.ts +16 -0
  62. package/dtos/task-list.dto.d.ts +26 -0
  63. package/dtos/task.dto.d.ts +48 -0
  64. package/entities/index.d.ts +22 -0
  65. package/entities/task-activity.entity.d.ts +9 -0
  66. package/entities/task-assignee.entity.d.ts +5 -0
  67. package/entities/task-board-member.entity.d.ts +12 -0
  68. package/entities/task-board-with-company.entity.d.ts +4 -0
  69. package/entities/task-board.entity.d.ts +8 -0
  70. package/entities/task-comment.entity.d.ts +7 -0
  71. package/entities/task-label.entity.d.ts +6 -0
  72. package/entities/task-list.entity.d.ts +9 -0
  73. package/entities/task-task-label.entity.d.ts +5 -0
  74. package/entities/task.entity.d.ts +23 -0
  75. package/fesm/config/index.js +2 -0
  76. package/fesm/config/message-keys.js +65 -0
  77. package/fesm/config/task-manager.constants.js +1 -0
  78. package/fesm/controllers/index.js +5 -0
  79. package/fesm/controllers/task-board.controller.js +209 -0
  80. package/fesm/controllers/task-comment.controller.js +93 -0
  81. package/fesm/controllers/task-label.controller.js +102 -0
  82. package/fesm/controllers/task-list.controller.js +148 -0
  83. package/fesm/controllers/task.controller.js +189 -0
  84. package/fesm/docs/index.js +1 -0
  85. package/fesm/docs/task-manager-swagger.config.js +33 -0
  86. package/fesm/dtos/index.js +5 -0
  87. package/fesm/dtos/task-board.dto.js +277 -0
  88. package/fesm/dtos/task-comment.dto.js +110 -0
  89. package/fesm/dtos/task-label.dto.js +99 -0
  90. package/fesm/dtos/task-list.dto.js +174 -0
  91. package/fesm/dtos/task.dto.js +337 -0
  92. package/fesm/entities/index.js +46 -0
  93. package/fesm/entities/task-activity.entity.js +88 -0
  94. package/fesm/entities/task-assignee.entity.js +57 -0
  95. package/fesm/entities/task-board-member.entity.js +76 -0
  96. package/fesm/entities/task-board-with-company.entity.js +47 -0
  97. package/fesm/entities/task-board.entity.js +78 -0
  98. package/fesm/entities/task-comment.entity.js +70 -0
  99. package/fesm/entities/task-label.entity.js +62 -0
  100. package/fesm/entities/task-list.entity.js +94 -0
  101. package/fesm/entities/task-task-label.entity.js +57 -0
  102. package/fesm/entities/task.entity.js +133 -0
  103. package/fesm/gateways/index.js +1 -0
  104. package/fesm/gateways/task-board.gateway.js +148 -0
  105. package/fesm/index.js +9 -0
  106. package/fesm/interfaces/index.js +2 -0
  107. package/fesm/interfaces/task-manager-module.interface.js +1 -0
  108. package/fesm/interfaces/task.interface.js +1 -0
  109. package/fesm/modules/index.js +1 -0
  110. package/fesm/modules/task-manager.module.js +121 -0
  111. package/fesm/services/index.js +8 -0
  112. package/fesm/services/task-activity.service.js +66 -0
  113. package/fesm/services/task-board.service.js +225 -0
  114. package/fesm/services/task-comment.service.js +93 -0
  115. package/fesm/services/task-label.service.js +87 -0
  116. package/fesm/services/task-list.service.js +105 -0
  117. package/fesm/services/task-manager-config.service.js +59 -0
  118. package/fesm/services/task-manager-datasource.provider.js +74 -0
  119. package/fesm/services/task.service.js +349 -0
  120. package/gateways/index.d.ts +1 -0
  121. package/gateways/task-board.gateway.d.ts +22 -0
  122. package/index.d.ts +9 -0
  123. package/interfaces/index.d.ts +2 -0
  124. package/interfaces/task-manager-module.interface.d.ts +19 -0
  125. package/interfaces/task.interface.d.ts +52 -0
  126. package/modules/index.d.ts +1 -0
  127. package/modules/task-manager.module.d.ts +8 -0
  128. package/package.json +91 -0
  129. package/services/index.d.ts +8 -0
  130. package/services/task-activity.service.d.ts +8 -0
  131. package/services/task-board.service.d.ts +32 -0
  132. package/services/task-comment.service.d.ts +18 -0
  133. package/services/task-label.service.d.ts +18 -0
  134. package/services/task-list.service.d.ts +19 -0
  135. package/services/task-manager-config.service.d.ts +12 -0
  136. package/services/task-manager-datasource.provider.d.ts +18 -0
  137. package/services/task.service.d.ts +44 -0
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "TaskManagerConfigService", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return TaskManagerConfigService;
9
+ }
10
+ });
11
+ const _common = require("@nestjs/common");
12
+ const _taskmanagerconstants = require("../config/task-manager.constants");
13
+ const _interfaces = require("../interfaces");
14
+ function _define_property(obj, key, value) {
15
+ if (key in obj) {
16
+ Object.defineProperty(obj, key, {
17
+ value: value,
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true
21
+ });
22
+ } else {
23
+ obj[key] = value;
24
+ }
25
+ return obj;
26
+ }
27
+ function _ts_decorate(decorators, target, key, desc) {
28
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
29
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
30
+ 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;
31
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
32
+ }
33
+ function _ts_metadata(k, v) {
34
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
35
+ }
36
+ function _ts_param(paramIndex, decorator) {
37
+ return function(target, key) {
38
+ decorator(target, key, paramIndex);
39
+ };
40
+ }
41
+ let TaskManagerConfigService = class TaskManagerConfigService {
42
+ isCompanyFeatureEnabled() {
43
+ return this.options.bootstrapAppConfig?.enableCompanyFeature ?? false;
44
+ }
45
+ getDatabaseMode() {
46
+ return this.options.bootstrapAppConfig?.databaseMode ?? 'single';
47
+ }
48
+ isMultiTenant() {
49
+ return this.getDatabaseMode() === 'multi-tenant';
50
+ }
51
+ getJwtSecret() {
52
+ return this.options.config?.jwtSecret;
53
+ }
54
+ getOptions() {
55
+ return this.options;
56
+ }
57
+ constructor(options){
58
+ _define_property(this, "options", void 0);
59
+ this.options = options;
60
+ }
61
+ };
62
+ TaskManagerConfigService = _ts_decorate([
63
+ (0, _common.Injectable)(),
64
+ _ts_param(0, (0, _common.Inject)(_taskmanagerconstants.TASK_MANAGER_MODULE_OPTIONS)),
65
+ _ts_metadata("design:type", Function),
66
+ _ts_metadata("design:paramtypes", [
67
+ typeof _interfaces.TaskManagerModuleOptions === "undefined" ? Object : _interfaces.TaskManagerModuleOptions
68
+ ])
69
+ ], TaskManagerConfigService);
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "TaskManagerDataSourceProvider", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return TaskManagerDataSourceProvider;
9
+ }
10
+ });
11
+ const _modules = require("@flusys/nestjs-shared/modules");
12
+ const _common = require("@nestjs/common");
13
+ const _core = require("@nestjs/core");
14
+ const _express = require("express");
15
+ const _entities = require("../entities");
16
+ const _taskmanagerconfigservice = require("./task-manager-config.service");
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 TaskManagerDataSourceProvider = class TaskManagerDataSourceProvider extends _modules.MultiTenantDataSourceService {
45
+ static buildParentOptions(options) {
46
+ return {
47
+ bootstrapAppConfig: options.bootstrapAppConfig,
48
+ defaultDatabaseConfig: options.config?.defaultDatabaseConfig,
49
+ tenantDefaultDatabaseConfig: options.config?.tenantDefaultDatabaseConfig,
50
+ tenants: options.config?.tenants
51
+ };
52
+ }
53
+ getEnableCompanyFeatureForTenant(tenant) {
54
+ return tenant?.enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
55
+ }
56
+ async createDataSourceFromConfig(config) {
57
+ const currentTenant = this.getCurrentTenant();
58
+ const enableCompanyFeature = this.getEnableCompanyFeatureForTenant(currentTenant ?? undefined);
59
+ const entities = (0, _entities.getTaskManagerEntitiesByConfig)(enableCompanyFeature);
60
+ return super.createDataSourceFromConfig(config, entities);
61
+ }
62
+ constructor(configService, request){
63
+ super(TaskManagerDataSourceProvider.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0), this.configService = configService;
64
+ }
65
+ };
66
+ _define_property(TaskManagerDataSourceProvider, "tenantConnections", new Map());
67
+ _define_property(TaskManagerDataSourceProvider, "singleDataSource", null);
68
+ _define_property(TaskManagerDataSourceProvider, "tenantsRegistry", new Map());
69
+ _define_property(TaskManagerDataSourceProvider, "initialized", false);
70
+ _define_property(TaskManagerDataSourceProvider, "connectionLocks", new Map());
71
+ _define_property(TaskManagerDataSourceProvider, "singleConnectionLock", null);
72
+ TaskManagerDataSourceProvider = _ts_decorate([
73
+ (0, _common.Injectable)({
74
+ scope: _common.Scope.REQUEST
75
+ }),
76
+ _ts_param(0, (0, _common.Inject)(_taskmanagerconfigservice.TaskManagerConfigService)),
77
+ _ts_param(1, (0, _common.Optional)()),
78
+ _ts_param(1, (0, _common.Inject)(_core.REQUEST)),
79
+ _ts_metadata("design:type", Function),
80
+ _ts_metadata("design:paramtypes", [
81
+ typeof _taskmanagerconfigservice.TaskManagerConfigService === "undefined" ? Object : _taskmanagerconfigservice.TaskManagerConfigService,
82
+ typeof _express.Request === "undefined" ? Object : _express.Request
83
+ ])
84
+ ], TaskManagerDataSourceProvider);
@@ -0,0 +1,359 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "TaskService", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return TaskService;
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 _typeorm = require("typeorm");
15
+ const _config = require("../config");
16
+ const _entities = require("../entities");
17
+ const _taskactivityservice = require("./task-activity.service");
18
+ const _taskboardservice = require("./task-board.service");
19
+ const _taskmanagerdatasourceprovider = require("./task-manager-datasource.provider");
20
+ function _define_property(obj, key, value) {
21
+ if (key in obj) {
22
+ Object.defineProperty(obj, key, {
23
+ value: value,
24
+ enumerable: true,
25
+ configurable: true,
26
+ writable: true
27
+ });
28
+ } else {
29
+ obj[key] = value;
30
+ }
31
+ return obj;
32
+ }
33
+ function _ts_decorate(decorators, target, key, desc) {
34
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
35
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
36
+ 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;
37
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
38
+ }
39
+ function _ts_metadata(k, v) {
40
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
41
+ }
42
+ function _ts_param(paramIndex, decorator) {
43
+ return function(target, key) {
44
+ decorator(target, key, paramIndex);
45
+ };
46
+ }
47
+ let TaskService = class TaskService extends _classes.ApiService {
48
+ async convertSingleDtoToEntity(dto, user) {
49
+ await this.ensureDataSourceRepository();
50
+ let entity = {};
51
+ if ('id' in dto && dto.id) {
52
+ const existing = await this.repository.findOne({
53
+ where: {
54
+ id: dto.id
55
+ }
56
+ });
57
+ if (!existing) throw new _common.NotFoundException({
58
+ message: 'Task not found',
59
+ messageKey: _config.TASK_MESSAGES.NOT_FOUND
60
+ });
61
+ entity = existing;
62
+ }
63
+ if (dto.assigneeIds?.length) {
64
+ const boardId = dto.boardId ?? entity.boardId;
65
+ const memberChecks = await Promise.all(dto.assigneeIds.map((id)=>this.boardService.isBoardMember(boardId, id)));
66
+ if (memberChecks.some((isMember)=>!isMember)) {
67
+ throw new _common.BadRequestException({
68
+ message: 'Assignee is not a board member',
69
+ messageKey: _config.TASK_MESSAGES.ASSIGNEE_NOT_BOARD_MEMBER
70
+ });
71
+ }
72
+ }
73
+ if ('labelIds' in dto && dto.labelIds !== undefined) {
74
+ this.pendingLabelIds.push(dto.labelIds ?? []);
75
+ }
76
+ if ('assigneeIds' in dto && dto.assigneeIds !== undefined) {
77
+ this.pendingAssigneeIds.push(dto.assigneeIds ?? []);
78
+ } else {
79
+ this.pendingAssigneeIds.push(undefined);
80
+ }
81
+ return {
82
+ ...entity,
83
+ boardId: dto.boardId ?? entity.boardId,
84
+ listId: dto.listId ?? entity.listId,
85
+ title: dto.title ?? entity.title,
86
+ description: dto.description !== undefined ? dto.description ?? null : entity.description ?? null,
87
+ priority: dto.priority ?? entity.priority ?? 'MEDIUM',
88
+ dueDate: dto.dueDate !== undefined ? dto.dueDate ?? null : entity.dueDate ?? null,
89
+ position: entity.position ?? 0,
90
+ reporterId: entity.reporterId ?? user?.id ?? null,
91
+ parentTaskId: dto.parentTaskId !== undefined ? dto.parentTaskId ?? null : entity.parentTaskId ?? null,
92
+ estimatedHours: dto.estimatedHours !== undefined ? dto.estimatedHours ?? null : entity.estimatedHours ?? null
93
+ };
94
+ }
95
+ async afterInsertOperation(entities, user, _qr) {
96
+ await Promise.all(entities.map(async (entity, i)=>{
97
+ const assigneeIds = this.pendingAssigneeIds[i] ?? [];
98
+ const syncOps = [
99
+ this.syncLabels(entity.id, this.pendingLabelIds[i] ?? [])
100
+ ];
101
+ if (assigneeIds.length > 0) {
102
+ syncOps.push(this.syncAssignees(entity.id, assigneeIds));
103
+ }
104
+ await Promise.all(syncOps);
105
+ }));
106
+ await Promise.all([
107
+ this.loadLabelsForTasks(entities),
108
+ this.loadAssigneesForTasks(entities)
109
+ ]);
110
+ await Promise.all(entities.map((entity)=>this.activityService.log(entity.id, entity.boardId, user?.id ?? null, 'task.created', null, {
111
+ title: entity.title
112
+ })));
113
+ this.pendingLabelIds = [];
114
+ this.pendingAssigneeIds = [];
115
+ }
116
+ async afterUpdateOperation(entities, _user, _qr) {
117
+ await Promise.all(entities.map(async (entity, i)=>{
118
+ const syncOps = [];
119
+ if (this.pendingLabelIds[i] !== undefined) {
120
+ syncOps.push(this.syncLabels(entity.id, this.pendingLabelIds[i]));
121
+ }
122
+ if (this.pendingAssigneeIds[i] !== undefined) {
123
+ syncOps.push(this.syncAssignees(entity.id, this.pendingAssigneeIds[i]));
124
+ }
125
+ if (syncOps.length > 0) await Promise.all(syncOps);
126
+ }));
127
+ await this.loadLabelsForTasks(entities);
128
+ const entitiesWithAssigneeUpdates = entities.filter((_, i)=>this.pendingAssigneeIds[i] !== undefined);
129
+ if (entitiesWithAssigneeUpdates.length > 0) {
130
+ await this.loadAssigneesForTasks(entitiesWithAssigneeUpdates);
131
+ }
132
+ this.pendingLabelIds = [];
133
+ this.pendingAssigneeIds = [];
134
+ }
135
+ async getFilterQuery(query, filter, _user) {
136
+ for (const [key, value] of Object.entries(filter)){
137
+ if (key === 'boardId') {
138
+ query.andWhere('task.boardId = :boardId', {
139
+ boardId: value
140
+ });
141
+ } else if (key === 'listId') {
142
+ query.andWhere('task.listId = :listId', {
143
+ listId: value
144
+ });
145
+ } else if (key === 'assigneeId') {
146
+ query.innerJoin('task_assignee', 'ta', 'ta.task_id = task.id').andWhere('ta.user_id = :assigneeUserId', {
147
+ assigneeUserId: value
148
+ });
149
+ } else if (key === 'priority') {
150
+ query.andWhere('task.priority = :priority', {
151
+ priority: value
152
+ });
153
+ }
154
+ }
155
+ return {
156
+ query,
157
+ isRaw: false
158
+ };
159
+ }
160
+ async getAll(search, filterAndPaginationDto, user) {
161
+ const result = await super.getAll(search, filterAndPaginationDto, user);
162
+ await this.loadLabelsForTasks(result.data);
163
+ await this.loadAssigneesForTasks(result.data);
164
+ return result;
165
+ }
166
+ async moveTask(dto, user) {
167
+ await this.ensureDataSourceRepository();
168
+ const task = await this.repository.findOne({
169
+ where: {
170
+ id: dto.taskId,
171
+ deletedAt: (0, _typeorm.IsNull)()
172
+ }
173
+ });
174
+ if (!task) throw new _common.NotFoundException({
175
+ message: 'Task not found',
176
+ messageKey: _config.TASK_MESSAGES.NOT_FOUND
177
+ });
178
+ const oldListId = task.listId;
179
+ task.listId = dto.targetListId;
180
+ task.position = dto.position ?? 0;
181
+ task.updatedById = user.id;
182
+ const saved = await this.repository.save(task);
183
+ await this.activityService.log(task.id, task.boardId, user.id, 'task.moved', {
184
+ listId: oldListId
185
+ }, {
186
+ listId: dto.targetListId
187
+ });
188
+ return saved;
189
+ }
190
+ async assignTask(dto, user) {
191
+ await this.ensureDataSourceRepository();
192
+ const task = await this.repository.findOne({
193
+ where: {
194
+ id: dto.taskId,
195
+ deletedAt: (0, _typeorm.IsNull)()
196
+ }
197
+ });
198
+ if (!task) throw new _common.NotFoundException({
199
+ message: 'Task not found',
200
+ messageKey: _config.TASK_MESSAGES.NOT_FOUND
201
+ });
202
+ const memberChecks = await Promise.all(dto.assigneeIds.map((id)=>this.boardService.isBoardMember(task.boardId, id)));
203
+ if (memberChecks.some((isMember)=>!isMember)) {
204
+ throw new _common.BadRequestException({
205
+ message: 'Assignee is not a board member',
206
+ messageKey: _config.TASK_MESSAGES.ASSIGNEE_NOT_BOARD_MEMBER
207
+ });
208
+ }
209
+ const assigneeRepo = await this.ensureAssigneeRepository();
210
+ const oldRows = await assigneeRepo.find({
211
+ where: {
212
+ taskId: dto.taskId
213
+ }
214
+ });
215
+ const oldIds = oldRows.map((r)=>r.userId);
216
+ await this.syncAssignees(dto.taskId, dto.assigneeIds);
217
+ task.updatedById = user.id;
218
+ const saved = await this.repository.save(task);
219
+ await this.activityService.log(task.id, task.boardId, user.id, 'task.assigned', {
220
+ assigneeIds: oldIds
221
+ }, {
222
+ assigneeIds: dto.assigneeIds
223
+ });
224
+ saved.assignees = await this.loadAssigneesForTask(saved.id);
225
+ return saved;
226
+ }
227
+ async syncAssignees(taskId, userIds) {
228
+ const repo = await this.ensureAssigneeRepository();
229
+ await repo.delete({
230
+ taskId
231
+ });
232
+ if (userIds.length > 0) {
233
+ await repo.save(userIds.map((userId)=>repo.create({
234
+ taskId,
235
+ userId
236
+ })));
237
+ }
238
+ }
239
+ async syncLabels(taskId, labelIds) {
240
+ const labelRepo = await this.ensureLabelRepository();
241
+ await labelRepo.delete({
242
+ taskId
243
+ });
244
+ if (labelIds.length > 0) {
245
+ const rows = labelIds.map((labelId)=>labelRepo.create({
246
+ taskId,
247
+ labelId
248
+ }));
249
+ await labelRepo.save(rows);
250
+ }
251
+ }
252
+ async loadLabelsForTasks(tasks) {
253
+ if (tasks.length === 0) return;
254
+ const junctionRepo = await this.ensureLabelRepository();
255
+ const fullRepo = await this.ensureFullLabelRepository();
256
+ const taskIds = tasks.map((t)=>t.id);
257
+ const junctionRows = await junctionRepo.find({
258
+ where: {
259
+ taskId: (0, _typeorm.In)(taskIds),
260
+ deletedAt: (0, _typeorm.IsNull)()
261
+ }
262
+ });
263
+ const uniqueLabelIds = [
264
+ ...new Set(junctionRows.map((r)=>r.labelId))
265
+ ];
266
+ const fullLabels = uniqueLabelIds.length > 0 ? await fullRepo.find({
267
+ where: {
268
+ id: (0, _typeorm.In)(uniqueLabelIds),
269
+ deletedAt: (0, _typeorm.IsNull)()
270
+ }
271
+ }) : [];
272
+ const labelById = new Map(fullLabels.map((l)=>[
273
+ l.id,
274
+ l
275
+ ]));
276
+ const byTask = new Map();
277
+ for (const row of junctionRows){
278
+ const label = labelById.get(row.labelId);
279
+ if (!label) continue;
280
+ const list = byTask.get(row.taskId) ?? [];
281
+ list.push(label);
282
+ byTask.set(row.taskId, list);
283
+ }
284
+ for (const task of tasks){
285
+ const taskLabels = byTask.get(task.id) ?? [];
286
+ task.labelIds = taskLabels.map((l)=>l.id);
287
+ task.labels = taskLabels;
288
+ }
289
+ }
290
+ async loadAssigneesForTasks(tasks) {
291
+ if (tasks.length === 0) return;
292
+ const repo = await this.ensureAssigneeRepository();
293
+ const taskIds = tasks.map((t)=>t.id);
294
+ const rows = await repo.createQueryBuilder('ta').select('ta.task_id', 'taskId').addSelect('ta.user_id', 'userId').addSelect('u.name', 'userName').leftJoin('app_user', 'u', 'u.id = ta.user_id').where('ta.task_id IN (:...taskIds)', {
295
+ taskIds
296
+ }).getRawMany();
297
+ const byTask = new Map();
298
+ for (const row of rows){
299
+ const list = byTask.get(row.taskId) ?? [];
300
+ list.push({
301
+ userId: row.userId,
302
+ userName: row.userName ?? null
303
+ });
304
+ byTask.set(row.taskId, list);
305
+ }
306
+ for (const task of tasks){
307
+ task.assignees = byTask.get(task.id) ?? [];
308
+ }
309
+ }
310
+ async loadAssigneesForTask(taskId) {
311
+ const repo = await this.ensureAssigneeRepository();
312
+ const rows = await repo.createQueryBuilder('ta').select('ta.user_id', 'userId').addSelect('u.name', 'userName').leftJoin('app_user', 'u', 'u.id = ta.user_id').where('ta.task_id = :taskId', {
313
+ taskId
314
+ }).getRawMany();
315
+ return rows.map((r)=>({
316
+ userId: r.userId,
317
+ userName: r.userName ?? null
318
+ }));
319
+ }
320
+ async ensureLabelRepository() {
321
+ if (!this.taskLabelRepository) {
322
+ this.taskLabelRepository = await this.dataSourceProvider.getRepository(_entities.TaskTaskLabel);
323
+ }
324
+ return this.taskLabelRepository;
325
+ }
326
+ async ensureFullLabelRepository() {
327
+ if (!this.fullLabelRepository) {
328
+ this.fullLabelRepository = await this.dataSourceProvider.getRepository(_entities.TaskLabel);
329
+ }
330
+ return this.fullLabelRepository;
331
+ }
332
+ async ensureAssigneeRepository() {
333
+ if (!this.taskAssigneeRepository) {
334
+ this.taskAssigneeRepository = await this.dataSourceProvider.getRepository(_entities.TaskAssignee);
335
+ }
336
+ return this.taskAssigneeRepository;
337
+ }
338
+ constructor(cacheManager, utilsService, dataSourceProvider, boardService, activityService){
339
+ super('task', cacheManager, utilsService, TaskService.name, true, 'task-manager', _entities.Task, dataSourceProvider), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "boardService", void 0), _define_property(this, "activityService", void 0), _define_property(this, "taskLabelRepository", void 0), _define_property(this, "fullLabelRepository", void 0), _define_property(this, "taskAssigneeRepository", void 0), _define_property(this, "pendingLabelIds", void 0), _define_property(this, "pendingAssigneeIds", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider, this.boardService = boardService, this.activityService = activityService, this.taskLabelRepository = null, this.fullLabelRepository = null, this.taskAssigneeRepository = null, this.pendingLabelIds = [], this.pendingAssigneeIds = [];
340
+ }
341
+ };
342
+ TaskService = _ts_decorate([
343
+ (0, _common.Injectable)({
344
+ scope: _common.Scope.REQUEST
345
+ }),
346
+ _ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
347
+ _ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
348
+ _ts_param(2, (0, _common.Inject)(_taskmanagerdatasourceprovider.TaskManagerDataSourceProvider)),
349
+ _ts_param(3, (0, _common.Inject)(_taskboardservice.TaskBoardService)),
350
+ _ts_param(4, (0, _common.Inject)(_taskactivityservice.TaskActivityService)),
351
+ _ts_metadata("design:type", Function),
352
+ _ts_metadata("design:paramtypes", [
353
+ typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
354
+ typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
355
+ typeof _taskmanagerdatasourceprovider.TaskManagerDataSourceProvider === "undefined" ? Object : _taskmanagerdatasourceprovider.TaskManagerDataSourceProvider,
356
+ typeof _taskboardservice.TaskBoardService === "undefined" ? Object : _taskboardservice.TaskBoardService,
357
+ typeof _taskactivityservice.TaskActivityService === "undefined" ? Object : _taskactivityservice.TaskActivityService
358
+ ])
359
+ ], TaskService);
@@ -0,0 +1,2 @@
1
+ export * from './task-manager.constants';
2
+ export * from './message-keys';
@@ -0,0 +1,65 @@
1
+ export declare const TASK_BOARD_MESSAGES: {
2
+ readonly NOT_FOUND: "task.board.not.found";
3
+ readonly CREATE_SUCCESS: "task.board.create.success";
4
+ readonly CREATE_MANY_SUCCESS: "task.board.create.many.success";
5
+ readonly GET_SUCCESS: "task.board.get.success";
6
+ readonly GET_ALL_SUCCESS: "task.board.get.all.success";
7
+ readonly UPDATE_SUCCESS: "task.board.update.success";
8
+ readonly UPDATE_MANY_SUCCESS: "task.board.update.many.success";
9
+ readonly DELETE_SUCCESS: "task.board.delete.success";
10
+ readonly RESTORE_SUCCESS: "task.board.restore.success";
11
+ readonly MEMBER_ADDED: "task.board.member.added";
12
+ readonly MEMBER_REMOVED: "task.board.member.removed";
13
+ readonly MEMBER_NOT_FOUND: "task.board.member.not.found";
14
+ readonly MEMBER_ALREADY_EXISTS: "task.board.member.already.exists";
15
+ readonly MEMBER_GET_ALL_SUCCESS: "task.board.member.get.all.success";
16
+ };
17
+ export declare const TASK_LIST_MESSAGES: {
18
+ readonly NOT_FOUND: "task.list.not.found";
19
+ readonly CREATE_SUCCESS: "task.list.create.success";
20
+ readonly CREATE_MANY_SUCCESS: "task.list.create.many.success";
21
+ readonly GET_SUCCESS: "task.list.get.success";
22
+ readonly GET_ALL_SUCCESS: "task.list.get.all.success";
23
+ readonly UPDATE_SUCCESS: "task.list.update.success";
24
+ readonly UPDATE_MANY_SUCCESS: "task.list.update.many.success";
25
+ readonly DELETE_SUCCESS: "task.list.delete.success";
26
+ readonly RESTORE_SUCCESS: "task.list.restore.success";
27
+ readonly REORDER_SUCCESS: "task.list.reorder.success";
28
+ };
29
+ export declare const TASK_MESSAGES: {
30
+ readonly NOT_FOUND: "task.not.found";
31
+ readonly CREATE_SUCCESS: "task.create.success";
32
+ readonly CREATE_MANY_SUCCESS: "task.create.many.success";
33
+ readonly GET_SUCCESS: "task.get.success";
34
+ readonly GET_ALL_SUCCESS: "task.get.all.success";
35
+ readonly UPDATE_SUCCESS: "task.update.success";
36
+ readonly UPDATE_MANY_SUCCESS: "task.update.many.success";
37
+ readonly DELETE_SUCCESS: "task.delete.success";
38
+ readonly RESTORE_SUCCESS: "task.restore.success";
39
+ readonly MOVE_SUCCESS: "task.move.success";
40
+ readonly ASSIGN_SUCCESS: "task.assign.success";
41
+ readonly ASSIGNEE_NOT_BOARD_MEMBER: "task.assignee.not.board.member";
42
+ };
43
+ export declare const TASK_LABEL_MESSAGES: {
44
+ readonly NOT_FOUND: "task.label.not.found";
45
+ readonly CREATE_SUCCESS: "task.label.create.success";
46
+ readonly CREATE_MANY_SUCCESS: "task.label.create.many.success";
47
+ readonly GET_SUCCESS: "task.label.get.success";
48
+ readonly GET_ALL_SUCCESS: "task.label.get.all.success";
49
+ readonly UPDATE_SUCCESS: "task.label.update.success";
50
+ readonly UPDATE_MANY_SUCCESS: "task.label.update.many.success";
51
+ readonly DELETE_SUCCESS: "task.label.delete.success";
52
+ readonly RESTORE_SUCCESS: "task.label.restore.success";
53
+ };
54
+ export declare const TASK_COMMENT_MESSAGES: {
55
+ readonly NOT_FOUND: "task.comment.not.found";
56
+ readonly CREATE_SUCCESS: "task.comment.create.success";
57
+ readonly CREATE_MANY_SUCCESS: "task.comment.create.many.success";
58
+ readonly GET_SUCCESS: "task.comment.get.success";
59
+ readonly GET_ALL_SUCCESS: "task.comment.get.all.success";
60
+ readonly UPDATE_SUCCESS: "task.comment.update.success";
61
+ readonly UPDATE_MANY_SUCCESS: "task.comment.update.many.success";
62
+ readonly DELETE_SUCCESS: "task.comment.delete.success";
63
+ readonly RESTORE_SUCCESS: "task.comment.restore.success";
64
+ readonly FORBIDDEN: "task.comment.forbidden";
65
+ };
@@ -0,0 +1 @@
1
+ export declare const TASK_MANAGER_MODULE_OPTIONS = "TASK_MANAGER_MODULE_OPTIONS";
@@ -0,0 +1,5 @@
1
+ export * from './task-board.controller';
2
+ export * from './task-list.controller';
3
+ export * from './task.controller';
4
+ export * from './task-label.controller';
5
+ export * from './task-comment.controller';
@@ -0,0 +1,27 @@
1
+ import { ListResponseDto, MessageResponseDto, SingleResponseDto } from '@flusys/nestjs-shared/dtos';
2
+ import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
3
+ import { AddBoardMemberDto, CreateTaskBoardDto, GetBoardMembersDto, RemoveBoardMemberDto, TaskBoardMemberResponseDto, TaskBoardResponseDto, UpdateTaskBoardDto } from '../dtos';
4
+ import { TaskBoardService } from '../services/task-board.service';
5
+ declare const TaskBoardController_base: abstract new (service: TaskBoardService) => {
6
+ readonly enabledEndpoints: import("@flusys/nestjs-shared").ApiEndpoint[] | "all";
7
+ service: TaskBoardService;
8
+ isEnabled(endpoint: import("@flusys/nestjs-shared").ApiEndpoint): boolean;
9
+ insert(addDto: CreateTaskBoardDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<TaskBoardResponseDto>>;
10
+ insertMany(addDto: CreateTaskBoardDto[], user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<TaskBoardResponseDto>>;
11
+ getById(id: string, body: import("@flusys/nestjs-shared").GetByIdBodyDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<TaskBoardResponseDto>>;
12
+ getByIds(body: import("@flusys/nestjs-shared").GetByIdsDto, user: ILoggedUserInfo | null): Promise<ListResponseDto<TaskBoardResponseDto>>;
13
+ update(updateDto: UpdateTaskBoardDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<TaskBoardResponseDto>>;
14
+ updateMany(updateDtos: UpdateTaskBoardDto[], user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<TaskBoardResponseDto>>;
15
+ bulkUpsert(dtos: (CreateTaskBoardDto | UpdateTaskBoardDto)[], user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<TaskBoardResponseDto>>;
16
+ getByFilter(filter: Record<string, any>, user: ILoggedUserInfo | null): Promise<SingleResponseDto<TaskBoardResponseDto>>;
17
+ getAll(filterAndPaginationDto: import("@flusys/nestjs-shared").FilterAndPaginationDto, user: ILoggedUserInfo | null, search?: string): Promise<ListResponseDto<TaskBoardResponseDto>>;
18
+ delete(deleteDto: import("@flusys/nestjs-shared").DeleteDto, user: ILoggedUserInfo | null): Promise<MessageResponseDto>;
19
+ };
20
+ export declare class TaskBoardController extends TaskBoardController_base {
21
+ protected boardService: TaskBoardService;
22
+ constructor(boardService: TaskBoardService);
23
+ addMember(dto: AddBoardMemberDto, user: ILoggedUserInfo): Promise<SingleResponseDto<TaskBoardMemberResponseDto>>;
24
+ removeMember(dto: RemoveBoardMemberDto): Promise<MessageResponseDto>;
25
+ getMembers(dto: GetBoardMembersDto): Promise<ListResponseDto<TaskBoardMemberResponseDto>>;
26
+ }
27
+ export {};
@@ -0,0 +1,22 @@
1
+ import { CreateTaskCommentDto, TaskCommentResponseDto, UpdateTaskCommentDto } from '../dtos';
2
+ import { TaskCommentService } from '../services/task-comment.service';
3
+ declare const TaskCommentController_base: abstract new (service: TaskCommentService) => {
4
+ readonly enabledEndpoints: import("@flusys/nestjs-shared").ApiEndpoint[] | "all";
5
+ service: TaskCommentService;
6
+ isEnabled(endpoint: import("@flusys/nestjs-shared").ApiEndpoint): boolean;
7
+ insert(addDto: CreateTaskCommentDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<TaskCommentResponseDto>>;
8
+ insertMany(addDto: CreateTaskCommentDto[], user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<TaskCommentResponseDto>>;
9
+ getById(id: string, body: import("@flusys/nestjs-shared").GetByIdBodyDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<TaskCommentResponseDto>>;
10
+ getByIds(body: import("@flusys/nestjs-shared").GetByIdsDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").ListResponseDto<TaskCommentResponseDto>>;
11
+ update(updateDto: UpdateTaskCommentDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<TaskCommentResponseDto>>;
12
+ updateMany(updateDtos: UpdateTaskCommentDto[], user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<TaskCommentResponseDto>>;
13
+ bulkUpsert(dtos: (CreateTaskCommentDto | UpdateTaskCommentDto)[], user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<TaskCommentResponseDto>>;
14
+ getByFilter(filter: Record<string, any>, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<TaskCommentResponseDto>>;
15
+ getAll(filterAndPaginationDto: import("@flusys/nestjs-shared").FilterAndPaginationDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null, search?: string): Promise<import("@flusys/nestjs-shared").ListResponseDto<TaskCommentResponseDto>>;
16
+ delete(deleteDto: import("@flusys/nestjs-shared").DeleteDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").MessageResponseDto>;
17
+ };
18
+ export declare class TaskCommentController extends TaskCommentController_base {
19
+ protected commentService: TaskCommentService;
20
+ constructor(commentService: TaskCommentService);
21
+ }
22
+ export {};