@flusys/nestjs-event-manager 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1328 -0
- package/adapters/event-manager.adapter.d.ts +12 -0
- package/adapters/index.d.ts +1 -0
- package/cjs/adapters/event-manager.adapter.js +71 -0
- package/cjs/adapters/index.js +18 -0
- package/cjs/config/event-manager.constants.js +13 -0
- package/cjs/config/index.js +18 -0
- package/cjs/controllers/event-participant.controller.js +271 -0
- package/cjs/controllers/event.controller.js +229 -0
- package/cjs/controllers/index.js +19 -0
- package/cjs/docs/event-manager-swagger.config.js +135 -0
- package/cjs/docs/index.js +24 -0
- package/cjs/dtos/calendar-query.dto.js +186 -0
- package/cjs/dtos/event-participant.dto.js +226 -0
- package/cjs/dtos/event.dto.js +291 -0
- package/cjs/dtos/index.js +20 -0
- package/cjs/entities/event-participant.entity.js +96 -0
- package/cjs/entities/event-with-company.entity.js +56 -0
- package/cjs/entities/event.entity.js +143 -0
- package/cjs/entities/index.js +55 -0
- package/cjs/index.js +27 -0
- package/cjs/interfaces/event-manager-module.interface.js +4 -0
- package/cjs/interfaces/event.interface.js +4 -0
- package/cjs/interfaces/index.js +19 -0
- package/cjs/modules/event-manager.module.js +133 -0
- package/cjs/modules/index.js +18 -0
- package/cjs/services/event-manager-config.service.js +76 -0
- package/cjs/services/event-manager-datasource.provider.js +181 -0
- package/cjs/services/event-manager-helper.service.js +253 -0
- package/cjs/services/event-participant.service.js +164 -0
- package/cjs/services/event.service.js +421 -0
- package/cjs/services/index.js +22 -0
- package/config/event-manager.constants.d.ts +1 -0
- package/config/index.d.ts +1 -0
- package/controllers/event-participant.controller.d.ts +31 -0
- package/controllers/event.controller.d.ts +24 -0
- package/controllers/index.d.ts +2 -0
- package/docs/event-manager-swagger.config.d.ts +3 -0
- package/docs/index.d.ts +2 -0
- package/dtos/calendar-query.dto.d.ts +23 -0
- package/dtos/event-participant.dto.d.ts +31 -0
- package/dtos/event.dto.d.ts +37 -0
- package/dtos/index.d.ts +3 -0
- package/entities/event-participant.entity.d.ts +8 -0
- package/entities/event-with-company.entity.d.ts +4 -0
- package/entities/event.entity.d.ts +14 -0
- package/entities/index.d.ts +11 -0
- package/fesm/adapters/event-manager.adapter.js +61 -0
- package/fesm/adapters/index.js +1 -0
- package/fesm/config/event-manager.constants.js +3 -0
- package/fesm/config/index.js +1 -0
- package/fesm/controllers/event-participant.controller.js +261 -0
- package/fesm/controllers/event.controller.js +219 -0
- package/fesm/controllers/index.js +2 -0
- package/fesm/docs/event-manager-swagger.config.js +128 -0
- package/fesm/docs/index.js +4 -0
- package/fesm/dtos/calendar-query.dto.js +168 -0
- package/fesm/dtos/event-participant.dto.js +199 -0
- package/fesm/dtos/event.dto.js +270 -0
- package/fesm/dtos/index.js +3 -0
- package/fesm/entities/event-participant.entity.js +86 -0
- package/fesm/entities/event-with-company.entity.js +46 -0
- package/fesm/entities/event.entity.js +133 -0
- package/fesm/entities/index.js +24 -0
- package/fesm/index.js +10 -0
- package/fesm/interfaces/event-manager-module.interface.js +3 -0
- package/fesm/interfaces/event.interface.js +1 -0
- package/fesm/interfaces/index.js +2 -0
- package/fesm/modules/event-manager.module.js +123 -0
- package/fesm/modules/index.js +1 -0
- package/fesm/services/event-manager-config.service.js +66 -0
- package/fesm/services/event-manager-datasource.provider.js +130 -0
- package/fesm/services/event-manager-helper.service.js +243 -0
- package/fesm/services/event-participant.service.js +154 -0
- package/fesm/services/event.service.js +411 -0
- package/fesm/services/index.js +5 -0
- package/index.d.ts +9 -0
- package/interfaces/event-manager-module.interface.d.ts +20 -0
- package/interfaces/event.interface.d.ts +28 -0
- package/interfaces/index.d.ts +2 -0
- package/modules/event-manager.module.d.ts +8 -0
- package/modules/index.d.ts +1 -0
- package/package.json +89 -0
- package/services/event-manager-config.service.d.ts +13 -0
- package/services/event-manager-datasource.provider.d.ts +23 -0
- package/services/event-manager-helper.service.d.ts +27 -0
- package/services/event-participant.service.d.ts +27 -0
- package/services/event.service.d.ts +49 -0
- package/services/index.d.ts +5 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "EventParticipantService", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return EventParticipantService;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _classes = require("@flusys/nestjs-shared/classes");
|
|
12
|
+
const _enums = require("@flusys/nestjs-shared/enums");
|
|
13
|
+
const _modules = require("@flusys/nestjs-shared/modules");
|
|
14
|
+
const _common = require("@nestjs/common");
|
|
15
|
+
const _eventmanagerconfigservice = require("./event-manager-config.service");
|
|
16
|
+
const _entities = require("../entities");
|
|
17
|
+
const _eventmanagerdatasourceprovider = require("./event-manager-datasource.provider");
|
|
18
|
+
function _define_property(obj, key, value) {
|
|
19
|
+
if (key in obj) {
|
|
20
|
+
Object.defineProperty(obj, key, {
|
|
21
|
+
value: value,
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true
|
|
25
|
+
});
|
|
26
|
+
} else {
|
|
27
|
+
obj[key] = value;
|
|
28
|
+
}
|
|
29
|
+
return obj;
|
|
30
|
+
}
|
|
31
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
32
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
33
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
34
|
+
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;
|
|
35
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
36
|
+
}
|
|
37
|
+
function _ts_metadata(k, v) {
|
|
38
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
39
|
+
}
|
|
40
|
+
function _ts_param(paramIndex, decorator) {
|
|
41
|
+
return function(target, key) {
|
|
42
|
+
decorator(target, key, paramIndex);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
let EventParticipantService = class EventParticipantService extends _classes.RequestScopedApiService {
|
|
46
|
+
resolveEntity() {
|
|
47
|
+
// EventParticipant doesn't need company variant - company context is inherited through Event
|
|
48
|
+
return _entities.EventParticipant;
|
|
49
|
+
}
|
|
50
|
+
getDataSourceProvider() {
|
|
51
|
+
return this.dataSourceProvider;
|
|
52
|
+
}
|
|
53
|
+
// Override Methods
|
|
54
|
+
async convertSingleDtoToEntity(dto, _user) {
|
|
55
|
+
let entity = {};
|
|
56
|
+
if ('id' in dto && dto.id && typeof dto.id === 'string') {
|
|
57
|
+
const existing = await this.repository.findOne({
|
|
58
|
+
where: {
|
|
59
|
+
id: dto.id
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
if (!existing) throw new _common.NotFoundException('Event participant not found');
|
|
63
|
+
entity = existing;
|
|
64
|
+
}
|
|
65
|
+
// EventParticipant doesn't have companyId - company context comes from Event
|
|
66
|
+
return {
|
|
67
|
+
...entity,
|
|
68
|
+
eventId: dto.eventId ?? entity.eventId,
|
|
69
|
+
userId: dto.userId ?? entity.userId,
|
|
70
|
+
status: dto.status ?? entity.status ?? _enums.ParticipantStatus.PENDING,
|
|
71
|
+
isOrganizer: dto.isOrganizer ?? entity.isOrganizer ?? false,
|
|
72
|
+
metadata: dto.metadata ?? entity.metadata
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async getFilterQuery(query, filter, _user) {
|
|
76
|
+
for (const [key, value] of Object.entries(filter)){
|
|
77
|
+
if (key === 'eventId') {
|
|
78
|
+
query.andWhere(`${this.entityName}.eventId = :eventId`, {
|
|
79
|
+
eventId: value
|
|
80
|
+
});
|
|
81
|
+
} else if (key === 'userId') {
|
|
82
|
+
query.andWhere(`${this.entityName}.userId = :userId`, {
|
|
83
|
+
userId: value
|
|
84
|
+
});
|
|
85
|
+
} else if (key === 'status') {
|
|
86
|
+
query.andWhere(`${this.entityName}.status = :status`, {
|
|
87
|
+
status: value
|
|
88
|
+
});
|
|
89
|
+
} else if (key === 'isOrganizer' && typeof value === 'boolean') {
|
|
90
|
+
query.andWhere(`${this.entityName}.isOrganizer = :isOrganizer`, {
|
|
91
|
+
isOrganizer: value
|
|
92
|
+
});
|
|
93
|
+
} else {
|
|
94
|
+
query.andWhere(`${this.entityName}.${key} = :value`, {
|
|
95
|
+
value
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
query,
|
|
101
|
+
isRaw: false
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// Public Methods
|
|
105
|
+
// Note: EventParticipant doesn't have companyId - company filtering happens at Event level
|
|
106
|
+
async updateStatus(dto, _user) {
|
|
107
|
+
await this.ensureRepositoryInitialized();
|
|
108
|
+
const participant = await this.repository.findOne({
|
|
109
|
+
where: {
|
|
110
|
+
id: dto.id
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
if (!participant) {
|
|
114
|
+
throw new _common.NotFoundException('Event participant not found');
|
|
115
|
+
}
|
|
116
|
+
participant.status = dto.status;
|
|
117
|
+
return this.repository.save(participant);
|
|
118
|
+
}
|
|
119
|
+
async getParticipantsByEvent(eventId, _user) {
|
|
120
|
+
await this.ensureRepositoryInitialized();
|
|
121
|
+
// Company filtering happens at Event level, not participant level
|
|
122
|
+
return this.repository.createQueryBuilder('event_participant').where('event_participant.eventId = :eventId', {
|
|
123
|
+
eventId
|
|
124
|
+
}).andWhere('event_participant.deletedAt IS NULL').getMany();
|
|
125
|
+
}
|
|
126
|
+
async getParticipantsByUser(userId, _user) {
|
|
127
|
+
await this.ensureRepositoryInitialized();
|
|
128
|
+
// Company filtering happens at Event level, not participant level
|
|
129
|
+
return this.repository.createQueryBuilder('event_participant').where('event_participant.userId = :userId', {
|
|
130
|
+
userId
|
|
131
|
+
}).andWhere('event_participant.deletedAt IS NULL').getMany();
|
|
132
|
+
}
|
|
133
|
+
async removeParticipant(eventId, userId, _user) {
|
|
134
|
+
await this.ensureRepositoryInitialized();
|
|
135
|
+
const participant = await this.repository.findOne({
|
|
136
|
+
where: {
|
|
137
|
+
eventId,
|
|
138
|
+
userId
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
if (participant) {
|
|
142
|
+
await this.repository.softRemove(participant);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
constructor(cacheManager, utilsService, eventConfig, dataSourceProvider){
|
|
146
|
+
super('event_participant', null, cacheManager, utilsService, EventParticipantService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "eventConfig", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.eventConfig = eventConfig, this.dataSourceProvider = dataSourceProvider;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
EventParticipantService = _ts_decorate([
|
|
150
|
+
(0, _common.Injectable)({
|
|
151
|
+
scope: _common.Scope.REQUEST
|
|
152
|
+
}),
|
|
153
|
+
_ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
|
|
154
|
+
_ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
|
|
155
|
+
_ts_param(2, (0, _common.Inject)(_eventmanagerconfigservice.EventManagerConfigService)),
|
|
156
|
+
_ts_param(3, (0, _common.Inject)(_eventmanagerdatasourceprovider.EventManagerDataSourceProvider)),
|
|
157
|
+
_ts_metadata("design:type", Function),
|
|
158
|
+
_ts_metadata("design:paramtypes", [
|
|
159
|
+
typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
|
|
160
|
+
typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
|
|
161
|
+
typeof _eventmanagerconfigservice.EventManagerConfigService === "undefined" ? Object : _eventmanagerconfigservice.EventManagerConfigService,
|
|
162
|
+
typeof _eventmanagerdatasourceprovider.EventManagerDataSourceProvider === "undefined" ? Object : _eventmanagerdatasourceprovider.EventManagerDataSourceProvider
|
|
163
|
+
])
|
|
164
|
+
], EventParticipantService);
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "EventService", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return EventService;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _classes = require("@flusys/nestjs-shared/classes");
|
|
12
|
+
const _enums = require("@flusys/nestjs-shared/enums");
|
|
13
|
+
const _modules = require("@flusys/nestjs-shared/modules");
|
|
14
|
+
const _utils = require("@flusys/nestjs-shared/utils");
|
|
15
|
+
const _common = require("@nestjs/common");
|
|
16
|
+
const _typeorm = require("typeorm");
|
|
17
|
+
const _eventmanagerconfigservice = require("./event-manager-config.service");
|
|
18
|
+
const _entities = require("../entities");
|
|
19
|
+
const _eventmanagerdatasourceprovider = require("./event-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 EventService = class EventService extends _classes.RequestScopedApiService {
|
|
48
|
+
// Abstract implementations
|
|
49
|
+
resolveEntity() {
|
|
50
|
+
return this.eventConfig.isCompanyFeatureEnabled() ? _entities.EventWithCompany : _entities.Event;
|
|
51
|
+
}
|
|
52
|
+
getDataSourceProvider() {
|
|
53
|
+
return this.dataSourceProvider;
|
|
54
|
+
}
|
|
55
|
+
// Override methods
|
|
56
|
+
async convertSingleDtoToEntity(dto, user) {
|
|
57
|
+
let entity = {};
|
|
58
|
+
if ('id' in dto && dto.id && typeof dto.id === 'string') {
|
|
59
|
+
const existing = await this.repository.findOne({
|
|
60
|
+
where: {
|
|
61
|
+
id: dto.id
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
if (!existing) throw new _common.NotFoundException('Event not found');
|
|
65
|
+
entity = existing;
|
|
66
|
+
}
|
|
67
|
+
const merged = {
|
|
68
|
+
...entity,
|
|
69
|
+
title: dto.title ?? entity.title,
|
|
70
|
+
description: dto.description ?? entity.description,
|
|
71
|
+
meetingLink: dto.meetingLink ?? entity.meetingLink,
|
|
72
|
+
startDateTime: dto.startDateTime ?? entity.startDateTime,
|
|
73
|
+
endDateTime: dto.endDateTime ?? entity.endDateTime,
|
|
74
|
+
isAllDay: dto.isAllDay ?? entity.isAllDay ?? false,
|
|
75
|
+
recurrenceType: dto.recurrenceType ?? entity.recurrenceType ?? _enums.RecurrenceType.NONE,
|
|
76
|
+
recurrenceEndDate: dto.recurrenceEndDate ?? entity.recurrenceEndDate,
|
|
77
|
+
color: dto.color ?? entity.color ?? this.eventConfig.getDefaultColor(),
|
|
78
|
+
isActive: dto.isActive ?? entity.isActive ?? true,
|
|
79
|
+
metadata: dto.metadata ?? entity.metadata
|
|
80
|
+
};
|
|
81
|
+
if (this.eventConfig.isCompanyFeatureEnabled()) {
|
|
82
|
+
merged.companyId = user?.companyId ?? null;
|
|
83
|
+
}
|
|
84
|
+
if ('participantIds' in dto) {
|
|
85
|
+
this.pendingParticipantsList.push(dto.participantIds ?? []);
|
|
86
|
+
}
|
|
87
|
+
return merged;
|
|
88
|
+
}
|
|
89
|
+
async getFilterQuery(query, filter, _user) {
|
|
90
|
+
for (const [key, value] of Object.entries(filter)){
|
|
91
|
+
if (key === 'isActive' && typeof value === 'boolean') {
|
|
92
|
+
query.andWhere(`${this.entityName}.isActive = :isActive`, {
|
|
93
|
+
isActive: value
|
|
94
|
+
});
|
|
95
|
+
} else if (key === 'recurrenceType') {
|
|
96
|
+
query.andWhere(`${this.entityName}.recurrenceType = :recurrenceType`, {
|
|
97
|
+
recurrenceType: value
|
|
98
|
+
});
|
|
99
|
+
} else if (key === 'participantUserId' && value) {
|
|
100
|
+
const eventIds = await this.getParticipantEventIds(value);
|
|
101
|
+
if (eventIds.length > 0) {
|
|
102
|
+
query.andWhere(`${this.entityName}.id IN (:...participantEventIds)`, {
|
|
103
|
+
participantEventIds: eventIds
|
|
104
|
+
});
|
|
105
|
+
} else {
|
|
106
|
+
query.andWhere('1 = 0');
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
query.andWhere(`${this.entityName}.${key} = :value`, {
|
|
110
|
+
value
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
query,
|
|
116
|
+
isRaw: false
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
async getExtraManipulateQuery(query, filterDto, user) {
|
|
120
|
+
const result = await super.getExtraManipulateQuery(query, filterDto, user);
|
|
121
|
+
this.applyEventCompanyFilter(query, user);
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
async afterInsertOperation(entities, user, _qr) {
|
|
125
|
+
for(let i = 0; i < entities.length; i++){
|
|
126
|
+
const participantIds = this.pendingParticipantsList[i] ?? [];
|
|
127
|
+
await this.addCreatorAndParticipants(entities[i].id, participantIds, user);
|
|
128
|
+
}
|
|
129
|
+
this.pendingParticipantsList = [];
|
|
130
|
+
}
|
|
131
|
+
// Public API methods
|
|
132
|
+
async getEventsForCalendarRange(queryDto, user) {
|
|
133
|
+
await this.ensureRepositoryInitialized();
|
|
134
|
+
const query = this.repository.createQueryBuilder('event').where('event.deletedAt IS NULL').andWhere('event.isActive = :isActive', {
|
|
135
|
+
isActive: queryDto.activeOnly !== false
|
|
136
|
+
});
|
|
137
|
+
query.andWhere('(event.startDateTime <= :endDate AND event.endDateTime >= :startDate)', {
|
|
138
|
+
startDate: queryDto.startDate,
|
|
139
|
+
endDate: queryDto.endDate
|
|
140
|
+
});
|
|
141
|
+
query.orWhere('event.deletedAt IS NULL AND event.recurrenceType != :none AND event.startDateTime <= :endDate AND (event.recurrenceEndDate IS NULL OR event.recurrenceEndDate >= :startDate)', {
|
|
142
|
+
none: _enums.RecurrenceType.NONE,
|
|
143
|
+
startDate: queryDto.startDate,
|
|
144
|
+
endDate: queryDto.endDate
|
|
145
|
+
});
|
|
146
|
+
this.applyEventCompanyFilter(query, user);
|
|
147
|
+
if (queryDto.userId) {
|
|
148
|
+
const eventIds = await this.getParticipantEventIds(queryDto.userId);
|
|
149
|
+
if (eventIds.length > 0) {
|
|
150
|
+
query.andWhere('event.id IN (:...eventIds)', {
|
|
151
|
+
eventIds
|
|
152
|
+
});
|
|
153
|
+
} else {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const events = await query.getMany();
|
|
158
|
+
if (queryDto.includeParticipants && events.length > 0) {
|
|
159
|
+
await this.loadParticipantsForEvents(events);
|
|
160
|
+
}
|
|
161
|
+
return this.expandRecurringEvents(events, queryDto.startDate, queryDto.endDate);
|
|
162
|
+
}
|
|
163
|
+
async getEventWithParticipants(id, user) {
|
|
164
|
+
await this.ensureRepositoryInitialized();
|
|
165
|
+
const query = this.repository.createQueryBuilder('event').where('event.id = :id', {
|
|
166
|
+
id
|
|
167
|
+
}).andWhere('event.deletedAt IS NULL');
|
|
168
|
+
this.applyEventCompanyFilter(query, user);
|
|
169
|
+
const event = await query.getOne();
|
|
170
|
+
if (event) {
|
|
171
|
+
const participantRepo = await this.ensureParticipantRepositoryInitialized();
|
|
172
|
+
event.participants = await participantRepo.find({
|
|
173
|
+
where: {
|
|
174
|
+
eventId: id,
|
|
175
|
+
deletedAt: (0, _typeorm.IsNull)()
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
return event;
|
|
180
|
+
}
|
|
181
|
+
async addParticipants(eventId, userIds, _user) {
|
|
182
|
+
await this.ensureRepositoryInitialized();
|
|
183
|
+
const participantRepo = await this.ensureParticipantRepositoryInitialized();
|
|
184
|
+
const event = await this.repository.findOne({
|
|
185
|
+
where: {
|
|
186
|
+
id: eventId,
|
|
187
|
+
deletedAt: (0, _typeorm.IsNull)()
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
if (!event) {
|
|
191
|
+
throw new _common.NotFoundException('Event not found');
|
|
192
|
+
}
|
|
193
|
+
const existingParticipants = await participantRepo.find({
|
|
194
|
+
where: {
|
|
195
|
+
eventId,
|
|
196
|
+
userId: (0, _typeorm.In)(userIds),
|
|
197
|
+
deletedAt: (0, _typeorm.IsNull)()
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
const existingUserIds = new Set(existingParticipants.map((p)=>p.userId));
|
|
201
|
+
const newParticipants = userIds.filter((userId)=>!existingUserIds.has(userId)).map((userId)=>({
|
|
202
|
+
eventId,
|
|
203
|
+
userId,
|
|
204
|
+
isOrganizer: false
|
|
205
|
+
}));
|
|
206
|
+
if (newParticipants.length === 0) {
|
|
207
|
+
return existingParticipants;
|
|
208
|
+
}
|
|
209
|
+
const created = await participantRepo.save(newParticipants);
|
|
210
|
+
return [
|
|
211
|
+
...existingParticipants,
|
|
212
|
+
...created
|
|
213
|
+
];
|
|
214
|
+
}
|
|
215
|
+
// Private business logic helpers
|
|
216
|
+
async addCreatorAndParticipants(eventId, participantIds, user) {
|
|
217
|
+
if (!user?.id) return;
|
|
218
|
+
const participantRepo = await this.ensureParticipantRepositoryInitialized();
|
|
219
|
+
const allUserIds = new Set([
|
|
220
|
+
user.id,
|
|
221
|
+
...participantIds
|
|
222
|
+
]);
|
|
223
|
+
const participants = Array.from(allUserIds).map((userId)=>({
|
|
224
|
+
eventId,
|
|
225
|
+
userId,
|
|
226
|
+
isOrganizer: userId === user.id
|
|
227
|
+
}));
|
|
228
|
+
await participantRepo.save(participants);
|
|
229
|
+
}
|
|
230
|
+
expandRecurringEvents(events, rangeStart, rangeEnd) {
|
|
231
|
+
const result = [];
|
|
232
|
+
const maxOccurrences = this.eventConfig.getMaxRecurrenceOccurrences();
|
|
233
|
+
for (const event of events){
|
|
234
|
+
if (event.recurrenceType === _enums.RecurrenceType.NONE) {
|
|
235
|
+
result.push(this.toCalendarEvent(event));
|
|
236
|
+
} else {
|
|
237
|
+
result.push(...this.generateOccurrences(event, rangeStart, rangeEnd, maxOccurrences));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return result.sort((a, b)=>new Date(a.startDateTime).getTime() - new Date(b.startDateTime).getTime());
|
|
241
|
+
}
|
|
242
|
+
generateOccurrences(event, rangeStart, rangeEnd, maxOccurrences) {
|
|
243
|
+
const occurrences = [];
|
|
244
|
+
const eventDuration = new Date(event.endDateTime).getTime() - new Date(event.startDateTime).getTime();
|
|
245
|
+
const recurrenceEnd = event.recurrenceEndDate ? new Date(event.recurrenceEndDate) : null;
|
|
246
|
+
const recurrenceType = event.recurrenceType;
|
|
247
|
+
const recurrenceDays = event.metadata?.recurrenceDays || [
|
|
248
|
+
new Date(event.startDateTime).getDay()
|
|
249
|
+
];
|
|
250
|
+
let currentStart = new Date(event.startDateTime);
|
|
251
|
+
let count = 0;
|
|
252
|
+
if (recurrenceType === _enums.RecurrenceType.WEEKLY || recurrenceType === _enums.RecurrenceType.BIWEEKLY) {
|
|
253
|
+
let weekStart = new Date(event.startDateTime);
|
|
254
|
+
weekStart.setDate(weekStart.getDate() - weekStart.getDay());
|
|
255
|
+
while(count < maxOccurrences){
|
|
256
|
+
for (const dayOfWeek of recurrenceDays){
|
|
257
|
+
if (count >= maxOccurrences) break;
|
|
258
|
+
currentStart = new Date(weekStart);
|
|
259
|
+
currentStart.setDate(currentStart.getDate() + dayOfWeek);
|
|
260
|
+
currentStart.setHours(new Date(event.startDateTime).getHours());
|
|
261
|
+
currentStart.setMinutes(new Date(event.startDateTime).getMinutes());
|
|
262
|
+
if (currentStart < new Date(event.startDateTime)) continue;
|
|
263
|
+
const shouldBreak = this.shouldStopRecurrence(currentStart, recurrenceEnd, rangeEnd);
|
|
264
|
+
if (shouldBreak) {
|
|
265
|
+
count = maxOccurrences;
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
const occurrence = this.tryCreateOccurrence(event, currentStart, eventDuration, rangeStart, rangeEnd, occurrences.length > 0);
|
|
269
|
+
if (occurrence) occurrences.push(occurrence);
|
|
270
|
+
count++;
|
|
271
|
+
}
|
|
272
|
+
const weeksToAdd = recurrenceType === _enums.RecurrenceType.BIWEEKLY ? 2 : 1;
|
|
273
|
+
weekStart.setDate(weekStart.getDate() + 7 * weeksToAdd);
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
276
|
+
const originalDayOfMonth = new Date(event.startDateTime).getDate();
|
|
277
|
+
while(count < maxOccurrences){
|
|
278
|
+
if (this.shouldStopRecurrence(currentStart, recurrenceEnd, rangeEnd)) break;
|
|
279
|
+
const occurrence = this.tryCreateOccurrence(event, currentStart, eventDuration, rangeStart, rangeEnd, count > 0);
|
|
280
|
+
if (occurrence) occurrences.push(occurrence);
|
|
281
|
+
currentStart = this.getNextOccurrenceDate(currentStart, recurrenceType, originalDayOfMonth);
|
|
282
|
+
count++;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return occurrences;
|
|
286
|
+
}
|
|
287
|
+
// Private utility helpers
|
|
288
|
+
async ensureParticipantRepositoryInitialized() {
|
|
289
|
+
if (!this.participantRepository) {
|
|
290
|
+
this.participantRepository = await this.dataSourceProvider.getRepository(_entities.EventParticipant);
|
|
291
|
+
}
|
|
292
|
+
return this.participantRepository;
|
|
293
|
+
}
|
|
294
|
+
async getParticipantEventIds(userId) {
|
|
295
|
+
const participantRepo = await this.ensureParticipantRepositoryInitialized();
|
|
296
|
+
const results = await participantRepo.createQueryBuilder('ep').select('ep.eventId').where('ep.userId = :userId', {
|
|
297
|
+
userId
|
|
298
|
+
}).andWhere('ep.deletedAt IS NULL').getRawMany();
|
|
299
|
+
return results.map((p)=>p.ep_event_id);
|
|
300
|
+
}
|
|
301
|
+
async loadParticipantsForEvents(events) {
|
|
302
|
+
const participantRepo = await this.ensureParticipantRepositoryInitialized();
|
|
303
|
+
const eventIds = events.map((e)=>e.id);
|
|
304
|
+
const participants = await participantRepo.find({
|
|
305
|
+
where: {
|
|
306
|
+
eventId: (0, _typeorm.In)(eventIds),
|
|
307
|
+
deletedAt: (0, _typeorm.IsNull)()
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
const participantsByEvent = new Map();
|
|
311
|
+
for (const p of participants){
|
|
312
|
+
const list = participantsByEvent.get(p.eventId) || [];
|
|
313
|
+
list.push(p);
|
|
314
|
+
participantsByEvent.set(p.eventId, list);
|
|
315
|
+
}
|
|
316
|
+
for (const event of events){
|
|
317
|
+
event.participants = participantsByEvent.get(event.id) || [];
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
applyEventCompanyFilter(query, user) {
|
|
321
|
+
(0, _utils.applyCompanyFilter)(query, {
|
|
322
|
+
isCompanyFeatureEnabled: this.eventConfig.isCompanyFeatureEnabled(),
|
|
323
|
+
entityAlias: 'event'
|
|
324
|
+
}, user);
|
|
325
|
+
}
|
|
326
|
+
shouldStopRecurrence(currentStart, recurrenceEnd, rangeEnd) {
|
|
327
|
+
return recurrenceEnd && currentStart > recurrenceEnd || currentStart > rangeEnd;
|
|
328
|
+
}
|
|
329
|
+
tryCreateOccurrence(event, currentStart, eventDuration, rangeStart, rangeEnd, isRecurrenceInstance) {
|
|
330
|
+
const currentEnd = new Date(currentStart.getTime() + eventDuration);
|
|
331
|
+
if (currentEnd >= rangeStart && currentStart <= rangeEnd) {
|
|
332
|
+
return {
|
|
333
|
+
...this.toCalendarEvent(event),
|
|
334
|
+
id: `${event.id}_${currentStart.toISOString()}`,
|
|
335
|
+
originalEventId: event.id,
|
|
336
|
+
isRecurrenceInstance,
|
|
337
|
+
startDateTime: new Date(currentStart),
|
|
338
|
+
endDateTime: currentEnd
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
getNextOccurrenceDate(current, recurrenceType, originalDayOfMonth) {
|
|
344
|
+
const next = new Date(current);
|
|
345
|
+
switch(recurrenceType){
|
|
346
|
+
case _enums.RecurrenceType.DAILY:
|
|
347
|
+
next.setDate(next.getDate() + 1);
|
|
348
|
+
break;
|
|
349
|
+
case _enums.RecurrenceType.MONTHLY:
|
|
350
|
+
{
|
|
351
|
+
const targetDay = originalDayOfMonth ?? current.getDate();
|
|
352
|
+
next.setMonth(next.getMonth() + 1);
|
|
353
|
+
const lastDayOfMonth = new Date(next.getFullYear(), next.getMonth() + 1, 0).getDate();
|
|
354
|
+
next.setDate(Math.min(targetDay, lastDayOfMonth));
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
default:
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
return next;
|
|
361
|
+
}
|
|
362
|
+
// Private transformation helpers
|
|
363
|
+
toCalendarEvent(event) {
|
|
364
|
+
return {
|
|
365
|
+
id: event.id,
|
|
366
|
+
title: event.title,
|
|
367
|
+
description: event.description,
|
|
368
|
+
meetingLink: event.meetingLink,
|
|
369
|
+
startDateTime: event.startDateTime,
|
|
370
|
+
endDateTime: event.endDateTime,
|
|
371
|
+
isAllDay: event.isAllDay,
|
|
372
|
+
recurrenceType: event.recurrenceType,
|
|
373
|
+
recurrenceEndDate: event.recurrenceEndDate,
|
|
374
|
+
color: event.color,
|
|
375
|
+
isActive: event.isActive,
|
|
376
|
+
metadata: event.metadata,
|
|
377
|
+
createdAt: event.createdAt,
|
|
378
|
+
updatedAt: event.updatedAt,
|
|
379
|
+
deletedAt: event.deletedAt,
|
|
380
|
+
createdById: event.createdById,
|
|
381
|
+
updatedById: event.updatedById,
|
|
382
|
+
deletedById: event.deletedById,
|
|
383
|
+
participants: event.participants?.map((p)=>this.toParticipantInfo(p))
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
toParticipantInfo(p) {
|
|
387
|
+
return {
|
|
388
|
+
id: p.id,
|
|
389
|
+
eventId: p.eventId,
|
|
390
|
+
userId: p.userId,
|
|
391
|
+
status: p.status,
|
|
392
|
+
isOrganizer: p.isOrganizer,
|
|
393
|
+
metadata: p.metadata,
|
|
394
|
+
createdAt: p.createdAt,
|
|
395
|
+
updatedAt: p.updatedAt,
|
|
396
|
+
deletedAt: p.deletedAt,
|
|
397
|
+
createdById: p.createdById,
|
|
398
|
+
updatedById: p.updatedById,
|
|
399
|
+
deletedById: p.deletedById
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
constructor(cacheManager, utilsService, eventConfig, dataSourceProvider){
|
|
403
|
+
super('event', null, cacheManager, utilsService, EventService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "eventConfig", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "participantRepository", void 0), _define_property(this, "pendingParticipantsList", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.eventConfig = eventConfig, this.dataSourceProvider = dataSourceProvider, this.participantRepository = null, this.pendingParticipantsList = [];
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
EventService = _ts_decorate([
|
|
407
|
+
(0, _common.Injectable)({
|
|
408
|
+
scope: _common.Scope.REQUEST
|
|
409
|
+
}),
|
|
410
|
+
_ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
|
|
411
|
+
_ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
|
|
412
|
+
_ts_param(2, (0, _common.Inject)(_eventmanagerconfigservice.EventManagerConfigService)),
|
|
413
|
+
_ts_param(3, (0, _common.Inject)(_eventmanagerdatasourceprovider.EventManagerDataSourceProvider)),
|
|
414
|
+
_ts_metadata("design:type", Function),
|
|
415
|
+
_ts_metadata("design:paramtypes", [
|
|
416
|
+
typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
|
|
417
|
+
typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
|
|
418
|
+
typeof _eventmanagerconfigservice.EventManagerConfigService === "undefined" ? Object : _eventmanagerconfigservice.EventManagerConfigService,
|
|
419
|
+
typeof _eventmanagerdatasourceprovider.EventManagerDataSourceProvider === "undefined" ? Object : _eventmanagerdatasourceprovider.EventManagerDataSourceProvider
|
|
420
|
+
])
|
|
421
|
+
], EventService);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
_export_star(require("./event-manager-config.service"), exports);
|
|
6
|
+
_export_star(require("./event-manager-datasource.provider"), exports);
|
|
7
|
+
_export_star(require("./event-manager-helper.service"), exports);
|
|
8
|
+
_export_star(require("./event.service"), exports);
|
|
9
|
+
_export_star(require("./event-participant.service"), exports);
|
|
10
|
+
function _export_star(from, to) {
|
|
11
|
+
Object.keys(from).forEach(function(k) {
|
|
12
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
13
|
+
Object.defineProperty(to, k, {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function() {
|
|
16
|
+
return from[k];
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
return from;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const EVENT_MANAGER_MODULE_OPTIONS = "EVENT_MANAGER_MODULE_OPTIONS";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './event-manager.constants';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ListResponseDto, MessageResponseDto, SingleResponseDto } from '@flusys/nestjs-shared/dtos';
|
|
2
|
+
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
3
|
+
import { CreateEventParticipantDto, EventParticipantResponseDto, UpdateParticipantStatusDto, UpdateEventParticipantDto } from '../dtos';
|
|
4
|
+
import { EventParticipantService } from '../services/event-participant.service';
|
|
5
|
+
declare const EventParticipantController_base: abstract new (service: EventParticipantService) => {
|
|
6
|
+
service: EventParticipantService;
|
|
7
|
+
insert(addDto: CreateEventParticipantDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<EventParticipantResponseDto>>;
|
|
8
|
+
insertMany(addDto: CreateEventParticipantDto[], user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").BulkResponseDto<EventParticipantResponseDto>>;
|
|
9
|
+
getById(id: string, body: import("@flusys/nestjs-shared/dtos").GetByIdBodyDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<EventParticipantResponseDto>>;
|
|
10
|
+
update(updateDto: UpdateEventParticipantDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<EventParticipantResponseDto>>;
|
|
11
|
+
updateMany(updateDtos: UpdateEventParticipantDto[], user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").BulkResponseDto<EventParticipantResponseDto>>;
|
|
12
|
+
getAll(filterAndPaginationDto: import("@flusys/nestjs-shared/dtos").FilterAndPaginationDto, user: ILoggedUserInfo | null, search?: string): Promise<ListResponseDto<EventParticipantResponseDto>>;
|
|
13
|
+
delete(deleteDto: import("@flusys/nestjs-shared/dtos").DeleteDto, user: ILoggedUserInfo | null): Promise<MessageResponseDto>;
|
|
14
|
+
};
|
|
15
|
+
export declare class EventParticipantController extends EventParticipantController_base {
|
|
16
|
+
protected participantService: EventParticipantService;
|
|
17
|
+
constructor(participantService: EventParticipantService);
|
|
18
|
+
updateStatus(dto: UpdateParticipantStatusDto, user: ILoggedUserInfo): Promise<SingleResponseDto<EventParticipantResponseDto>>;
|
|
19
|
+
getByEvent(body: {
|
|
20
|
+
eventId: string;
|
|
21
|
+
}, user: ILoggedUserInfo): Promise<ListResponseDto<EventParticipantResponseDto>>;
|
|
22
|
+
getByUser(body: {
|
|
23
|
+
userId: string;
|
|
24
|
+
}, user: ILoggedUserInfo): Promise<ListResponseDto<EventParticipantResponseDto>>;
|
|
25
|
+
removeParticipant(body: {
|
|
26
|
+
eventId: string;
|
|
27
|
+
userId: string;
|
|
28
|
+
}, user: ILoggedUserInfo): Promise<MessageResponseDto>;
|
|
29
|
+
private buildListResponse;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ListResponseDto, SingleResponseDto } from '@flusys/nestjs-shared/dtos';
|
|
2
|
+
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
3
|
+
import { BulkAddParticipantsDto, CalendarQueryDto, CalendarEventResponseDto, CreateEventDto, EventParticipantResponseDto, EventResponseDto, UpdateEventDto } from '../dtos';
|
|
4
|
+
import { EventService } from '../services/event.service';
|
|
5
|
+
declare const EventController_base: abstract new (service: EventService) => {
|
|
6
|
+
service: EventService;
|
|
7
|
+
insert(addDto: CreateEventDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<EventResponseDto>>;
|
|
8
|
+
insertMany(addDto: CreateEventDto[], user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").BulkResponseDto<EventResponseDto>>;
|
|
9
|
+
getById(id: string, body: import("@flusys/nestjs-shared/dtos").GetByIdBodyDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<EventResponseDto>>;
|
|
10
|
+
update(updateDto: UpdateEventDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<EventResponseDto>>;
|
|
11
|
+
updateMany(updateDtos: UpdateEventDto[], user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").BulkResponseDto<EventResponseDto>>;
|
|
12
|
+
getAll(filterAndPaginationDto: import("@flusys/nestjs-shared/dtos").FilterAndPaginationDto, user: ILoggedUserInfo | null, search?: string): Promise<ListResponseDto<EventResponseDto>>;
|
|
13
|
+
delete(deleteDto: import("@flusys/nestjs-shared/dtos").DeleteDto, user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").MessageResponseDto>;
|
|
14
|
+
};
|
|
15
|
+
export declare class EventController extends EventController_base {
|
|
16
|
+
protected eventService: EventService;
|
|
17
|
+
constructor(eventService: EventService);
|
|
18
|
+
getCalendarEvents(dto: CalendarQueryDto, user: ILoggedUserInfo): Promise<ListResponseDto<CalendarEventResponseDto>>;
|
|
19
|
+
getEventWithParticipants(body: {
|
|
20
|
+
id: string;
|
|
21
|
+
}, user: ILoggedUserInfo): Promise<SingleResponseDto<EventResponseDto>>;
|
|
22
|
+
addParticipants(dto: BulkAddParticipantsDto, user: ILoggedUserInfo): Promise<SingleResponseDto<EventParticipantResponseDto[]>>;
|
|
23
|
+
}
|
|
24
|
+
export {};
|