@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.
165 lines • 8.24 kB
JavaScript
;
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");
const webhook_notification_validator_1 = require("../utils/webhook-notification.validator");
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) {
const validation = (0, webhook_notification_validator_1.validateNotificationItem)(item, webhook_notification_validator_1.WebhookResourceType.CALENDAR, this.logger);
if (!validation.isValid || validation.shouldSkip) {
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);
}
if (!(0, webhook_notification_validator_1.validateChangeType)(item.changeType, this.logger, '[CALENDAR_WEBHOOK]')) {
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