@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.
- package/README.md +245 -0
- package/cjs/config/index.js +19 -0
- package/cjs/config/message-keys.js +92 -0
- package/cjs/config/task-manager.constants.js +11 -0
- package/cjs/controllers/index.js +22 -0
- package/cjs/controllers/task-board.controller.js +219 -0
- package/cjs/controllers/task-comment.controller.js +103 -0
- package/cjs/controllers/task-label.controller.js +112 -0
- package/cjs/controllers/task-list.controller.js +158 -0
- package/cjs/controllers/task.controller.js +199 -0
- package/cjs/docs/index.js +18 -0
- package/cjs/docs/task-manager-swagger.config.js +43 -0
- package/cjs/dtos/index.js +22 -0
- package/cjs/dtos/task-board.dto.js +310 -0
- package/cjs/dtos/task-comment.dto.js +131 -0
- package/cjs/dtos/task-label.dto.js +120 -0
- package/cjs/dtos/task-list.dto.js +198 -0
- package/cjs/dtos/task.dto.js +367 -0
- package/cjs/entities/index.js +72 -0
- package/cjs/entities/task-activity.entity.js +98 -0
- package/cjs/entities/task-assignee.entity.js +67 -0
- package/cjs/entities/task-board-member.entity.js +94 -0
- package/cjs/entities/task-board-with-company.entity.js +57 -0
- package/cjs/entities/task-board.entity.js +88 -0
- package/cjs/entities/task-comment.entity.js +80 -0
- package/cjs/entities/task-label.entity.js +72 -0
- package/cjs/entities/task-list.entity.js +104 -0
- package/cjs/entities/task-task-label.entity.js +67 -0
- package/cjs/entities/task.entity.js +151 -0
- package/cjs/gateways/index.js +18 -0
- package/cjs/gateways/task-board.gateway.js +199 -0
- package/cjs/index.js +26 -0
- package/cjs/interfaces/index.js +19 -0
- package/cjs/interfaces/task-manager-module.interface.js +4 -0
- package/cjs/interfaces/task.interface.js +4 -0
- package/cjs/modules/index.js +18 -0
- package/cjs/modules/task-manager.module.js +131 -0
- package/cjs/services/index.js +25 -0
- package/cjs/services/task-activity.service.js +76 -0
- package/cjs/services/task-board.service.js +235 -0
- package/cjs/services/task-comment.service.js +103 -0
- package/cjs/services/task-label.service.js +97 -0
- package/cjs/services/task-list.service.js +115 -0
- package/cjs/services/task-manager-config.service.js +69 -0
- package/cjs/services/task-manager-datasource.provider.js +84 -0
- package/cjs/services/task.service.js +359 -0
- package/config/index.d.ts +2 -0
- package/config/message-keys.d.ts +65 -0
- package/config/task-manager.constants.d.ts +1 -0
- package/controllers/index.d.ts +5 -0
- package/controllers/task-board.controller.d.ts +27 -0
- package/controllers/task-comment.controller.d.ts +22 -0
- package/controllers/task-label.controller.d.ts +22 -0
- package/controllers/task-list.controller.d.ts +26 -0
- package/controllers/task.controller.d.ts +28 -0
- package/docs/index.d.ts +1 -0
- package/docs/task-manager-swagger.config.d.ts +2 -0
- package/dtos/index.d.ts +5 -0
- package/dtos/task-board.dto.d.ts +44 -0
- package/dtos/task-comment.dto.d.ts +16 -0
- package/dtos/task-label.dto.d.ts +16 -0
- package/dtos/task-list.dto.d.ts +26 -0
- package/dtos/task.dto.d.ts +48 -0
- package/entities/index.d.ts +22 -0
- package/entities/task-activity.entity.d.ts +9 -0
- package/entities/task-assignee.entity.d.ts +5 -0
- package/entities/task-board-member.entity.d.ts +12 -0
- package/entities/task-board-with-company.entity.d.ts +4 -0
- package/entities/task-board.entity.d.ts +8 -0
- package/entities/task-comment.entity.d.ts +7 -0
- package/entities/task-label.entity.d.ts +6 -0
- package/entities/task-list.entity.d.ts +9 -0
- package/entities/task-task-label.entity.d.ts +5 -0
- package/entities/task.entity.d.ts +23 -0
- package/fesm/config/index.js +2 -0
- package/fesm/config/message-keys.js +65 -0
- package/fesm/config/task-manager.constants.js +1 -0
- package/fesm/controllers/index.js +5 -0
- package/fesm/controllers/task-board.controller.js +209 -0
- package/fesm/controllers/task-comment.controller.js +93 -0
- package/fesm/controllers/task-label.controller.js +102 -0
- package/fesm/controllers/task-list.controller.js +148 -0
- package/fesm/controllers/task.controller.js +189 -0
- package/fesm/docs/index.js +1 -0
- package/fesm/docs/task-manager-swagger.config.js +33 -0
- package/fesm/dtos/index.js +5 -0
- package/fesm/dtos/task-board.dto.js +277 -0
- package/fesm/dtos/task-comment.dto.js +110 -0
- package/fesm/dtos/task-label.dto.js +99 -0
- package/fesm/dtos/task-list.dto.js +174 -0
- package/fesm/dtos/task.dto.js +337 -0
- package/fesm/entities/index.js +46 -0
- package/fesm/entities/task-activity.entity.js +88 -0
- package/fesm/entities/task-assignee.entity.js +57 -0
- package/fesm/entities/task-board-member.entity.js +76 -0
- package/fesm/entities/task-board-with-company.entity.js +47 -0
- package/fesm/entities/task-board.entity.js +78 -0
- package/fesm/entities/task-comment.entity.js +70 -0
- package/fesm/entities/task-label.entity.js +62 -0
- package/fesm/entities/task-list.entity.js +94 -0
- package/fesm/entities/task-task-label.entity.js +57 -0
- package/fesm/entities/task.entity.js +133 -0
- package/fesm/gateways/index.js +1 -0
- package/fesm/gateways/task-board.gateway.js +148 -0
- package/fesm/index.js +9 -0
- package/fesm/interfaces/index.js +2 -0
- package/fesm/interfaces/task-manager-module.interface.js +1 -0
- package/fesm/interfaces/task.interface.js +1 -0
- package/fesm/modules/index.js +1 -0
- package/fesm/modules/task-manager.module.js +121 -0
- package/fesm/services/index.js +8 -0
- package/fesm/services/task-activity.service.js +66 -0
- package/fesm/services/task-board.service.js +225 -0
- package/fesm/services/task-comment.service.js +93 -0
- package/fesm/services/task-label.service.js +87 -0
- package/fesm/services/task-list.service.js +105 -0
- package/fesm/services/task-manager-config.service.js +59 -0
- package/fesm/services/task-manager-datasource.provider.js +74 -0
- package/fesm/services/task.service.js +349 -0
- package/gateways/index.d.ts +1 -0
- package/gateways/task-board.gateway.d.ts +22 -0
- package/index.d.ts +9 -0
- package/interfaces/index.d.ts +2 -0
- package/interfaces/task-manager-module.interface.d.ts +19 -0
- package/interfaces/task.interface.d.ts +52 -0
- package/modules/index.d.ts +1 -0
- package/modules/task-manager.module.d.ts +8 -0
- package/package.json +91 -0
- package/services/index.d.ts +8 -0
- package/services/task-activity.service.d.ts +8 -0
- package/services/task-board.service.d.ts +32 -0
- package/services/task-comment.service.d.ts +18 -0
- package/services/task-label.service.d.ts +18 -0
- package/services/task-list.service.d.ts +19 -0
- package/services/task-manager-config.service.d.ts +12 -0
- package/services/task-manager-datasource.provider.d.ts +18 -0
- package/services/task.service.d.ts +44 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
function _define_property(obj, key, value) {
|
|
2
|
+
if (key in obj) {
|
|
3
|
+
Object.defineProperty(obj, key, {
|
|
4
|
+
value: value,
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true
|
|
8
|
+
});
|
|
9
|
+
} else {
|
|
10
|
+
obj[key] = value;
|
|
11
|
+
}
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
15
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
16
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
17
|
+
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;
|
|
18
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
19
|
+
}
|
|
20
|
+
function _ts_metadata(k, v) {
|
|
21
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
|
+
}
|
|
23
|
+
function _ts_param(paramIndex, decorator) {
|
|
24
|
+
return function(target, key) {
|
|
25
|
+
decorator(target, key, paramIndex);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
import { HybridCache, ApiService } from '@flusys/nestjs-shared/classes';
|
|
29
|
+
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
30
|
+
import { applyCompanyFilter } from '@flusys/nestjs-shared/utils';
|
|
31
|
+
import { BadRequestException, Inject, Injectable, NotFoundException, Scope } from '@nestjs/common';
|
|
32
|
+
import { IsNull } from 'typeorm';
|
|
33
|
+
import { TASK_BOARD_MESSAGES } from '../config';
|
|
34
|
+
import { BoardMemberRole, TaskBoardMember, TaskBoard, TaskBoardWithCompany } from '../entities';
|
|
35
|
+
import { TaskManagerConfigService } from './task-manager-config.service';
|
|
36
|
+
import { TaskManagerDataSourceProvider } from './task-manager-datasource.provider';
|
|
37
|
+
export class TaskBoardService extends ApiService {
|
|
38
|
+
resolveEntity() {
|
|
39
|
+
return this.config.isCompanyFeatureEnabled() ? TaskBoardWithCompany : TaskBoard;
|
|
40
|
+
}
|
|
41
|
+
async convertSingleDtoToEntity(dto, user) {
|
|
42
|
+
await this.ensureDataSourceRepository();
|
|
43
|
+
let entity = {};
|
|
44
|
+
if ('id' in dto && dto.id) {
|
|
45
|
+
const existing = await this.repository.findOne({
|
|
46
|
+
where: {
|
|
47
|
+
id: dto.id
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
if (!existing) throw new NotFoundException({
|
|
51
|
+
message: 'Board not found',
|
|
52
|
+
messageKey: TASK_BOARD_MESSAGES.NOT_FOUND
|
|
53
|
+
});
|
|
54
|
+
entity = existing;
|
|
55
|
+
}
|
|
56
|
+
const merged = {
|
|
57
|
+
...entity,
|
|
58
|
+
name: dto.name ?? entity.name,
|
|
59
|
+
description: dto.description !== undefined ? dto.description ?? null : entity.description ?? null,
|
|
60
|
+
color: dto.color ?? entity.color ?? '#3B82F6',
|
|
61
|
+
isActive: ('isActive' in dto ? dto.isActive : undefined) ?? entity.isActive ?? true
|
|
62
|
+
};
|
|
63
|
+
if (this.config.isCompanyFeatureEnabled()) {
|
|
64
|
+
merged.companyId = user?.companyId ?? null;
|
|
65
|
+
}
|
|
66
|
+
return merged;
|
|
67
|
+
}
|
|
68
|
+
async getExtraManipulateQuery(query, filterDto, user) {
|
|
69
|
+
await super.getExtraManipulateQuery(query, filterDto, user);
|
|
70
|
+
applyCompanyFilter(query, {
|
|
71
|
+
isCompanyFeatureEnabled: this.config.isCompanyFeatureEnabled(),
|
|
72
|
+
entityAlias: 'task_board'
|
|
73
|
+
}, user);
|
|
74
|
+
if (user?.id) {
|
|
75
|
+
query.innerJoin('task_board_member', 'tbm_filter', 'tbm_filter.board_id = task_board.id AND tbm_filter.user_id = :currentUserId AND tbm_filter.deleted_at IS NULL', {
|
|
76
|
+
currentUserId: user.id
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
query.addSelect('task_board.createdAt').addSelect('task_board.updatedAt').addSelect(`(SELECT CAST(COUNT(*) AS INTEGER) FROM task_board_member tbm WHERE tbm.board_id = task_board.id AND tbm.deleted_at IS NULL)`, 'total_members').addSelect(`(SELECT CAST(COUNT(*) AS INTEGER) FROM task_list tl WHERE tl.board_id = task_board.id AND tl.is_active = true AND tl.deleted_at IS NULL)`, 'total_lists').addSelect(`(SELECT CAST(COUNT(*) AS INTEGER) FROM task t WHERE t.board_id = task_board.id AND t.deleted_at IS NULL)`, 'total_tasks');
|
|
80
|
+
return {
|
|
81
|
+
query,
|
|
82
|
+
isRaw: true
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
convertEntityToResponseDto(entity, isRaw) {
|
|
86
|
+
if (!isRaw) return super.convertEntityToResponseDto(entity, isRaw);
|
|
87
|
+
const prefix = `${this.entityName}_`;
|
|
88
|
+
const mapped = {};
|
|
89
|
+
for (const [key, value] of Object.entries(entity)){
|
|
90
|
+
const rawKey = key.startsWith(prefix) ? key.slice(prefix.length) : key;
|
|
91
|
+
const camelKey = rawKey.replace(/_([a-z])/g, (_, c)=>c.toUpperCase());
|
|
92
|
+
mapped[camelKey] = typeof value === 'string' && value !== '' && !isNaN(Number(value)) ? Number(value) : value;
|
|
93
|
+
}
|
|
94
|
+
return mapped;
|
|
95
|
+
}
|
|
96
|
+
async addMember(dto, user) {
|
|
97
|
+
await this.ensureDataSourceRepository();
|
|
98
|
+
const memberRepo = await this.ensureMemberRepository();
|
|
99
|
+
const board = await this.repository.findOne({
|
|
100
|
+
where: {
|
|
101
|
+
id: dto.boardId
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
if (!board) throw new NotFoundException({
|
|
105
|
+
message: 'Board not found',
|
|
106
|
+
messageKey: TASK_BOARD_MESSAGES.NOT_FOUND
|
|
107
|
+
});
|
|
108
|
+
const existing = await memberRepo.findOne({
|
|
109
|
+
where: {
|
|
110
|
+
boardId: dto.boardId,
|
|
111
|
+
userId: dto.userId,
|
|
112
|
+
deletedAt: IsNull()
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
if (existing) throw new BadRequestException({
|
|
116
|
+
message: 'User is already a board member',
|
|
117
|
+
messageKey: TASK_BOARD_MESSAGES.MEMBER_ALREADY_EXISTS
|
|
118
|
+
});
|
|
119
|
+
const softDeleted = await memberRepo.findOne({
|
|
120
|
+
where: {
|
|
121
|
+
boardId: dto.boardId,
|
|
122
|
+
userId: dto.userId
|
|
123
|
+
},
|
|
124
|
+
withDeleted: true
|
|
125
|
+
});
|
|
126
|
+
if (softDeleted) {
|
|
127
|
+
await memberRepo.restore({
|
|
128
|
+
id: softDeleted.id
|
|
129
|
+
});
|
|
130
|
+
await memberRepo.update({
|
|
131
|
+
id: softDeleted.id
|
|
132
|
+
}, {
|
|
133
|
+
role: dto.role ?? BoardMemberRole.MEMBER
|
|
134
|
+
});
|
|
135
|
+
return memberRepo.findOne({
|
|
136
|
+
where: {
|
|
137
|
+
id: softDeleted.id
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const member = memberRepo.create({
|
|
142
|
+
boardId: dto.boardId,
|
|
143
|
+
userId: dto.userId,
|
|
144
|
+
role: dto.role ?? BoardMemberRole.MEMBER,
|
|
145
|
+
createdById: user.id
|
|
146
|
+
});
|
|
147
|
+
return memberRepo.save(member);
|
|
148
|
+
}
|
|
149
|
+
async removeMember(dto) {
|
|
150
|
+
const memberRepo = await this.ensureMemberRepository();
|
|
151
|
+
const member = await memberRepo.findOne({
|
|
152
|
+
where: {
|
|
153
|
+
boardId: dto.boardId,
|
|
154
|
+
userId: dto.userId,
|
|
155
|
+
deletedAt: IsNull()
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
if (!member) throw new NotFoundException({
|
|
159
|
+
message: 'Member not found',
|
|
160
|
+
messageKey: TASK_BOARD_MESSAGES.MEMBER_NOT_FOUND
|
|
161
|
+
});
|
|
162
|
+
await memberRepo.update({
|
|
163
|
+
id: member.id
|
|
164
|
+
}, {
|
|
165
|
+
deletedAt: new Date()
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async getMembers(boardId) {
|
|
169
|
+
const memberRepo = await this.ensureMemberRepository();
|
|
170
|
+
const { entities, raw } = await memberRepo.createQueryBuilder('tbm').leftJoin('app_user', 'u', 'u.id = tbm.user_id').addSelect('u.name', 'userName').addSelect('u.email', 'userEmail').where('tbm.board_id = :boardId', {
|
|
171
|
+
boardId
|
|
172
|
+
}).andWhere('tbm.deleted_at IS NULL').orderBy('tbm.created_at', 'ASC').getRawAndEntities();
|
|
173
|
+
return entities.map((entity, i)=>({
|
|
174
|
+
...entity,
|
|
175
|
+
userName: raw[i]?.userName ?? null,
|
|
176
|
+
userEmail: raw[i]?.userEmail ?? null
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
async isBoardMember(boardId, userId) {
|
|
180
|
+
const memberRepo = await this.ensureMemberRepository();
|
|
181
|
+
const count = await memberRepo.count({
|
|
182
|
+
where: {
|
|
183
|
+
boardId,
|
|
184
|
+
userId,
|
|
185
|
+
deletedAt: IsNull()
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
return count > 0;
|
|
189
|
+
}
|
|
190
|
+
async afterInsertOperation(entities, user, _qr) {
|
|
191
|
+
if (!user?.id) return;
|
|
192
|
+
const memberRepo = await this.ensureMemberRepository();
|
|
193
|
+
await memberRepo.save(entities.map((board)=>memberRepo.create({
|
|
194
|
+
boardId: board.id,
|
|
195
|
+
userId: user.id,
|
|
196
|
+
role: BoardMemberRole.OWNER,
|
|
197
|
+
createdById: user.id
|
|
198
|
+
})));
|
|
199
|
+
}
|
|
200
|
+
async ensureMemberRepository() {
|
|
201
|
+
if (!this.memberRepository) {
|
|
202
|
+
this.memberRepository = await this.dataSourceProvider.getRepository(TaskBoardMember);
|
|
203
|
+
}
|
|
204
|
+
return this.memberRepository;
|
|
205
|
+
}
|
|
206
|
+
constructor(cacheManager, utilsService, config, dataSourceProvider){
|
|
207
|
+
super('task_board', cacheManager, utilsService, TaskBoardService.name, true, 'task-manager', undefined, dataSourceProvider), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "config", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "memberRepository", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.config = config, this.dataSourceProvider = dataSourceProvider, this.memberRepository = null;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
TaskBoardService = _ts_decorate([
|
|
211
|
+
Injectable({
|
|
212
|
+
scope: Scope.REQUEST
|
|
213
|
+
}),
|
|
214
|
+
_ts_param(0, Inject('CACHE_INSTANCE')),
|
|
215
|
+
_ts_param(1, Inject(UtilsService)),
|
|
216
|
+
_ts_param(2, Inject(TaskManagerConfigService)),
|
|
217
|
+
_ts_param(3, Inject(TaskManagerDataSourceProvider)),
|
|
218
|
+
_ts_metadata("design:type", Function),
|
|
219
|
+
_ts_metadata("design:paramtypes", [
|
|
220
|
+
typeof HybridCache === "undefined" ? Object : HybridCache,
|
|
221
|
+
typeof UtilsService === "undefined" ? Object : UtilsService,
|
|
222
|
+
typeof TaskManagerConfigService === "undefined" ? Object : TaskManagerConfigService,
|
|
223
|
+
typeof TaskManagerDataSourceProvider === "undefined" ? Object : TaskManagerDataSourceProvider
|
|
224
|
+
])
|
|
225
|
+
], TaskBoardService);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
function _define_property(obj, key, value) {
|
|
2
|
+
if (key in obj) {
|
|
3
|
+
Object.defineProperty(obj, key, {
|
|
4
|
+
value: value,
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true
|
|
8
|
+
});
|
|
9
|
+
} else {
|
|
10
|
+
obj[key] = value;
|
|
11
|
+
}
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
15
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
16
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
17
|
+
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;
|
|
18
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
19
|
+
}
|
|
20
|
+
function _ts_metadata(k, v) {
|
|
21
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
|
+
}
|
|
23
|
+
function _ts_param(paramIndex, decorator) {
|
|
24
|
+
return function(target, key) {
|
|
25
|
+
decorator(target, key, paramIndex);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
import { HybridCache, ApiService } from '@flusys/nestjs-shared/classes';
|
|
29
|
+
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
30
|
+
import { ForbiddenException, Inject, Injectable, NotFoundException, Scope } from '@nestjs/common';
|
|
31
|
+
import { TASK_COMMENT_MESSAGES } from '../config';
|
|
32
|
+
import { TaskComment } from '../entities';
|
|
33
|
+
import { TaskManagerDataSourceProvider } from './task-manager-datasource.provider';
|
|
34
|
+
export class TaskCommentService extends ApiService {
|
|
35
|
+
async convertSingleDtoToEntity(dto, user) {
|
|
36
|
+
await this.ensureDataSourceRepository();
|
|
37
|
+
let entity = {};
|
|
38
|
+
if ('id' in dto && dto.id) {
|
|
39
|
+
const existing = await this.repository.findOne({
|
|
40
|
+
where: {
|
|
41
|
+
id: dto.id
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
if (!existing) throw new NotFoundException({
|
|
45
|
+
message: 'Comment not found',
|
|
46
|
+
messageKey: TASK_COMMENT_MESSAGES.NOT_FOUND
|
|
47
|
+
});
|
|
48
|
+
if (existing.userId !== user?.id) throw new ForbiddenException({
|
|
49
|
+
message: 'Cannot edit another user comment',
|
|
50
|
+
messageKey: TASK_COMMENT_MESSAGES.FORBIDDEN
|
|
51
|
+
});
|
|
52
|
+
entity = existing;
|
|
53
|
+
}
|
|
54
|
+
const taskId = ('taskId' in dto ? dto.taskId : undefined) ?? entity.taskId;
|
|
55
|
+
return {
|
|
56
|
+
...entity,
|
|
57
|
+
taskId,
|
|
58
|
+
userId: entity.userId !== undefined ? entity.userId : user?.id ?? null,
|
|
59
|
+
content: dto.content,
|
|
60
|
+
parentCommentId: 'parentCommentId' in dto ? dto.parentCommentId ?? null : entity.parentCommentId ?? null
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async getFilterQuery(query, filter, _user) {
|
|
64
|
+
for (const [key, value] of Object.entries(filter)){
|
|
65
|
+
if (key === 'taskId') {
|
|
66
|
+
query.andWhere('task_comment.taskId = :taskId', {
|
|
67
|
+
taskId: value
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
query,
|
|
73
|
+
isRaw: false
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
constructor(cacheManager, utilsService, dataSourceProvider){
|
|
77
|
+
super('task_comment', cacheManager, utilsService, TaskCommentService.name, false, 'task-manager', TaskComment, 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;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
TaskCommentService = _ts_decorate([
|
|
81
|
+
Injectable({
|
|
82
|
+
scope: Scope.REQUEST
|
|
83
|
+
}),
|
|
84
|
+
_ts_param(0, Inject('CACHE_INSTANCE')),
|
|
85
|
+
_ts_param(1, Inject(UtilsService)),
|
|
86
|
+
_ts_param(2, Inject(TaskManagerDataSourceProvider)),
|
|
87
|
+
_ts_metadata("design:type", Function),
|
|
88
|
+
_ts_metadata("design:paramtypes", [
|
|
89
|
+
typeof HybridCache === "undefined" ? Object : HybridCache,
|
|
90
|
+
typeof UtilsService === "undefined" ? Object : UtilsService,
|
|
91
|
+
typeof TaskManagerDataSourceProvider === "undefined" ? Object : TaskManagerDataSourceProvider
|
|
92
|
+
])
|
|
93
|
+
], TaskCommentService);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
function _define_property(obj, key, value) {
|
|
2
|
+
if (key in obj) {
|
|
3
|
+
Object.defineProperty(obj, key, {
|
|
4
|
+
value: value,
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true
|
|
8
|
+
});
|
|
9
|
+
} else {
|
|
10
|
+
obj[key] = value;
|
|
11
|
+
}
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
15
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
16
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
17
|
+
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;
|
|
18
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
19
|
+
}
|
|
20
|
+
function _ts_metadata(k, v) {
|
|
21
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
|
+
}
|
|
23
|
+
function _ts_param(paramIndex, decorator) {
|
|
24
|
+
return function(target, key) {
|
|
25
|
+
decorator(target, key, paramIndex);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
import { ApiService, HybridCache } from '@flusys/nestjs-shared/classes';
|
|
29
|
+
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
30
|
+
import { Inject, Injectable, NotFoundException, Scope } from '@nestjs/common';
|
|
31
|
+
import { TASK_LABEL_MESSAGES } from '../config';
|
|
32
|
+
import { TaskLabel } from '../entities';
|
|
33
|
+
import { TaskManagerDataSourceProvider } from './task-manager-datasource.provider';
|
|
34
|
+
export class TaskLabelService extends ApiService {
|
|
35
|
+
async convertSingleDtoToEntity(dto, _user) {
|
|
36
|
+
await this.ensureDataSourceRepository();
|
|
37
|
+
let entity = {};
|
|
38
|
+
if ('id' in dto && dto.id) {
|
|
39
|
+
const existing = await this.repository.findOne({
|
|
40
|
+
where: {
|
|
41
|
+
id: dto.id
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
if (!existing) throw new NotFoundException({
|
|
45
|
+
message: 'Label not found',
|
|
46
|
+
messageKey: TASK_LABEL_MESSAGES.NOT_FOUND
|
|
47
|
+
});
|
|
48
|
+
entity = existing;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
...entity,
|
|
52
|
+
boardId: dto.boardId ?? entity.boardId,
|
|
53
|
+
name: dto.name ?? entity.name,
|
|
54
|
+
color: dto.color ?? entity.color ?? '#10B981'
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async getFilterQuery(query, filter, _user) {
|
|
58
|
+
for (const [key, value] of Object.entries(filter)){
|
|
59
|
+
if (key === 'boardId') {
|
|
60
|
+
query.andWhere('task_label.boardId = :boardId', {
|
|
61
|
+
boardId: value
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
query,
|
|
67
|
+
isRaw: false
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
constructor(cacheManager, utilsService, dataSourceProvider){
|
|
71
|
+
super('task_label', cacheManager, utilsService, TaskLabelService.name, true, 'task-manager', TaskLabel, 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;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
TaskLabelService = _ts_decorate([
|
|
75
|
+
Injectable({
|
|
76
|
+
scope: Scope.REQUEST
|
|
77
|
+
}),
|
|
78
|
+
_ts_param(0, Inject('CACHE_INSTANCE')),
|
|
79
|
+
_ts_param(1, Inject(UtilsService)),
|
|
80
|
+
_ts_param(2, Inject(TaskManagerDataSourceProvider)),
|
|
81
|
+
_ts_metadata("design:type", Function),
|
|
82
|
+
_ts_metadata("design:paramtypes", [
|
|
83
|
+
typeof HybridCache === "undefined" ? Object : HybridCache,
|
|
84
|
+
typeof UtilsService === "undefined" ? Object : UtilsService,
|
|
85
|
+
typeof TaskManagerDataSourceProvider === "undefined" ? Object : TaskManagerDataSourceProvider
|
|
86
|
+
])
|
|
87
|
+
], TaskLabelService);
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
function _define_property(obj, key, value) {
|
|
2
|
+
if (key in obj) {
|
|
3
|
+
Object.defineProperty(obj, key, {
|
|
4
|
+
value: value,
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true
|
|
8
|
+
});
|
|
9
|
+
} else {
|
|
10
|
+
obj[key] = value;
|
|
11
|
+
}
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
15
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
16
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
17
|
+
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;
|
|
18
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
19
|
+
}
|
|
20
|
+
function _ts_metadata(k, v) {
|
|
21
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
|
+
}
|
|
23
|
+
function _ts_param(paramIndex, decorator) {
|
|
24
|
+
return function(target, key) {
|
|
25
|
+
decorator(target, key, paramIndex);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
import { ApiService, HybridCache } from '@flusys/nestjs-shared/classes';
|
|
29
|
+
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
30
|
+
import { Inject, Injectable, NotFoundException, Scope } from '@nestjs/common';
|
|
31
|
+
import { TASK_LIST_MESSAGES } from '../config';
|
|
32
|
+
import { TaskList } from '../entities';
|
|
33
|
+
import { TaskManagerDataSourceProvider } from './task-manager-datasource.provider';
|
|
34
|
+
export class TaskListService extends ApiService {
|
|
35
|
+
async convertSingleDtoToEntity(dto, _user) {
|
|
36
|
+
await this.ensureDataSourceRepository();
|
|
37
|
+
let entity = {};
|
|
38
|
+
if ('id' in dto && dto.id) {
|
|
39
|
+
const existing = await this.repository.findOne({
|
|
40
|
+
where: {
|
|
41
|
+
id: dto.id
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
if (!existing) throw new NotFoundException({
|
|
45
|
+
message: 'List not found',
|
|
46
|
+
messageKey: TASK_LIST_MESSAGES.NOT_FOUND
|
|
47
|
+
});
|
|
48
|
+
entity = existing;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
...entity,
|
|
52
|
+
boardId: dto.boardId ?? entity.boardId,
|
|
53
|
+
name: dto.name ?? entity.name,
|
|
54
|
+
color: dto.color ?? entity.color ?? '#6B7280',
|
|
55
|
+
position: dto.position ?? entity.position ?? 0,
|
|
56
|
+
isDoneList: ('isDoneList' in dto ? dto.isDoneList : undefined) ?? entity.isDoneList ?? false,
|
|
57
|
+
isActive: ('isActive' in dto ? dto.isActive : undefined) ?? entity.isActive ?? true
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
async getFilterQuery(query, filter, _user) {
|
|
61
|
+
for (const [key, value] of Object.entries(filter)){
|
|
62
|
+
if (key === 'boardId') {
|
|
63
|
+
query.andWhere('task_list.boardId = :boardId', {
|
|
64
|
+
boardId: value
|
|
65
|
+
});
|
|
66
|
+
} else if (key === 'isActive' && typeof value === 'boolean') {
|
|
67
|
+
query.andWhere('task_list.isActive = :isActive', {
|
|
68
|
+
isActive: value
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
query.orderBy('task_list.position', 'ASC');
|
|
73
|
+
return {
|
|
74
|
+
query,
|
|
75
|
+
isRaw: false
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async reorderLists(dto) {
|
|
79
|
+
await this.ensureDataSourceRepository();
|
|
80
|
+
await Promise.all(dto.orderedIds.map((id, i)=>this.repository.update({
|
|
81
|
+
id,
|
|
82
|
+
boardId: dto.boardId
|
|
83
|
+
}, {
|
|
84
|
+
position: i * 100
|
|
85
|
+
})));
|
|
86
|
+
await this.clearCacheForAll();
|
|
87
|
+
}
|
|
88
|
+
constructor(cacheManager, utilsService, dataSourceProvider){
|
|
89
|
+
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;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
TaskListService = _ts_decorate([
|
|
93
|
+
Injectable({
|
|
94
|
+
scope: Scope.REQUEST
|
|
95
|
+
}),
|
|
96
|
+
_ts_param(0, Inject('CACHE_INSTANCE')),
|
|
97
|
+
_ts_param(1, Inject(UtilsService)),
|
|
98
|
+
_ts_param(2, Inject(TaskManagerDataSourceProvider)),
|
|
99
|
+
_ts_metadata("design:type", Function),
|
|
100
|
+
_ts_metadata("design:paramtypes", [
|
|
101
|
+
typeof HybridCache === "undefined" ? Object : HybridCache,
|
|
102
|
+
typeof UtilsService === "undefined" ? Object : UtilsService,
|
|
103
|
+
typeof TaskManagerDataSourceProvider === "undefined" ? Object : TaskManagerDataSourceProvider
|
|
104
|
+
])
|
|
105
|
+
], TaskListService);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
function _define_property(obj, key, value) {
|
|
2
|
+
if (key in obj) {
|
|
3
|
+
Object.defineProperty(obj, key, {
|
|
4
|
+
value: value,
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true
|
|
8
|
+
});
|
|
9
|
+
} else {
|
|
10
|
+
obj[key] = value;
|
|
11
|
+
}
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
15
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
16
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
17
|
+
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;
|
|
18
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
19
|
+
}
|
|
20
|
+
function _ts_metadata(k, v) {
|
|
21
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
|
+
}
|
|
23
|
+
function _ts_param(paramIndex, decorator) {
|
|
24
|
+
return function(target, key) {
|
|
25
|
+
decorator(target, key, paramIndex);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
import { Inject, Injectable } from '@nestjs/common';
|
|
29
|
+
import { TASK_MANAGER_MODULE_OPTIONS } from '../config/task-manager.constants';
|
|
30
|
+
import { TaskManagerModuleOptions } from '../interfaces';
|
|
31
|
+
export class TaskManagerConfigService {
|
|
32
|
+
isCompanyFeatureEnabled() {
|
|
33
|
+
return this.options.bootstrapAppConfig?.enableCompanyFeature ?? false;
|
|
34
|
+
}
|
|
35
|
+
getDatabaseMode() {
|
|
36
|
+
return this.options.bootstrapAppConfig?.databaseMode ?? 'single';
|
|
37
|
+
}
|
|
38
|
+
isMultiTenant() {
|
|
39
|
+
return this.getDatabaseMode() === 'multi-tenant';
|
|
40
|
+
}
|
|
41
|
+
getJwtSecret() {
|
|
42
|
+
return this.options.config?.jwtSecret;
|
|
43
|
+
}
|
|
44
|
+
getOptions() {
|
|
45
|
+
return this.options;
|
|
46
|
+
}
|
|
47
|
+
constructor(options){
|
|
48
|
+
_define_property(this, "options", void 0);
|
|
49
|
+
this.options = options;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
TaskManagerConfigService = _ts_decorate([
|
|
53
|
+
Injectable(),
|
|
54
|
+
_ts_param(0, Inject(TASK_MANAGER_MODULE_OPTIONS)),
|
|
55
|
+
_ts_metadata("design:type", Function),
|
|
56
|
+
_ts_metadata("design:paramtypes", [
|
|
57
|
+
typeof TaskManagerModuleOptions === "undefined" ? Object : TaskManagerModuleOptions
|
|
58
|
+
])
|
|
59
|
+
], TaskManagerConfigService);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
function _define_property(obj, key, value) {
|
|
2
|
+
if (key in obj) {
|
|
3
|
+
Object.defineProperty(obj, key, {
|
|
4
|
+
value: value,
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true
|
|
8
|
+
});
|
|
9
|
+
} else {
|
|
10
|
+
obj[key] = value;
|
|
11
|
+
}
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
15
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
16
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
17
|
+
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;
|
|
18
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
19
|
+
}
|
|
20
|
+
function _ts_metadata(k, v) {
|
|
21
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
|
+
}
|
|
23
|
+
function _ts_param(paramIndex, decorator) {
|
|
24
|
+
return function(target, key) {
|
|
25
|
+
decorator(target, key, paramIndex);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
import { MultiTenantDataSourceService } from '@flusys/nestjs-shared/modules';
|
|
29
|
+
import { Inject, Injectable, Optional, Scope } from '@nestjs/common';
|
|
30
|
+
import { REQUEST } from '@nestjs/core';
|
|
31
|
+
import { Request } from 'express';
|
|
32
|
+
import { getTaskManagerEntitiesByConfig } from '../entities';
|
|
33
|
+
import { TaskManagerConfigService } from './task-manager-config.service';
|
|
34
|
+
export class TaskManagerDataSourceProvider extends MultiTenantDataSourceService {
|
|
35
|
+
static buildParentOptions(options) {
|
|
36
|
+
return {
|
|
37
|
+
bootstrapAppConfig: options.bootstrapAppConfig,
|
|
38
|
+
defaultDatabaseConfig: options.config?.defaultDatabaseConfig,
|
|
39
|
+
tenantDefaultDatabaseConfig: options.config?.tenantDefaultDatabaseConfig,
|
|
40
|
+
tenants: options.config?.tenants
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
getEnableCompanyFeatureForTenant(tenant) {
|
|
44
|
+
return tenant?.enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
|
|
45
|
+
}
|
|
46
|
+
async createDataSourceFromConfig(config) {
|
|
47
|
+
const currentTenant = this.getCurrentTenant();
|
|
48
|
+
const enableCompanyFeature = this.getEnableCompanyFeatureForTenant(currentTenant ?? undefined);
|
|
49
|
+
const entities = getTaskManagerEntitiesByConfig(enableCompanyFeature);
|
|
50
|
+
return super.createDataSourceFromConfig(config, entities);
|
|
51
|
+
}
|
|
52
|
+
constructor(configService, request){
|
|
53
|
+
super(TaskManagerDataSourceProvider.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0), this.configService = configService;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
_define_property(TaskManagerDataSourceProvider, "tenantConnections", new Map());
|
|
57
|
+
_define_property(TaskManagerDataSourceProvider, "singleDataSource", null);
|
|
58
|
+
_define_property(TaskManagerDataSourceProvider, "tenantsRegistry", new Map());
|
|
59
|
+
_define_property(TaskManagerDataSourceProvider, "initialized", false);
|
|
60
|
+
_define_property(TaskManagerDataSourceProvider, "connectionLocks", new Map());
|
|
61
|
+
_define_property(TaskManagerDataSourceProvider, "singleConnectionLock", null);
|
|
62
|
+
TaskManagerDataSourceProvider = _ts_decorate([
|
|
63
|
+
Injectable({
|
|
64
|
+
scope: Scope.REQUEST
|
|
65
|
+
}),
|
|
66
|
+
_ts_param(0, Inject(TaskManagerConfigService)),
|
|
67
|
+
_ts_param(1, Optional()),
|
|
68
|
+
_ts_param(1, Inject(REQUEST)),
|
|
69
|
+
_ts_metadata("design:type", Function),
|
|
70
|
+
_ts_metadata("design:paramtypes", [
|
|
71
|
+
typeof TaskManagerConfigService === "undefined" ? Object : TaskManagerConfigService,
|
|
72
|
+
typeof Request === "undefined" ? Object : Request
|
|
73
|
+
])
|
|
74
|
+
], TaskManagerDataSourceProvider);
|