@flusys/nestjs-event-manager 4.1.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +126 -337
- package/adapters/event-manager.adapter.d.ts +0 -2
- package/cjs/adapters/event-manager.adapter.js +1 -7
- package/cjs/config/message-keys.js +1 -31
- package/cjs/controllers/event.controller.js +10 -60
- package/cjs/controllers/index.js +0 -1
- package/cjs/docs/event-manager-swagger.config.js +19 -29
- package/cjs/docs/index.js +0 -3
- package/cjs/dtos/calendar-query.dto.js +46 -20
- package/cjs/dtos/event-participant.dto.js +0 -45
- package/cjs/dtos/event.dto.js +97 -45
- package/cjs/entities/event-participant.entity.js +1 -8
- package/cjs/entities/event.entity.js +38 -26
- package/cjs/modules/event-manager.module.js +2 -4
- package/cjs/services/event-manager-helper.service.js +15 -83
- package/cjs/services/event.service.js +143 -122
- package/cjs/services/index.js +0 -1
- package/config/message-keys.d.ts +0 -56
- package/controllers/event.controller.d.ts +2 -5
- package/controllers/index.d.ts +0 -1
- package/docs/index.d.ts +1 -1
- package/dtos/calendar-query.dto.d.ts +8 -5
- package/dtos/event-participant.dto.d.ts +0 -6
- package/dtos/event.dto.d.ts +14 -10
- package/entities/event-participant.entity.d.ts +0 -1
- package/entities/event.entity.d.ts +6 -5
- package/fesm/adapters/event-manager.adapter.js +1 -7
- package/fesm/config/message-keys.js +1 -29
- package/fesm/controllers/event.controller.js +11 -61
- package/fesm/controllers/index.js +0 -1
- package/fesm/docs/event-manager-swagger.config.js +19 -29
- package/fesm/docs/index.js +1 -1
- package/fesm/dtos/calendar-query.dto.js +47 -21
- package/fesm/dtos/event-participant.dto.js +0 -42
- package/fesm/dtos/event.dto.js +98 -46
- package/fesm/entities/event-participant.entity.js +1 -8
- package/fesm/entities/event.entity.js +38 -26
- package/fesm/modules/event-manager.module.js +4 -6
- package/fesm/services/event-manager-helper.service.js +17 -85
- package/fesm/services/event.service.js +144 -123
- package/fesm/services/index.js +0 -1
- package/interfaces/event.interface.d.ts +6 -6
- package/package.json +3 -3
- package/services/event-manager-helper.service.d.ts +1 -3
- package/services/event.service.d.ts +8 -8
- package/services/index.d.ts +0 -1
- package/cjs/controllers/event-participant.controller.js +0 -287
- package/cjs/services/event-participant.service.js +0 -198
- package/controllers/event-participant.controller.d.ts +0 -35
- package/fesm/controllers/event-participant.controller.js +0 -277
- package/fesm/services/event-participant.service.js +0 -188
- package/services/event-participant.service.d.ts +0 -27
|
@@ -30,10 +30,11 @@ import { LogAction } from '@flusys/nestjs-shared/decorators';
|
|
|
30
30
|
import { RecurrenceType } from '@flusys/nestjs-shared/enums';
|
|
31
31
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
32
32
|
import { applyCompanyFilter } from '@flusys/nestjs-shared/utils';
|
|
33
|
-
import { EVENT_MESSAGES } from '../config';
|
|
33
|
+
import { EVENT_MESSAGES, EVENT_PARTICIPANT_MESSAGES } from '../config';
|
|
34
34
|
import { Inject, Injectable, NotFoundException, Scope } from '@nestjs/common';
|
|
35
35
|
import { In, IsNull } from 'typeorm';
|
|
36
36
|
import { EventManagerConfigService } from './event-manager-config.service';
|
|
37
|
+
import { UpdateParticipantStatusDto } from '../dtos';
|
|
37
38
|
import { Event, EventWithCompany, EventParticipant } from '../entities';
|
|
38
39
|
import { EventManagerDataSourceProvider } from './event-manager-datasource.provider';
|
|
39
40
|
export class EventService extends RequestScopedApiService {
|
|
@@ -46,6 +47,7 @@ export class EventService extends RequestScopedApiService {
|
|
|
46
47
|
}
|
|
47
48
|
// Override methods
|
|
48
49
|
async convertSingleDtoToEntity(dto, user) {
|
|
50
|
+
await this.ensureRepositoryInitialized();
|
|
49
51
|
let entity = {};
|
|
50
52
|
if ('id' in dto && dto.id && typeof dto.id === 'string') {
|
|
51
53
|
const existing = await this.repository.findOne({
|
|
@@ -59,19 +61,21 @@ export class EventService extends RequestScopedApiService {
|
|
|
59
61
|
});
|
|
60
62
|
entity = existing;
|
|
61
63
|
}
|
|
64
|
+
const isAllDay = dto.isAllDay ?? entity.isAllDay ?? false;
|
|
62
65
|
const merged = {
|
|
63
66
|
...entity,
|
|
64
67
|
title: dto.title ?? entity.title,
|
|
65
68
|
description: dto.description ?? entity.description,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
isAllDay
|
|
69
|
+
eventDate: dto.eventDate ?? entity.eventDate,
|
|
70
|
+
startTime: isAllDay ? '00:00' : dto.startTime ?? entity.startTime ?? '00:00',
|
|
71
|
+
endTime: isAllDay ? '23:59' : dto.endTime ?? entity.endTime ?? '23:59',
|
|
72
|
+
isAllDay,
|
|
70
73
|
recurrenceType: dto.recurrenceType ?? entity.recurrenceType ?? RecurrenceType.NONE,
|
|
71
|
-
recurrenceEndDate: dto.recurrenceEndDate ?? entity.recurrenceEndDate,
|
|
74
|
+
recurrenceEndDate: dto.recurrenceEndDate ?? entity.recurrenceEndDate ?? null,
|
|
75
|
+
weekDays: dto.weekDays ?? entity.weekDays ?? null,
|
|
72
76
|
color: dto.color ?? entity.color ?? this.eventConfig.getDefaultColor(),
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
meetingLink: dto.meetingLink !== undefined ? dto.meetingLink ?? null : entity.meetingLink ?? null,
|
|
78
|
+
isActive: dto.isActive ?? entity.isActive ?? true
|
|
75
79
|
};
|
|
76
80
|
if (this.eventConfig.isCompanyFeatureEnabled()) {
|
|
77
81
|
merged.companyId = user?.companyId ?? null;
|
|
@@ -114,6 +118,8 @@ export class EventService extends RequestScopedApiService {
|
|
|
114
118
|
async getExtraManipulateQuery(query, filterDto, user) {
|
|
115
119
|
const result = await super.getExtraManipulateQuery(query, filterDto, user);
|
|
116
120
|
this.applyEventCompanyFilter(query, user);
|
|
121
|
+
await this.ensureParticipantRepositoryInitialized();
|
|
122
|
+
query.leftJoinAndMapMany(`${this.entityName}.participants`, EventParticipant, 'ep', 'ep.event_id = event.id AND ep.deleted_at IS NULL');
|
|
117
123
|
return result;
|
|
118
124
|
}
|
|
119
125
|
async afterInsertOperation(entities, user, _qr) {
|
|
@@ -123,20 +129,29 @@ export class EventService extends RequestScopedApiService {
|
|
|
123
129
|
}
|
|
124
130
|
this.pendingParticipantsList = [];
|
|
125
131
|
}
|
|
132
|
+
async afterUpdateOperation(entities, user, _qr) {
|
|
133
|
+
const participantRepo = await this.ensureParticipantRepositoryInitialized();
|
|
134
|
+
for(let i = 0; i < entities.length; i++){
|
|
135
|
+
const participantIds = this.pendingParticipantsList[i] ?? [];
|
|
136
|
+
await participantRepo.update({
|
|
137
|
+
eventId: entities[i].id,
|
|
138
|
+
deletedAt: IsNull()
|
|
139
|
+
}, {
|
|
140
|
+
deletedAt: new Date()
|
|
141
|
+
});
|
|
142
|
+
await this.addCreatorAndParticipants(entities[i].id, participantIds, user);
|
|
143
|
+
}
|
|
144
|
+
this.pendingParticipantsList = [];
|
|
145
|
+
}
|
|
126
146
|
// Public API methods
|
|
127
147
|
async getEventsForCalendarRange(queryDto, user) {
|
|
128
148
|
await this.ensureRepositoryInitialized();
|
|
129
149
|
const query = this.repository.createQueryBuilder('event').where('event.deletedAt IS NULL').andWhere('event.isActive = :isActive', {
|
|
130
150
|
isActive: queryDto.activeOnly !== false
|
|
131
|
-
})
|
|
132
|
-
query.andWhere('(event.startDateTime <= :endDate AND event.endDateTime >= :startDate)', {
|
|
151
|
+
}).andWhere('((event.eventDate >= :startDate AND event.eventDate <= :endDate) OR (event.recurrenceType != :none AND event.eventDate <= :endDate AND (event.recurrenceEndDate IS NULL OR event.recurrenceEndDate >= :startDate)))', {
|
|
133
152
|
startDate: queryDto.startDate,
|
|
134
|
-
endDate: queryDto.endDate
|
|
135
|
-
|
|
136
|
-
query.orWhere('event.deletedAt IS NULL AND event.recurrenceType != :none AND event.startDateTime <= :endDate AND (event.recurrenceEndDate IS NULL OR event.recurrenceEndDate >= :startDate)', {
|
|
137
|
-
none: RecurrenceType.NONE,
|
|
138
|
-
startDate: queryDto.startDate,
|
|
139
|
-
endDate: queryDto.endDate
|
|
153
|
+
endDate: queryDto.endDate,
|
|
154
|
+
none: RecurrenceType.NONE
|
|
140
155
|
});
|
|
141
156
|
this.applyEventCompanyFilter(query, user);
|
|
142
157
|
if (queryDto.userId) {
|
|
@@ -155,75 +170,57 @@ export class EventService extends RequestScopedApiService {
|
|
|
155
170
|
}
|
|
156
171
|
return this.expandRecurringEvents(events, queryDto.startDate, queryDto.endDate);
|
|
157
172
|
}
|
|
158
|
-
async
|
|
159
|
-
await this.ensureRepositoryInitialized();
|
|
160
|
-
const query = this.repository.createQueryBuilder('event').where('event.id = :id', {
|
|
161
|
-
id
|
|
162
|
-
}).andWhere('event.deletedAt IS NULL');
|
|
163
|
-
this.applyEventCompanyFilter(query, user);
|
|
164
|
-
const event = await query.getOne();
|
|
165
|
-
if (event) {
|
|
166
|
-
const participantRepo = await this.ensureParticipantRepositoryInitialized();
|
|
167
|
-
event.participants = await participantRepo.find({
|
|
168
|
-
where: {
|
|
169
|
-
eventId: id,
|
|
170
|
-
deletedAt: IsNull()
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
return event;
|
|
175
|
-
}
|
|
176
|
-
async addParticipants(eventId, userIds, _user) {
|
|
177
|
-
await this.ensureRepositoryInitialized();
|
|
173
|
+
async updateParticipantStatus(dto, _user) {
|
|
178
174
|
const participantRepo = await this.ensureParticipantRepositoryInitialized();
|
|
179
|
-
const
|
|
175
|
+
const participant = await participantRepo.findOne({
|
|
180
176
|
where: {
|
|
181
|
-
id:
|
|
182
|
-
deletedAt: IsNull()
|
|
177
|
+
id: dto.id
|
|
183
178
|
}
|
|
184
179
|
});
|
|
185
|
-
if (!
|
|
180
|
+
if (!participant) {
|
|
186
181
|
throw new NotFoundException({
|
|
187
|
-
message: 'Event not found',
|
|
188
|
-
messageKey:
|
|
182
|
+
message: 'Event participant not found',
|
|
183
|
+
messageKey: EVENT_PARTICIPANT_MESSAGES.NOT_FOUND
|
|
189
184
|
});
|
|
190
185
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
eventId,
|
|
194
|
-
userId: In(userIds),
|
|
195
|
-
deletedAt: IsNull()
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
const existingUserIds = new Set(existingParticipants.map((p)=>p.userId));
|
|
199
|
-
const newParticipants = userIds.filter((userId)=>!existingUserIds.has(userId)).map((userId)=>({
|
|
200
|
-
eventId,
|
|
201
|
-
userId,
|
|
202
|
-
isOrganizer: false
|
|
203
|
-
}));
|
|
204
|
-
if (newParticipants.length === 0) {
|
|
205
|
-
return existingParticipants;
|
|
206
|
-
}
|
|
207
|
-
const created = await participantRepo.save(newParticipants);
|
|
208
|
-
return [
|
|
209
|
-
...existingParticipants,
|
|
210
|
-
...created
|
|
211
|
-
];
|
|
186
|
+
participant.status = dto.status;
|
|
187
|
+
return participantRepo.save(participant);
|
|
212
188
|
}
|
|
213
189
|
// Private business logic helpers
|
|
214
190
|
async addCreatorAndParticipants(eventId, participantIds, user) {
|
|
215
191
|
if (!user?.id) return;
|
|
216
192
|
const participantRepo = await this.ensureParticipantRepositoryInitialized();
|
|
217
|
-
const allUserIds = new Set([
|
|
193
|
+
const allUserIds = Array.from(new Set([
|
|
218
194
|
user.id,
|
|
219
195
|
...participantIds
|
|
220
|
-
]);
|
|
221
|
-
const
|
|
196
|
+
]));
|
|
197
|
+
const existing = await participantRepo.find({
|
|
198
|
+
where: {
|
|
199
|
+
eventId,
|
|
200
|
+
userId: In(allUserIds)
|
|
201
|
+
},
|
|
202
|
+
withDeleted: true
|
|
203
|
+
});
|
|
204
|
+
const existingByUserId = new Map(existing.map((p)=>[
|
|
205
|
+
p.userId,
|
|
206
|
+
p
|
|
207
|
+
]));
|
|
208
|
+
const toSave = allUserIds.map((userId)=>{
|
|
209
|
+
const existingRecord = existingByUserId.get(userId);
|
|
210
|
+
if (existingRecord) {
|
|
211
|
+
return {
|
|
212
|
+
...existingRecord,
|
|
213
|
+
deletedAt: null,
|
|
214
|
+
isOrganizer: userId === user.id
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
222
218
|
eventId,
|
|
223
219
|
userId,
|
|
224
220
|
isOrganizer: userId === user.id
|
|
225
|
-
}
|
|
226
|
-
|
|
221
|
+
};
|
|
222
|
+
});
|
|
223
|
+
await participantRepo.save(toSave);
|
|
227
224
|
}
|
|
228
225
|
expandRecurringEvents(events, rangeStart, rangeEnd) {
|
|
229
226
|
const result = [];
|
|
@@ -235,48 +232,44 @@ export class EventService extends RequestScopedApiService {
|
|
|
235
232
|
result.push(...this.generateOccurrences(event, rangeStart, rangeEnd, maxOccurrences));
|
|
236
233
|
}
|
|
237
234
|
}
|
|
238
|
-
return result.sort((a, b)=>
|
|
235
|
+
return result.sort((a, b)=>a.eventDate.localeCompare(b.eventDate));
|
|
239
236
|
}
|
|
240
237
|
generateOccurrences(event, rangeStart, rangeEnd, maxOccurrences) {
|
|
241
238
|
const occurrences = [];
|
|
242
|
-
const
|
|
243
|
-
const recurrenceEnd = event.recurrenceEndDate ? new Date(event.recurrenceEndDate) : null;
|
|
239
|
+
const recurrenceEnd = event.recurrenceEndDate ?? null;
|
|
244
240
|
const recurrenceType = event.recurrenceType;
|
|
245
|
-
const
|
|
246
|
-
|
|
241
|
+
const weekDays = event.weekDays ?? [
|
|
242
|
+
this.getDayOfWeek(event.eventDate)
|
|
247
243
|
];
|
|
248
|
-
let
|
|
244
|
+
let currentDate = event.eventDate;
|
|
249
245
|
let count = 0;
|
|
250
246
|
if (recurrenceType === RecurrenceType.WEEKLY || recurrenceType === RecurrenceType.BIWEEKLY) {
|
|
251
|
-
let weekStart =
|
|
252
|
-
weekStart.setDate(weekStart.getDate() - weekStart.getDay());
|
|
247
|
+
let weekStart = this.getWeekStart(event.eventDate);
|
|
253
248
|
while(count < maxOccurrences){
|
|
254
|
-
for (const dayOfWeek of
|
|
249
|
+
for (const dayOfWeek of weekDays){
|
|
255
250
|
if (count >= maxOccurrences) break;
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
currentStart.setMinutes(new Date(event.startDateTime).getMinutes());
|
|
260
|
-
if (currentStart < new Date(event.startDateTime)) continue;
|
|
261
|
-
const shouldBreak = this.shouldStopRecurrence(currentStart, recurrenceEnd, rangeEnd);
|
|
262
|
-
if (shouldBreak) {
|
|
251
|
+
currentDate = this.addDaysToDate(weekStart, this.weekdayNameToIndex(dayOfWeek));
|
|
252
|
+
if (currentDate < event.eventDate) continue;
|
|
253
|
+
if (this.shouldStopRecurrence(currentDate, recurrenceEnd, rangeEnd)) {
|
|
263
254
|
count = maxOccurrences;
|
|
264
255
|
break;
|
|
265
256
|
}
|
|
266
|
-
|
|
267
|
-
|
|
257
|
+
if (currentDate >= rangeStart && currentDate <= rangeEnd) {
|
|
258
|
+
occurrences.push(this.toCalendarEventOnDate(event, currentDate, occurrences.length > 0));
|
|
259
|
+
}
|
|
268
260
|
count++;
|
|
269
261
|
}
|
|
270
262
|
const weeksToAdd = recurrenceType === RecurrenceType.BIWEEKLY ? 2 : 1;
|
|
271
|
-
weekStart.
|
|
263
|
+
weekStart = this.addDaysToDate(weekStart, 7 * weeksToAdd);
|
|
272
264
|
}
|
|
273
265
|
} else {
|
|
274
|
-
const originalDayOfMonth =
|
|
266
|
+
const originalDayOfMonth = parseInt(event.eventDate.split('-')[2], 10);
|
|
275
267
|
while(count < maxOccurrences){
|
|
276
|
-
if (this.shouldStopRecurrence(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
268
|
+
if (this.shouldStopRecurrence(currentDate, recurrenceEnd, rangeEnd)) break;
|
|
269
|
+
if (currentDate >= rangeStart && currentDate <= rangeEnd) {
|
|
270
|
+
occurrences.push(this.toCalendarEventOnDate(event, currentDate, count > 0));
|
|
271
|
+
}
|
|
272
|
+
currentDate = this.getNextOccurrenceDate(currentDate, recurrenceType, originalDayOfMonth);
|
|
280
273
|
count++;
|
|
281
274
|
}
|
|
282
275
|
}
|
|
@@ -321,41 +314,61 @@ export class EventService extends RequestScopedApiService {
|
|
|
321
314
|
entityAlias: 'event'
|
|
322
315
|
}, user);
|
|
323
316
|
}
|
|
324
|
-
shouldStopRecurrence(
|
|
325
|
-
return recurrenceEnd &&
|
|
317
|
+
shouldStopRecurrence(currentDate, recurrenceEnd, rangeEnd) {
|
|
318
|
+
return recurrenceEnd !== null && currentDate > recurrenceEnd || currentDate > rangeEnd;
|
|
326
319
|
}
|
|
327
|
-
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
320
|
+
getDayOfWeek(dateStr) {
|
|
321
|
+
const days = [
|
|
322
|
+
'SUN',
|
|
323
|
+
'MON',
|
|
324
|
+
'TUE',
|
|
325
|
+
'WED',
|
|
326
|
+
'THU',
|
|
327
|
+
'FRI',
|
|
328
|
+
'SAT'
|
|
329
|
+
];
|
|
330
|
+
return days[new Date(`${dateStr}T00:00:00Z`).getUTCDay()];
|
|
331
|
+
}
|
|
332
|
+
weekdayNameToIndex(day) {
|
|
333
|
+
const map = {
|
|
334
|
+
SUN: 0,
|
|
335
|
+
MON: 1,
|
|
336
|
+
TUE: 2,
|
|
337
|
+
WED: 3,
|
|
338
|
+
THU: 4,
|
|
339
|
+
FRI: 5,
|
|
340
|
+
SAT: 6
|
|
341
|
+
};
|
|
342
|
+
return map[day.toUpperCase()] ?? 0;
|
|
343
|
+
}
|
|
344
|
+
getWeekStart(dateStr) {
|
|
345
|
+
const d = new Date(`${dateStr}T00:00:00Z`);
|
|
346
|
+
d.setUTCDate(d.getUTCDate() - d.getUTCDay());
|
|
347
|
+
return d.toISOString().slice(0, 10);
|
|
348
|
+
}
|
|
349
|
+
addDaysToDate(dateStr, days) {
|
|
350
|
+
const d = new Date(`${dateStr}T00:00:00Z`);
|
|
351
|
+
d.setUTCDate(d.getUTCDate() + days);
|
|
352
|
+
return d.toISOString().slice(0, 10);
|
|
340
353
|
}
|
|
341
354
|
getNextOccurrenceDate(current, recurrenceType, originalDayOfMonth) {
|
|
342
|
-
const
|
|
355
|
+
const d = new Date(`${current}T00:00:00Z`);
|
|
343
356
|
switch(recurrenceType){
|
|
344
357
|
case RecurrenceType.DAILY:
|
|
345
|
-
|
|
358
|
+
d.setUTCDate(d.getUTCDate() + 1);
|
|
346
359
|
break;
|
|
347
360
|
case RecurrenceType.MONTHLY:
|
|
348
361
|
{
|
|
349
|
-
const targetDay = originalDayOfMonth ??
|
|
350
|
-
|
|
351
|
-
const lastDayOfMonth = new Date(
|
|
352
|
-
|
|
362
|
+
const targetDay = originalDayOfMonth ?? d.getUTCDate();
|
|
363
|
+
d.setUTCMonth(d.getUTCMonth() + 1);
|
|
364
|
+
const lastDayOfMonth = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 0)).getUTCDate();
|
|
365
|
+
d.setUTCDate(Math.min(targetDay, lastDayOfMonth));
|
|
353
366
|
break;
|
|
354
367
|
}
|
|
355
368
|
default:
|
|
356
369
|
break;
|
|
357
370
|
}
|
|
358
|
-
return
|
|
371
|
+
return d.toISOString().slice(0, 10);
|
|
359
372
|
}
|
|
360
373
|
// Private transformation helpers
|
|
361
374
|
toCalendarEvent(event) {
|
|
@@ -363,15 +376,16 @@ export class EventService extends RequestScopedApiService {
|
|
|
363
376
|
id: event.id,
|
|
364
377
|
title: event.title,
|
|
365
378
|
description: event.description,
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
379
|
+
eventDate: event.eventDate,
|
|
380
|
+
startTime: event.startTime,
|
|
381
|
+
endTime: event.endTime,
|
|
369
382
|
isAllDay: event.isAllDay,
|
|
370
383
|
recurrenceType: event.recurrenceType,
|
|
371
384
|
recurrenceEndDate: event.recurrenceEndDate,
|
|
385
|
+
weekDays: event.weekDays,
|
|
372
386
|
color: event.color,
|
|
387
|
+
meetingLink: event.meetingLink ?? null,
|
|
373
388
|
isActive: event.isActive,
|
|
374
|
-
metadata: event.metadata,
|
|
375
389
|
createdAt: event.createdAt,
|
|
376
390
|
updatedAt: event.updatedAt,
|
|
377
391
|
deletedAt: event.deletedAt,
|
|
@@ -381,6 +395,15 @@ export class EventService extends RequestScopedApiService {
|
|
|
381
395
|
participants: event.participants?.map((p)=>this.toParticipantInfo(p))
|
|
382
396
|
};
|
|
383
397
|
}
|
|
398
|
+
toCalendarEventOnDate(event, occurrenceDate, isRecurrenceInstance) {
|
|
399
|
+
return {
|
|
400
|
+
...this.toCalendarEvent(event),
|
|
401
|
+
id: `${event.id}_${occurrenceDate}`,
|
|
402
|
+
originalEventId: event.id,
|
|
403
|
+
isRecurrenceInstance,
|
|
404
|
+
eventDate: occurrenceDate
|
|
405
|
+
};
|
|
406
|
+
}
|
|
384
407
|
toParticipantInfo(p) {
|
|
385
408
|
return {
|
|
386
409
|
id: p.id,
|
|
@@ -388,7 +411,6 @@ export class EventService extends RequestScopedApiService {
|
|
|
388
411
|
userId: p.userId,
|
|
389
412
|
status: p.status,
|
|
390
413
|
isOrganizer: p.isOrganizer,
|
|
391
|
-
metadata: p.metadata,
|
|
392
414
|
createdAt: p.createdAt,
|
|
393
415
|
updatedAt: p.updatedAt,
|
|
394
416
|
deletedAt: p.deletedAt,
|
|
@@ -403,17 +425,16 @@ export class EventService extends RequestScopedApiService {
|
|
|
403
425
|
}
|
|
404
426
|
_ts_decorate([
|
|
405
427
|
LogAction({
|
|
406
|
-
action: '
|
|
428
|
+
action: 'eventParticipant.updateStatus',
|
|
407
429
|
module: 'event-manager'
|
|
408
430
|
}),
|
|
409
431
|
_ts_metadata("design:type", Function),
|
|
410
432
|
_ts_metadata("design:paramtypes", [
|
|
411
|
-
|
|
412
|
-
Array,
|
|
433
|
+
typeof UpdateParticipantStatusDto === "undefined" ? Object : UpdateParticipantStatusDto,
|
|
413
434
|
Object
|
|
414
435
|
]),
|
|
415
436
|
_ts_metadata("design:returntype", Promise)
|
|
416
|
-
], EventService.prototype, "
|
|
437
|
+
], EventService.prototype, "updateParticipantStatus", null);
|
|
417
438
|
EventService = _ts_decorate([
|
|
418
439
|
Injectable({
|
|
419
440
|
scope: Scope.REQUEST
|
package/fesm/services/index.js
CHANGED
|
@@ -3,15 +3,16 @@ import { IIdentity } from '@flusys/nestjs-shared/interfaces';
|
|
|
3
3
|
export interface IEvent extends IIdentity {
|
|
4
4
|
title: string;
|
|
5
5
|
description: string | null;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
eventDate: string;
|
|
7
|
+
startTime: string;
|
|
8
|
+
endTime: string;
|
|
9
9
|
isAllDay: boolean;
|
|
10
10
|
recurrenceType: RecurrenceType | string;
|
|
11
|
-
recurrenceEndDate:
|
|
11
|
+
recurrenceEndDate: string | null;
|
|
12
|
+
weekDays: string[] | null;
|
|
12
13
|
color: string;
|
|
14
|
+
meetingLink: string | null;
|
|
13
15
|
isActive: boolean;
|
|
14
|
-
metadata: Record<string, unknown> | null;
|
|
15
16
|
companyId?: string | null;
|
|
16
17
|
}
|
|
17
18
|
export interface IEventParticipant extends IIdentity {
|
|
@@ -19,7 +20,6 @@ export interface IEventParticipant extends IIdentity {
|
|
|
19
20
|
userId: string;
|
|
20
21
|
status: ParticipantStatus | string;
|
|
21
22
|
isOrganizer: boolean;
|
|
22
|
-
metadata: Record<string, unknown> | null;
|
|
23
23
|
}
|
|
24
24
|
export interface ICalendarEvent extends IEvent {
|
|
25
25
|
originalEventId?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-event-manager",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Event manager module with calendar support and recurrence",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "fesm/index.js",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"express": "^4.18.0"
|
|
85
85
|
},
|
|
86
86
|
"dependencies": {
|
|
87
|
-
"@flusys/nestjs-core": "
|
|
88
|
-
"@flusys/nestjs-shared": "
|
|
87
|
+
"@flusys/nestjs-core": "5.0.0",
|
|
88
|
+
"@flusys/nestjs-shared": "5.0.0"
|
|
89
89
|
}
|
|
90
90
|
}
|
|
@@ -15,10 +15,8 @@ export declare class EventManagerHelperService {
|
|
|
15
15
|
private getEventRepository;
|
|
16
16
|
private getParticipantRepository;
|
|
17
17
|
createEvent(options: CreateEventOptions): Promise<EventResult>;
|
|
18
|
-
addParticipants(eventId: string, userIds: string[], _companyId?: string): Promise<void>;
|
|
19
|
-
removeParticipant(eventId: string, userId: string): Promise<void>;
|
|
20
18
|
updateParticipantStatus(participantId: string, status: ParticipantStatus): Promise<void>;
|
|
21
|
-
getEventsForUser(userId: string, startDate:
|
|
19
|
+
getEventsForUser(userId: string, startDate: string, endDate: string, companyId?: string): Promise<EventResult[]>;
|
|
22
20
|
getEventById(eventId: string): Promise<EventResult | null>;
|
|
23
21
|
private addEventParticipants;
|
|
24
22
|
private toEventResult;
|
|
@@ -3,13 +3,10 @@ import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
|
3
3
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
4
4
|
import { EntityTarget, QueryRunner, Repository, SelectQueryBuilder } from 'typeorm';
|
|
5
5
|
import { EventManagerConfigService } from './event-manager-config.service';
|
|
6
|
-
import { CalendarQueryDto, CreateEventDto, UpdateEventDto } from '../dtos';
|
|
6
|
+
import { CalendarQueryDto, CreateEventDto, UpdateEventDto, UpdateParticipantStatusDto } from '../dtos';
|
|
7
7
|
import { EventBase, EventParticipant } from '../entities';
|
|
8
8
|
import { ICalendarEvent, IEvent } from '../interfaces';
|
|
9
9
|
import { EventManagerDataSourceProvider } from './event-manager-datasource.provider';
|
|
10
|
-
type EventWithParticipants = Omit<EventBase, 'participants'> & {
|
|
11
|
-
participants?: EventParticipant[];
|
|
12
|
-
};
|
|
13
10
|
export declare class EventService extends RequestScopedApiService<CreateEventDto, UpdateEventDto, IEvent, EventBase, Repository<EventBase>> {
|
|
14
11
|
protected cacheManager: HybridCache;
|
|
15
12
|
protected utilsService: UtilsService;
|
|
@@ -30,9 +27,9 @@ export declare class EventService extends RequestScopedApiService<CreateEventDto
|
|
|
30
27
|
isRaw: boolean;
|
|
31
28
|
}>;
|
|
32
29
|
protected afterInsertOperation(entities: EventBase[], user: ILoggedUserInfo | null, _qr: QueryRunner): Promise<void>;
|
|
30
|
+
protected afterUpdateOperation(entities: EventBase[], user: ILoggedUserInfo | null, _qr: QueryRunner): Promise<void>;
|
|
33
31
|
getEventsForCalendarRange(queryDto: CalendarQueryDto, user: ILoggedUserInfo | null): Promise<ICalendarEvent[]>;
|
|
34
|
-
|
|
35
|
-
addParticipants(eventId: string, userIds: string[], _user: ILoggedUserInfo | null): Promise<EventParticipant[]>;
|
|
32
|
+
updateParticipantStatus(dto: UpdateParticipantStatusDto, _user: ILoggedUserInfo | null): Promise<EventParticipant>;
|
|
36
33
|
private addCreatorAndParticipants;
|
|
37
34
|
private expandRecurringEvents;
|
|
38
35
|
private generateOccurrences;
|
|
@@ -41,9 +38,12 @@ export declare class EventService extends RequestScopedApiService<CreateEventDto
|
|
|
41
38
|
private loadParticipantsForEvents;
|
|
42
39
|
private applyEventCompanyFilter;
|
|
43
40
|
private shouldStopRecurrence;
|
|
44
|
-
private
|
|
41
|
+
private getDayOfWeek;
|
|
42
|
+
private weekdayNameToIndex;
|
|
43
|
+
private getWeekStart;
|
|
44
|
+
private addDaysToDate;
|
|
45
45
|
private getNextOccurrenceDate;
|
|
46
46
|
private toCalendarEvent;
|
|
47
|
+
private toCalendarEventOnDate;
|
|
47
48
|
private toParticipantInfo;
|
|
48
49
|
}
|
|
49
|
-
export {};
|
package/services/index.d.ts
CHANGED