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.

166 lines 8.16 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 CalendarController_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.CalendarController = void 0; const common_1 = require("@nestjs/common"); const swagger_1 = require("@nestjs/swagger"); const calendar_service_1 = require("../services/calendar/calendar.service"); const outlook_webhook_notification_dto_1 = require("../dto/outlook-webhook-notification.dto"); let CalendarController = CalendarController_1 = class CalendarController { constructor(calendarService) { this.calendarService = calendarService; this.logger = new common_1.Logger(CalendarController_1.name); } async handleCalendarWebhook(validationToken, notificationBody, req, res) { if (validationToken) { this.logger.log('Handling Microsoft Graph validation request'); const decodedToken = decodeURIComponent(validationToken); res.set('Content-Type', 'text/plain; charset=utf-8'); res.send(decodedToken); return; } try { this.logger.debug(`Received webhook notification: ${JSON.stringify(notificationBody)}`); if (Array.isArray(notificationBody.value) && notificationBody.value.length > 2) { this.logger.log(`Received batch of ${notificationBody.value.length.toString()} notifications, responding with 202 Accepted`); res.status(202).json({ success: true, message: 'Notifications accepted for processing', }); this.processCalendarNotificationBatch(notificationBody).catch((error) => { const errorMessage = error instanceof Error ? error.message : String(error); this.logger.error(`Error processing notification batch: ${errorMessage}`); }); return; } if (Array.isArray(notificationBody.value) && notificationBody.value.length > 0) { const results = await this.processCalendarNotificationBatch(notificationBody); res.json({ success: true, message: `Processed ${results.successCount.toString()} out of ${notificationBody.value.length.toString()} notifications`, }); return; } this.logger.warn('Received webhook notification with unexpected format'); res.json({ success: true, message: `Received webhook notification with unexpected format`, }); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); const errorStack = error instanceof Error ? error.stack : undefined; this.logger.error(`Error processing webhook notification: ${errorMessage}`, errorStack); res.status(500).json({ success: false, message: 'Error processing webhook notification', }); } } async processCalendarNotificationBatch(notificationBody) { let successCount = 0; let failureCount = 0; const processedEvents = new Set(); for (const item of notificationBody.value) { if (!item.subscriptionId || !item.resource) { this.logger.warn(`Skipping notification with missing required fields`); failureCount++; continue; } const resourceData = item.resourceData; if (resourceData.id && processedEvents.has(resourceData.id)) { this.logger.debug(`Skipping duplicate event: ${resourceData.id}`); continue; } if (resourceData.id) { processedEvents.add(resourceData.id); } const validChangeTypes = ['created', 'updated', 'deleted']; if (!validChangeTypes.includes(item.changeType)) { this.logger.warn(`Skipping notification with unsupported change type: ${item.changeType}`); failureCount++; continue; } try { const changeNotification = { subscriptionId: item.subscriptionId, subscriptionExpirationDateTime: item.subscriptionExpirationDateTime, changeType: item.changeType, resource: item.resource, resourceData: resourceData, clientState: item.clientState, tenantId: item.tenantId, }; const result = await this.calendarService.handleOutlookWebhook(changeNotification); if (result.success) { this.logger.log(`Successfully processed ${item.changeType} event for resource ID: ${resourceData.id || 'unknown'}`); successCount++; } else { this.logger.warn(`Failed to process event: ${result.message}`); failureCount++; } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); this.logger.error(`Error processing event: ${errorMessage}`); failureCount++; } } this.logger.log(`Finished processing batch: ${successCount.toString()} succeeded, ${failureCount.toString()} failed`); return { successCount, failureCount }; } }; exports.CalendarController = CalendarController; __decorate([ (0, common_1.Post)('webhook'), (0, common_1.HttpCode)(200), (0, swagger_1.ApiResponse)({ status: 200, description: 'Webhook validation or notification processed successfully', }), (0, swagger_1.ApiResponse)({ status: 202, description: 'Notification accepted for processing', }), (0, swagger_1.ApiResponse)({ status: 500, description: 'Server error processing the notification', }), (0, swagger_1.ApiQuery)({ name: 'validationToken', required: false, description: 'Token sent by Microsoft Graph to validate the webhook endpoint', }), (0, swagger_1.ApiBody)({ description: 'Microsoft Graph webhook notification payload', type: outlook_webhook_notification_dto_1.OutlookWebhookNotificationDto, required: false, }), __param(0, (0, common_1.Query)('validationToken')), __param(1, (0, common_1.Body)()), __param(2, (0, common_1.Req)()), __param(3, (0, common_1.Res)()), __metadata("design:type", Function), __metadata("design:paramtypes", [String, outlook_webhook_notification_dto_1.OutlookWebhookNotificationDto, Object, Object]), __metadata("design:returntype", Promise) ], CalendarController.prototype, "handleCalendarWebhook", null); exports.CalendarController = CalendarController = CalendarController_1 = __decorate([ (0, swagger_1.ApiTags)('Calendar'), (0, common_1.Controller)('calendar'), (0, common_1.Injectable)(), __metadata("design:paramtypes", [calendar_service_1.CalendarService]) ], CalendarController); //# sourceMappingURL=calendar.controller.js.map