@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.
Files changed (89) hide show
  1. package/README.md +1328 -0
  2. package/adapters/event-manager.adapter.d.ts +12 -0
  3. package/adapters/index.d.ts +1 -0
  4. package/cjs/adapters/event-manager.adapter.js +71 -0
  5. package/cjs/adapters/index.js +18 -0
  6. package/cjs/config/event-manager.constants.js +13 -0
  7. package/cjs/config/index.js +18 -0
  8. package/cjs/controllers/event-participant.controller.js +271 -0
  9. package/cjs/controllers/event.controller.js +229 -0
  10. package/cjs/controllers/index.js +19 -0
  11. package/cjs/docs/event-manager-swagger.config.js +135 -0
  12. package/cjs/docs/index.js +24 -0
  13. package/cjs/dtos/calendar-query.dto.js +186 -0
  14. package/cjs/dtos/event-participant.dto.js +226 -0
  15. package/cjs/dtos/event.dto.js +291 -0
  16. package/cjs/dtos/index.js +20 -0
  17. package/cjs/entities/event-participant.entity.js +96 -0
  18. package/cjs/entities/event-with-company.entity.js +56 -0
  19. package/cjs/entities/event.entity.js +143 -0
  20. package/cjs/entities/index.js +55 -0
  21. package/cjs/index.js +27 -0
  22. package/cjs/interfaces/event-manager-module.interface.js +4 -0
  23. package/cjs/interfaces/event.interface.js +4 -0
  24. package/cjs/interfaces/index.js +19 -0
  25. package/cjs/modules/event-manager.module.js +133 -0
  26. package/cjs/modules/index.js +18 -0
  27. package/cjs/services/event-manager-config.service.js +76 -0
  28. package/cjs/services/event-manager-datasource.provider.js +181 -0
  29. package/cjs/services/event-manager-helper.service.js +253 -0
  30. package/cjs/services/event-participant.service.js +164 -0
  31. package/cjs/services/event.service.js +421 -0
  32. package/cjs/services/index.js +22 -0
  33. package/config/event-manager.constants.d.ts +1 -0
  34. package/config/index.d.ts +1 -0
  35. package/controllers/event-participant.controller.d.ts +31 -0
  36. package/controllers/event.controller.d.ts +24 -0
  37. package/controllers/index.d.ts +2 -0
  38. package/docs/event-manager-swagger.config.d.ts +3 -0
  39. package/docs/index.d.ts +2 -0
  40. package/dtos/calendar-query.dto.d.ts +23 -0
  41. package/dtos/event-participant.dto.d.ts +31 -0
  42. package/dtos/event.dto.d.ts +37 -0
  43. package/dtos/index.d.ts +3 -0
  44. package/entities/event-participant.entity.d.ts +8 -0
  45. package/entities/event-with-company.entity.d.ts +4 -0
  46. package/entities/event.entity.d.ts +14 -0
  47. package/entities/index.d.ts +11 -0
  48. package/fesm/adapters/event-manager.adapter.js +61 -0
  49. package/fesm/adapters/index.js +1 -0
  50. package/fesm/config/event-manager.constants.js +3 -0
  51. package/fesm/config/index.js +1 -0
  52. package/fesm/controllers/event-participant.controller.js +261 -0
  53. package/fesm/controllers/event.controller.js +219 -0
  54. package/fesm/controllers/index.js +2 -0
  55. package/fesm/docs/event-manager-swagger.config.js +128 -0
  56. package/fesm/docs/index.js +4 -0
  57. package/fesm/dtos/calendar-query.dto.js +168 -0
  58. package/fesm/dtos/event-participant.dto.js +199 -0
  59. package/fesm/dtos/event.dto.js +270 -0
  60. package/fesm/dtos/index.js +3 -0
  61. package/fesm/entities/event-participant.entity.js +86 -0
  62. package/fesm/entities/event-with-company.entity.js +46 -0
  63. package/fesm/entities/event.entity.js +133 -0
  64. package/fesm/entities/index.js +24 -0
  65. package/fesm/index.js +10 -0
  66. package/fesm/interfaces/event-manager-module.interface.js +3 -0
  67. package/fesm/interfaces/event.interface.js +1 -0
  68. package/fesm/interfaces/index.js +2 -0
  69. package/fesm/modules/event-manager.module.js +123 -0
  70. package/fesm/modules/index.js +1 -0
  71. package/fesm/services/event-manager-config.service.js +66 -0
  72. package/fesm/services/event-manager-datasource.provider.js +130 -0
  73. package/fesm/services/event-manager-helper.service.js +243 -0
  74. package/fesm/services/event-participant.service.js +154 -0
  75. package/fesm/services/event.service.js +411 -0
  76. package/fesm/services/index.js +5 -0
  77. package/index.d.ts +9 -0
  78. package/interfaces/event-manager-module.interface.d.ts +20 -0
  79. package/interfaces/event.interface.d.ts +28 -0
  80. package/interfaces/index.d.ts +2 -0
  81. package/modules/event-manager.module.d.ts +8 -0
  82. package/modules/index.d.ts +1 -0
  83. package/package.json +89 -0
  84. package/services/event-manager-config.service.d.ts +13 -0
  85. package/services/event-manager-datasource.provider.d.ts +23 -0
  86. package/services/event-manager-helper.service.d.ts +27 -0
  87. package/services/event-participant.service.d.ts +27 -0
  88. package/services/event.service.d.ts +49 -0
  89. package/services/index.d.ts +5 -0
