UNPKG

@checkfirst/nestjs-outlook

Version:

An opinionated NestJS module for Microsoft Outlook integration that provides easy access to Microsoft Graph API for emails, calendars, and more.

201 lines 10.6 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 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; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var LifecycleEventHandlerService_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.LifecycleEventHandlerService = void 0; const common_1 = require("@nestjs/common"); const event_emitter_1 = require("@nestjs/event-emitter"); const lifecycle_event_types_enum_1 = require("../../enums/lifecycle-event-types.enum"); const event_types_enum_1 = require("../../enums/event-types.enum"); const outlook_webhook_subscription_repository_1 = require("../../repositories/outlook-webhook-subscription.repository"); const calendar_service_1 = require("./calendar.service"); const user_id_converter_service_1 = require("../shared/user-id-converter.service"); let LifecycleEventHandlerService = LifecycleEventHandlerService_1 = class LifecycleEventHandlerService { constructor(calendarService, subscriptionRepository, eventEmitter, userIdConverter) { this.calendarService = calendarService; this.subscriptionRepository = subscriptionRepository; this.eventEmitter = eventEmitter; this.userIdConverter = userIdConverter; this.logger = new common_1.Logger(LifecycleEventHandlerService_1.name); } async handleLifecycleEvent(notificationItem) { const { lifecycleEvent, subscriptionId, tenantId } = notificationItem; if (!lifecycleEvent) { return { success: false, message: 'Missing lifecycleEvent field', }; } if (!subscriptionId) { this.logger.warn('Lifecycle event received without subscriptionId'); return { success: false, message: 'Missing subscriptionId field', }; } this.logger.log(`Handling lifecycle event: ${lifecycleEvent} for subscription ${subscriptionId}`); try { switch (lifecycleEvent) { case lifecycle_event_types_enum_1.LifecycleEventType.REAUTHORIZATION_REQUIRED: return await this.handleReauthorizationRequired(subscriptionId, tenantId); case lifecycle_event_types_enum_1.LifecycleEventType.SUBSCRIPTION_REMOVED: return await this.handleSubscriptionRemoved(subscriptionId, tenantId); case lifecycle_event_types_enum_1.LifecycleEventType.MISSED: return await this.handleMissedNotifications(subscriptionId, tenantId); default: this.logger.warn(`Unknown lifecycle event type: ${lifecycleEvent}`); return { success: false, message: `Unknown lifecycle event type: ${lifecycleEvent}`, }; } } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; this.logger.error(`Error handling lifecycle event ${lifecycleEvent}: ${errorMessage}`); return { success: false, message: errorMessage, }; } } async handleReauthorizationRequired(subscriptionId, tenantId) { this.logger.log(`[REAUTHORIZATION_REQUIRED] Subscription ${subscriptionId} requires reauthorization`); try { const subscription = await this.subscriptionRepository.findBySubscriptionId(subscriptionId); if (!subscription) { this.logger.warn(`[REAUTHORIZATION_REQUIRED] Subscription ${subscriptionId} not found in database`); return { success: false, message: 'Subscription not found', }; } this.logger.log(`[REAUTHORIZATION_REQUIRED] Attempting to renew subscription ${subscriptionId}`); const renewedSubscription = await this.calendarService.renewWebhookSubscription(subscriptionId, subscription.userId); const expirationDate = renewedSubscription.expirationDateTime ? new Date(renewedSubscription.expirationDateTime).toISOString() : 'unknown'; this.logger.log(`[REAUTHORIZATION_REQUIRED] Successfully renewed subscription ${subscriptionId}. New expiration: ${expirationDate}`); this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.LIFECYCLE_REAUTHORIZATION_REQUIRED, { subscriptionId, tenantId, userId: subscription.userId, renewalSuccessful: true, }); return { success: true, message: 'Subscription renewed successfully', }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; this.logger.error(`[REAUTHORIZATION_REQUIRED] Failed to renew subscription ${subscriptionId}: ${errorMessage}`); this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.LIFECYCLE_REAUTHORIZATION_REQUIRED, { subscriptionId, tenantId, renewalSuccessful: false, error: errorMessage, }); return { success: false, message: `Failed to renew subscription: ${errorMessage}`, }; } } async handleSubscriptionRemoved(subscriptionId, tenantId) { this.logger.warn(`[SUBSCRIPTION_REMOVED] Subscription ${subscriptionId} has been removed by Microsoft Graph`); try { const subscription = await this.subscriptionRepository.findBySubscriptionId(subscriptionId); if (!subscription) { this.logger.warn(`[SUBSCRIPTION_REMOVED] Subscription ${subscriptionId} not found in database`); return { success: true, message: 'Subscription not found (already removed)', }; } await this.subscriptionRepository.deactivateSubscription(subscriptionId); this.logger.log(`[SUBSCRIPTION_REMOVED] Deactivated subscription ${subscriptionId} in database`); this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.LIFECYCLE_SUBSCRIPTION_REMOVED, { subscriptionId, tenantId, userId: subscription.userId, resource: subscription.resource, }); return { success: true, message: 'Subscription marked as inactive', }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; this.logger.error(`[SUBSCRIPTION_REMOVED] Error handling removed subscription ${subscriptionId}: ${errorMessage}`); return { success: false, message: errorMessage, }; } } async handleMissedNotifications(subscriptionId, tenantId) { this.logger.warn(`[MISSED] Notifications were missed for subscription ${subscriptionId}. Triggering delta sync.`); try { const subscription = await this.subscriptionRepository.findBySubscriptionId(subscriptionId); if (!subscription) { this.logger.warn(`[MISSED] Subscription ${subscriptionId} not found in database`); return { success: false, message: 'Subscription not found', }; } this.logger.log(`[MISSED] Starting delta sync for user ${subscription.userId} to recover missed changes`); const externalUserId = await this.userIdConverter.internalToExternal(subscription.userId); const changes = await this.calendarService.fetchAndSortChanges(externalUserId, false); const changesCount = changes.length; this.logger.log(`[MISSED] Delta sync completed. Found ${changesCount} changes for subscription ${subscriptionId}`); this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.LIFECYCLE_MISSED, { subscriptionId, tenantId, userId: subscription.userId, changesFound: changesCount, }); return { success: true, message: `Delta sync completed. Found ${changesCount} changes.`, }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; this.logger.error(`[MISSED] Error during delta sync for subscription ${subscriptionId}: ${errorMessage}`); this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.LIFECYCLE_MISSED, { subscriptionId, tenantId, syncSuccessful: false, error: errorMessage, }); return { success: false, message: `Delta sync failed: ${errorMessage}`, }; } } }; exports.LifecycleEventHandlerService = LifecycleEventHandlerService; exports.LifecycleEventHandlerService = LifecycleEventHandlerService = LifecycleEventHandlerService_1 = __decorate([ (0, common_1.Injectable)(), __param(0, (0, common_1.Inject)((0, common_1.forwardRef)(() => calendar_service_1.CalendarService))), __metadata("design:paramtypes", [calendar_service_1.CalendarService, outlook_webhook_subscription_repository_1.OutlookWebhookSubscriptionRepository, event_emitter_1.EventEmitter2, user_id_converter_service_1.UserIdConverterService]) ], LifecycleEventHandlerService); //# sourceMappingURL=lifecycle-event-handler.service.js.map