@@ -0,0 +1,243 @@
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, Logger, NotFoundException } from '@nestjs/common';
29
+ import { In, IsNull } from 'typeorm';
30
+ import { HybridCache } from '@flusys/nestjs-shared/classes';
31
+ import { UtilsService } from '@flusys/nestjs-shared/modules';
32
+ import { ParticipantStatus, RecurrenceType } from '@flusys/nestjs-shared';
33
+ import { EventManagerConfigService } from './event-manager-config.service';
34
+ import { EventManagerDataSourceProvider } from './event-manager-datasource.provider';
35
+ import { Event, EventWithCompany, EventParticipant } from '../entities';
36
+ export class EventManagerHelperService {
37
+ async getDataSource() {
38
+ if (!this.dataSource) {
39
+ this.dataSource = await this.dataSourceProvider.getDataSource();
40
+ }
41
+ return this.dataSource;
42
+ }
43
+ async getEventRepository() {
44
+ const ds = await this.getDataSource();
45
+ const EntityClass = this.configService.isCompanyFeatureEnabled() ? EventWithCompany : Event;
46
+ return ds.getRepository(EntityClass);
47
+ }
48
+ async getParticipantRepository() {
49
+ const ds = await this.getDataSource();
50
+ return ds.getRepository(EventParticipant);
51
+ }
52
+ async createEvent(options) {
53
+ const repo = await this.getEventRepository();
54
+ const entity = {
55
+ title: options.title,
56
+ description: options.description ?? null,
57
+ meetingLink: options.meetingLink ?? null,
58
+ startDateTime: options.startDateTime,
59
+ endDateTime: options.endDateTime,
60
+ isAllDay: options.isAllDay ?? false,
61
+ recurrenceType: options.recurrenceType ?? RecurrenceType.NONE,
62
+ recurrenceEndDate: options.recurrenceEndDate ?? null,
63
+ color: options.color ?? this.configService.getDefaultColor(),
64
+ isActive: true,
65
+ metadata: options.metadata ?? null
66
+ };
67
+ if (this.configService.isCompanyFeatureEnabled() && options.companyId) {
68
+ entity.companyId = options.companyId;
69
+ }
70
+ const saved = await repo.save(entity);
71
+ await this.addEventParticipants(saved.id, options.participantIds ?? [], options.organizerId);
72
+ await this.clearCache();
73
+ this.logger.debug(`Event created: ${saved.id} - ${options.title}`);
74
+ return this.toEventResult(saved);
75
+ }
76
+ async addParticipants(eventId, userIds, _companyId) {
77
+ const eventRepo = await this.getEventRepository();
78
+ const participantRepo = await this.getParticipantRepository();
79
+ const event = await eventRepo.findOne({
80
+ where: {
81
+ id: eventId,
82
+ deletedAt: IsNull()
83
+ }
84
+ });
85
+ if (!event) {
86
+ throw new NotFoundException('Event not found');
87
+ }
88
+ const existingParticipants = await participantRepo.find({
89
+ where: {
90
+ eventId,
91
+ userId: In(userIds),
92
+ deletedAt: IsNull()
93
+ }
94
+ });
95
+ const existingUserIds = new Set(existingParticipants.map((p)=>p.userId));
96
+ const newParticipants = userIds.filter((userId)=>!existingUserIds.has(userId)).map((userId)=>({
97
+ eventId,
98
+ userId,
99
+ status: ParticipantStatus.PENDING,
100
+ isOrganizer: false
101
+ }));
102
+ if (newParticipants.length > 0) {
103
+ await participantRepo.save(newParticipants);
104
+ this.logger.debug(`Added ${newParticipants.length} participants to event ${eventId}`);
105
+ }
106
+ }
107
+ async removeParticipant(eventId, userId) {
108
+ const participantRepo = await this.getParticipantRepository();
109
+ const participant = await participantRepo.findOne({
110
+ where: {
111
+ eventId,
112
+ userId,
113
+ deletedAt: IsNull()
114
+ }
115
+ });
116
+ if (participant) {
117
+ await participantRepo.softRemove(participant);
118
+ this.logger.debug(`Removed participant ${userId} from event ${eventId}`);
119
+ }
120
+ }
121
+ async updateParticipantStatus(participantId, status) {
122
+ const participantRepo = await this.getParticipantRepository();
123
+ const participant = await participantRepo.findOne({
124
+ where: {
125
+ id: participantId,
126
+ deletedAt: IsNull()
127
+ }
128
+ });
129
+ if (!participant) {
130
+ throw new NotFoundException('Event participant not found');
131
+ }
132
+ participant.status = status;
133
+ await participantRepo.save(participant);
134
+ this.logger.debug(`Updated participant ${participantId} status to ${status}`);
135
+ }
136
+ async getEventsForUser(userId, startDate, endDate, companyId) {
137
+ const eventRepo = await this.getEventRepository();
138
+ const participantRepo = await this.getParticipantRepository();
139
+ const participantEvents = await participantRepo.createQueryBuilder('ep').select('ep.eventId').where('ep.userId = :userId', {
140
+ userId
141
+ }).andWhere('ep.deletedAt IS NULL').getRawMany();
142
+ const eventIds = participantEvents.map((p)=>p.ep_event_id);
143
+ if (eventIds.length === 0) {
144
+ return [];
145
+ }
146
+ const query = eventRepo.createQueryBuilder('event').where('event.id IN (:...eventIds)', {
147
+ eventIds
148
+ }).andWhere('event.deletedAt IS NULL').andWhere('event.isActive = :isActive', {
149
+ isActive: true
150
+ }).andWhere('event.startDateTime <= :endDate', {
151
+ endDate
152
+ }).andWhere('event.endDateTime >= :startDate', {
153
+ startDate
154
+ });
155
+ if (this.configService.isCompanyFeatureEnabled() && companyId) {
156
+ query.andWhere('event.companyId = :companyId', {
157
+ companyId
158
+ });
159
+ }
160
+ const events = await query.getMany();
161
+ return events.map((e)=>this.toEventResult(e));
162
+ }
163
+ async getEventById(eventId) {
164
+ const repo = await this.getEventRepository();
165
+ const event = await repo.findOne({
166
+ where: {
167
+ id: eventId,
168
+ deletedAt: IsNull()
169
+ }
170
+ });
171
+ return event ? this.toEventResult(event) : null;
172
+ }
173
+ async addEventParticipants(eventId, participantIds, organizerId) {
174
+ if (!organizerId && participantIds.length === 0) return;
175
+ const participantRepo = await this.getParticipantRepository();
176
+ const allUserIds = new Set([
177
+ ...organizerId ? [
178
+ organizerId
179
+ ] : [],
180
+ ...participantIds
181
+ ]);
182
+ const participants = Array.from(allUserIds).map((userId)=>({
183
+ eventId,
184
+ userId,
185
+ status: ParticipantStatus.PENDING,
186
+ isOrganizer: userId === organizerId
187
+ }));
188
+ await participantRepo.save(participants);
189
+ }
190
+ toEventResult(event) {
191
+ const eventExt = event;
192
+ return {
193
+ id: event.id,
194
+ title: event.title,
195
+ description: event.description,
196
+ meetingLink: event.meetingLink,
197
+ startDateTime: event.startDateTime,
198
+ endDateTime: event.endDateTime,
199
+ isAllDay: event.isAllDay,
200
+ recurrenceType: event.recurrenceType,
201
+ recurrenceEndDate: event.recurrenceEndDate,
202
+ color: event.color,
203
+ isActive: event.isActive,
204
+ metadata: event.metadata,
205
+ companyId: eventExt.companyId ?? null,
206
+ createdAt: event.createdAt,
207
+ updatedAt: event.updatedAt
208
+ };
209
+ }
210
+ async clearCache() {
211
+ await this.utilsService.clearCache(this.eventEntityName, this.cacheManager);
212
+ }
213
+ constructor(cacheManager, utilsService, configService, dataSourceProvider){
214
+ _define_property(this, "cacheManager", void 0);
215
+ _define_property(this, "utilsService", void 0);
216
+ _define_property(this, "configService", void 0);
217
+ _define_property(this, "dataSourceProvider", void 0);
218
+ _define_property(this, "logger", void 0);
219
+ _define_property(this, "eventEntityName", void 0);
220
+ _define_property(this, "dataSource", void 0);
221
+ this.cacheManager = cacheManager;
222
+ this.utilsService = utilsService;
223
+ this.configService = configService;
224
+ this.dataSourceProvider = dataSourceProvider;
225
+ this.logger = new Logger(EventManagerHelperService.name);
226
+ this.eventEntityName = 'event';
227
+ this.dataSource = null;
228
+ }
229
+ }
230
+ EventManagerHelperService = _ts_decorate([
231
+ Injectable(),
232
+ _ts_param(0, Inject('CACHE_INSTANCE')),
233
+ _ts_param(1, Inject(UtilsService)),
234
+ _ts_param(2, Inject(EventManagerConfigService)),
235
+ _ts_param(3, Inject(EventManagerDataSourceProvider)),
236
+ _ts_metadata("design:type", Function),
237
+ _ts_metadata("design:paramtypes", [
238
+ typeof HybridCache === "undefined" ? Object : HybridCache,
239
+ typeof UtilsService === "undefined" ? Object : UtilsService,
240
+ typeof EventManagerConfigService === "undefined" ? Object : EventManagerConfigService,
241
+ typeof EventManagerDataSourceProvider === "undefined" ? Object : EventManagerDataSourceProvider
242
+ ])
243
+ ], EventManagerHelperService);
@@ -0,0 +1,154 @@
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, RequestScopedApiService } from '@flusys/nestjs-shared/classes';
29
+ import { ParticipantStatus } from '@flusys/nestjs-shared/enums';
30
+ import { UtilsService } from '@flusys/nestjs-shared/modules';
31
+ import { Inject, Injectable, NotFoundException, Scope } from '@nestjs/common';
32
+ import { EventManagerConfigService } from './event-manager-config.service';
33
+ import { EventParticipant } from '../entities';
34
+ import { EventManagerDataSourceProvider } from './event-manager-datasource.provider';
35
+ export class EventParticipantService extends RequestScopedApiService {
36
+ resolveEntity() {
37
+ // EventParticipant doesn't need company variant - company context is inherited through Event
38
+ return EventParticipant;
39
+ }
40
+ getDataSourceProvider() {
41
+ return this.dataSourceProvider;
42
+ }
43
+ // Override Methods
44
+ async convertSingleDtoToEntity(dto, _user) {
45
+ let entity = {};
46
+ if ('id' in dto && dto.id && typeof dto.id === 'string') {
47
+ const existing = await this.repository.findOne({
48
+ where: {
49
+ id: dto.id
50
+ }
51
+ });
52
+ if (!existing) throw new NotFoundException('Event participant not found');
53
+ entity = existing;
54
+ }
55
+ // EventParticipant doesn't have companyId - company context comes from Event
56
+ return {
57
+ ...entity,
58
+ eventId: dto.eventId ?? entity.eventId,
59
+ userId: dto.userId ?? entity.userId,
60
+ status: dto.status ?? entity.status ?? ParticipantStatus.PENDING,
61
+ isOrganizer: dto.isOrganizer ?? entity.isOrganizer ?? false,
62
+ metadata: dto.metadata ?? entity.metadata
63
+ };
64
+ }
65
+ async getFilterQuery(query, filter, _user) {
66
+ for (const [key, value] of Object.entries(filter)){
67
+ if (key === 'eventId') {
68
+ query.andWhere(`${this.entityName}.eventId = :eventId`, {
69
+ eventId: value
70
+ });
71
+ } else if (key === 'userId') {
72
+ query.andWhere(`${this.entityName}.userId = :userId`, {
73
+ userId: value
74
+ });
75
+ } else if (key === 'status') {
76
+ query.andWhere(`${this.entityName}.status = :status`, {
77
+ status: value
78
+ });
79
+ } else if (key === 'isOrganizer' && typeof value === 'boolean') {
80
+ query.andWhere(`${this.entityName}.isOrganizer = :isOrganizer`, {
81
+ isOrganizer: value
82
+ });
83
+ } else {
84
+ query.andWhere(`${this.entityName}.${key} = :value`, {
85
+ value
86
+ });
87
+ }
88
+ }
89
+ return {
90
+ query,
91
+ isRaw: false
92
+ };
93
+ }
94
+ // Public Methods
95
+ // Note: EventParticipant doesn't have companyId - company filtering happens at Event level
96
+ async updateStatus(dto, _user) {
97
+ await this.ensureRepositoryInitialized();
98
+ const participant = await this.repository.findOne({
99
+ where: {
100
+ id: dto.id
101
+ }
102
+ });
103
+ if (!participant) {
104
+ throw new NotFoundException('Event participant not found');
105
+ }
106
+ participant.status = dto.status;
107
+ return this.repository.save(participant);
108
+ }
109
+ async getParticipantsByEvent(eventId, _user) {
110
+ await this.ensureRepositoryInitialized();
111
+ // Company filtering happens at Event level, not participant level
112
+ return this.repository.createQueryBuilder('event_participant').where('event_participant.eventId = :eventId', {
113
+ eventId
114
+ }).andWhere('event_participant.deletedAt IS NULL').getMany();
115
+ }
116
+ async getParticipantsByUser(userId, _user) {
117
+ await this.ensureRepositoryInitialized();
118
+ // Company filtering happens at Event level, not participant level
119
+ return this.repository.createQueryBuilder('event_participant').where('event_participant.userId = :userId', {
120
+ userId
121
+ }).andWhere('event_participant.deletedAt IS NULL').getMany();
122
+ }
123
+ async removeParticipant(eventId, userId, _user) {
124
+ await this.ensureRepositoryInitialized();
125
+ const participant = await this.repository.findOne({
126
+ where: {
127
+ eventId,
128
+ userId
129
+ }
130
+ });
131
+ if (participant) {
132
+ await this.repository.softRemove(participant);
133
+ }
134
+ }
135
+ constructor(cacheManager, utilsService, eventConfig, dataSourceProvider){
136
+ 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;
137
+ }
138
+ }
139
+ EventParticipantService = _ts_decorate([
140
+ Injectable({
141
+ scope: Scope.REQUEST
142
+ }),
143
+ _ts_param(0, Inject('CACHE_INSTANCE')),
144
+ _ts_param(1, Inject(UtilsService)),
145
+ _ts_param(2, Inject(EventManagerConfigService)),
146
+ _ts_param(3, Inject(EventManagerDataSourceProvider)),
147
+ _ts_metadata("design:type", Function),
148
+ _ts_metadata("design:paramtypes", [
149
+ typeof HybridCache === "undefined" ? Object : HybridCache,
150
+ typeof UtilsService === "undefined" ? Object : UtilsService,
151
+ typeof EventManagerConfigService === "undefined" ? Object : EventManagerConfigService,
152
+ typeof EventManagerDataSourceProvider === "undefined" ? Object : EventManagerDataSourceProvider
153
+ ])
154
+ ], EventParticipantService);