@checkfirst/nestjs-outlook 0.1.0
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/LICENSE +21 -0
- package/README.md +224 -0
- package/assets/checkfirst-logo.png +0 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +5 -0
- package/dist/constants.js.map +1 -0
- package/dist/controllers/microsoft-auth.controller.d.ts +7 -0
- package/dist/controllers/microsoft-auth.controller.js +101 -0
- package/dist/controllers/microsoft-auth.controller.js.map +1 -0
- package/dist/controllers/outlook.controller.d.ts +8 -0
- package/dist/controllers/outlook.controller.js +117 -0
- package/dist/controllers/outlook.controller.js.map +1 -0
- package/dist/dto/outlook-webhook-notification.dto.d.ts +19 -0
- package/dist/dto/outlook-webhook-notification.dto.js +149 -0
- package/dist/dto/outlook-webhook-notification.dto.js.map +1 -0
- package/dist/entities/csrf-token.entity.d.ts +7 -0
- package/dist/entities/csrf-token.entity.js +48 -0
- package/dist/entities/csrf-token.entity.js.map +1 -0
- package/dist/entities/outlook-webhook-subscription.entity.d.ts +15 -0
- package/dist/entities/outlook-webhook-subscription.entity.js +87 -0
- package/dist/entities/outlook-webhook-subscription.entity.js.map +1 -0
- package/dist/event-types.enum.d.ts +7 -0
- package/dist/event-types.enum.js +12 -0
- package/dist/event-types.enum.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/config/outlook-config.interface.d.ts +7 -0
- package/dist/interfaces/config/outlook-config.interface.js +3 -0
- package/dist/interfaces/config/outlook-config.interface.js.map +1 -0
- package/dist/interfaces/microsoft-auth/microsoft-token-api-response.interface.d.ts +9 -0
- package/dist/interfaces/microsoft-auth/microsoft-token-api-response.interface.js +3 -0
- package/dist/interfaces/microsoft-auth/microsoft-token-api-response.interface.js.map +1 -0
- package/dist/interfaces/microsoft-auth/state-object.interface.d.ts +5 -0
- package/dist/interfaces/microsoft-auth/state-object.interface.js +3 -0
- package/dist/interfaces/microsoft-auth/state-object.interface.js.map +1 -0
- package/dist/interfaces/outlook/token-response.interface.d.ts +5 -0
- package/dist/interfaces/outlook/token-response.interface.js +3 -0
- package/dist/interfaces/outlook/token-response.interface.js.map +1 -0
- package/dist/microsoft-outlook.module.d.ts +4 -0
- package/dist/microsoft-outlook.module.js +50 -0
- package/dist/microsoft-outlook.module.js.map +1 -0
- package/dist/migrations/1697025846000-CreateOutlookTables.d.ts +5 -0
- package/dist/migrations/1697025846000-CreateOutlookTables.js +40 -0
- package/dist/migrations/1697025846000-CreateOutlookTables.js.map +1 -0
- package/dist/repositories/microsoft-csrf-token.repository.d.ts +9 -0
- package/dist/repositories/microsoft-csrf-token.repository.js +60 -0
- package/dist/repositories/microsoft-csrf-token.repository.js.map +1 -0
- package/dist/repositories/outlook-webhook-subscription.repository.d.ts +12 -0
- package/dist/repositories/outlook-webhook-subscription.repository.js +70 -0
- package/dist/repositories/outlook-webhook-subscription.repository.js.map +1 -0
- package/dist/services/microsoft-auth.service.d.ts +32 -0
- package/dist/services/microsoft-auth.service.js +254 -0
- package/dist/services/microsoft-auth.service.js.map +1 -0
- package/dist/services/outlook.service.d.ts +28 -0
- package/dist/services/outlook.service.js +265 -0
- package/dist/services/outlook.service.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +103 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 CheckFirst Ltd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# NestJS Outlook
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://checkfirst.ai" target="_blank">
|
|
5
|
+
<img src="https://raw.githubusercontent.com/checkfirst-ltd/nestjs-outlook/main/assets/checkfirst-logo.png" width="400" alt="CheckFirst Logo" />
|
|
6
|
+
</a>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/@checkfirst/nestjs-outlook"><img src="https://img.shields.io/npm/v/@checkfirst/nestjs-outlook.svg" alt="NPM Version" /></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/@checkfirst/nestjs-outlook"><img src="https://img.shields.io/npm/dm/@checkfirst/nestjs-outlook.svg" alt="NPM Downloads" /></a>
|
|
12
|
+
<a href="https://github.com/checkfirst-ltd/nestjs-outlook/blob/main/LICENSE"><img src="https://img.shields.io/github/license/checkfirst-ltd/nestjs-outlook" alt="License" /></a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
An opinionated NestJS module for Microsoft Outlook integration that provides easy access to Microsoft Graph API for emails, calendars, and more.
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- 🔄 Simplified Microsoft OAuth flow
|
|
20
|
+
- 📅 Calendar events management
|
|
21
|
+
- 🔔 Real-time webhooks for changes
|
|
22
|
+
- 🔐 Secure token storage and refresh
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @checkfirst/nestjs-outlook
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Setup
|
|
31
|
+
|
|
32
|
+
### 1. Database Setup
|
|
33
|
+
|
|
34
|
+
This library requires two database tables in your application's database. Create these tables using a migration:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { MigrationInterface, QueryRunner } from 'typeorm';
|
|
38
|
+
|
|
39
|
+
export class CreateOutlookTables1697025846000 implements MigrationInterface {
|
|
40
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
41
|
+
// Create outlook_webhook_subscriptions table
|
|
42
|
+
await queryRunner.query(`
|
|
43
|
+
CREATE TABLE outlook_webhook_subscriptions (
|
|
44
|
+
id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
|
45
|
+
subscription_id VARCHAR(255) NOT NULL,
|
|
46
|
+
user_id INTEGER NOT NULL,
|
|
47
|
+
resource VARCHAR(255) NOT NULL,
|
|
48
|
+
change_type VARCHAR(255) NOT NULL,
|
|
49
|
+
client_state VARCHAR(255) NOT NULL,
|
|
50
|
+
notification_url VARCHAR(255) NOT NULL,
|
|
51
|
+
expiration_date_time TIMESTAMP NOT NULL,
|
|
52
|
+
is_active BOOLEAN DEFAULT true,
|
|
53
|
+
access_token TEXT,
|
|
54
|
+
refresh_token TEXT,
|
|
55
|
+
created_at TIMESTAMP DEFAULT NOW() NOT NULL,
|
|
56
|
+
updated_at TIMESTAMP DEFAULT NOW() NOT NULL
|
|
57
|
+
);
|
|
58
|
+
`);
|
|
59
|
+
|
|
60
|
+
// Create microsoft_csrf_tokens table
|
|
61
|
+
await queryRunner.query(`
|
|
62
|
+
CREATE TABLE microsoft_csrf_tokens (
|
|
63
|
+
id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
|
64
|
+
token VARCHAR(64) NOT NULL,
|
|
65
|
+
user_id VARCHAR(255) NOT NULL,
|
|
66
|
+
expires TIMESTAMP NOT NULL,
|
|
67
|
+
created_at TIMESTAMP DEFAULT NOW() NOT NULL,
|
|
68
|
+
CONSTRAINT "UQ_microsoft_csrf_tokens_token" UNIQUE (token)
|
|
69
|
+
);
|
|
70
|
+
`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
74
|
+
await queryRunner.query(`DROP TABLE IF EXISTS outlook_webhook_subscriptions`);
|
|
75
|
+
await queryRunner.query(`DROP TABLE IF EXISTS microsoft_csrf_tokens`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
You can customize this migration to match your database dialect (PostgreSQL, MySQL, etc.) if needed.
|
|
81
|
+
|
|
82
|
+
### 2. Import Required Modules
|
|
83
|
+
|
|
84
|
+
Register the module in your NestJS application and include the module entities in TypeORM:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { Module } from '@nestjs/common';
|
|
88
|
+
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
89
|
+
import { EventEmitterModule } from '@nestjs/event-emitter';
|
|
90
|
+
import { ScheduleModule } from '@nestjs/schedule';
|
|
91
|
+
import { MicrosoftOutlookModule } from '@checkfirst/nestjs-outlook';
|
|
92
|
+
import * as path from 'path';
|
|
93
|
+
|
|
94
|
+
// Resolve the path to the outlook package
|
|
95
|
+
const outlookPackagePath = path.dirname(require.resolve('@checkfirst/nestjs-outlook/package.json'));
|
|
96
|
+
|
|
97
|
+
@Module({
|
|
98
|
+
imports: [
|
|
99
|
+
// Required modules
|
|
100
|
+
TypeOrmModule.forRoot({
|
|
101
|
+
// Your TypeORM configuration
|
|
102
|
+
entities: [
|
|
103
|
+
// Your app entities
|
|
104
|
+
__dirname + '/**/*.entity{.ts,.js}',
|
|
105
|
+
// Include outlook module entities
|
|
106
|
+
path.join(outlookPackagePath, 'dist', 'entities', '*.entity.js')
|
|
107
|
+
],
|
|
108
|
+
}),
|
|
109
|
+
ScheduleModule.forRoot(),
|
|
110
|
+
EventEmitterModule.forRoot(),
|
|
111
|
+
|
|
112
|
+
// Microsoft Outlook Module
|
|
113
|
+
MicrosoftOutlookModule.forRoot({
|
|
114
|
+
clientId: 'YOUR_MICROSOFT_APP_CLIENT_ID',
|
|
115
|
+
clientSecret: 'YOUR_MICROSOFT_APP_CLIENT_SECRET',
|
|
116
|
+
redirectPath: 'auth/microsoft/callback',
|
|
117
|
+
backendBaseUrl: 'https://your-api.example.com',
|
|
118
|
+
basePath: 'api/v1',
|
|
119
|
+
}),
|
|
120
|
+
],
|
|
121
|
+
})
|
|
122
|
+
export class AppModule {}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 3. Create a Login Controller
|
|
126
|
+
|
|
127
|
+
Create a controller to handle Microsoft authentication:
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
export class CalendarController {
|
|
131
|
+
constructor(
|
|
132
|
+
private readonly microsoftAuthService: MicrosoftAuthService
|
|
133
|
+
) {}
|
|
134
|
+
|
|
135
|
+
@UseGuards(AuthGuard)
|
|
136
|
+
@Get('auth/microsoft/login')
|
|
137
|
+
async login(@Req() req: Request) {
|
|
138
|
+
const user = req.user as UserTokenPayload;
|
|
139
|
+
if (!user?.id) {
|
|
140
|
+
throw new ForbiddenException('User not authenticated');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Get the login URL from the Microsoft auth service
|
|
144
|
+
return await this.microsoftAuthService.getLoginUrl(user.id.toString());
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Available Services
|
|
150
|
+
|
|
151
|
+
- `OutlookService` - Main service for Microsoft Graph API operations on Outlook
|
|
152
|
+
- `MicrosoftAuthService` - For authentication and token management
|
|
153
|
+
|
|
154
|
+
## Events
|
|
155
|
+
|
|
156
|
+
The library uses NestJS's EventEmitter to emit events for various Outlook activities. You can listen to these events in your application to react to changes.
|
|
157
|
+
|
|
158
|
+
### Available Events
|
|
159
|
+
|
|
160
|
+
The library exposes event types through the `OutlookEventTypes` enum:
|
|
161
|
+
|
|
162
|
+
- `OutlookEventTypes.AUTH_TOKENS_SAVE` - Emitted when OAuth tokens are initially saved
|
|
163
|
+
- `OutlookEventTypes.AUTH_TOKENS_UPDATE` - Emitted when OAuth tokens are refreshed
|
|
164
|
+
- `OutlookEventTypes.EVENT_CREATED` - Emitted when a new Outlook calendar event is created via webhook
|
|
165
|
+
- `OutlookEventTypes.EVENT_UPDATED` - Emitted when an Outlook calendar event is updated via webhook
|
|
166
|
+
- `OutlookEventTypes.EVENT_DELETED` - Emitted when an Outlook calendar event is deleted via webhook
|
|
167
|
+
|
|
168
|
+
### Listening to Events
|
|
169
|
+
|
|
170
|
+
You can listen to these events in your application using the `@OnEvent` decorator from `@nestjs/event-emitter` and the `OutlookEventTypes` enum:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import { Injectable } from '@nestjs/common';
|
|
174
|
+
import { OnEvent } from '@nestjs/event-emitter';
|
|
175
|
+
import { OutlookEventTypes, OutlookResourceData } from '@checkfirst/nestjs-outlook';
|
|
176
|
+
|
|
177
|
+
@Injectable()
|
|
178
|
+
export class YourService {
|
|
179
|
+
@OnEvent(OutlookEventTypes.EVENT_CREATED)
|
|
180
|
+
handleOutlookEventCreated(data: OutlookResourceData) {
|
|
181
|
+
console.log('New Outlook event created:', data.id);
|
|
182
|
+
// Handle the new event...
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@OnEvent(OutlookEventTypes.EVENT_UPDATED)
|
|
186
|
+
handleOutlookEventUpdated(data: OutlookResourceData) {
|
|
187
|
+
console.log('Outlook event updated:', data.id);
|
|
188
|
+
// Handle the updated event...
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
@OnEvent(OutlookEventTypes.EVENT_DELETED)
|
|
192
|
+
handleOutlookEventDeleted(data: OutlookResourceData) {
|
|
193
|
+
console.log('Outlook event deleted:', data.id);
|
|
194
|
+
// Handle the deleted event...
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
These events are emitted when Microsoft Graph sends webhook notifications to your application for calendar events changes.
|
|
200
|
+
|
|
201
|
+
## Support
|
|
202
|
+
|
|
203
|
+
- [GitHub Issues](https://github.com/checkfirst-ltd/nestjs-outlook/issues)
|
|
204
|
+
- [Documentation](https://github.com/checkfirst-ltd/nestjs-outlook#readme)
|
|
205
|
+
|
|
206
|
+
## Contributing
|
|
207
|
+
|
|
208
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for more details.
|
|
209
|
+
|
|
210
|
+
## Code of Conduct
|
|
211
|
+
|
|
212
|
+
This project adheres to a Code of Conduct that all participants are expected to follow. Please read the [Code of Conduct](https://github.com/checkfirst-ltd/nestjs-outlook/blob/main/CONTRIBUTING.md#code-of-conduct) for details on our expectations.
|
|
213
|
+
|
|
214
|
+
## About CheckFirst
|
|
215
|
+
|
|
216
|
+
<a href="https://checkfirst.ai" target="_blank">
|
|
217
|
+
<img src="https://raw.githubusercontent.com/checkfirst-ltd/nestjs-outlook/main/assets/checkfirst-banner.png" alt="CheckFirst Banner" width="100%" />
|
|
218
|
+
</a>
|
|
219
|
+
|
|
220
|
+
[CheckFirst](https://checkfirst.ai) is a trusted provider of developer tools and solutions. We build open-source libraries that help developers create better applications faster.
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
[MIT](LICENSE) © [CheckFirst Ltd](https://checkfirst.ai)
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const MICROSOFT_CONFIG = "MICROSOFT_CONFIG";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AACa,QAAA,gBAAgB,GAAG,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Response } from 'express';
|
|
2
|
+
import { MicrosoftAuthService } from '../services/microsoft-auth.service';
|
|
3
|
+
export declare class MicrosoftAuthController {
|
|
4
|
+
private readonly microsoftAuthService;
|
|
5
|
+
constructor(microsoftAuthService: MicrosoftAuthService);
|
|
6
|
+
callback(code: string, state: string, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.MicrosoftAuthController = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
18
|
+
const microsoft_auth_service_1 = require("../services/microsoft-auth.service");
|
|
19
|
+
let MicrosoftAuthController = class MicrosoftAuthController {
|
|
20
|
+
constructor(microsoftAuthService) {
|
|
21
|
+
this.microsoftAuthService = microsoftAuthService;
|
|
22
|
+
}
|
|
23
|
+
async callback(code, state, res) {
|
|
24
|
+
if (!code) {
|
|
25
|
+
throw new common_1.BadRequestException('No code provided');
|
|
26
|
+
}
|
|
27
|
+
if (!state) {
|
|
28
|
+
throw new common_1.BadRequestException('No state parameter provided');
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
await this.microsoftAuthService.exchangeCodeForToken(code, state);
|
|
32
|
+
return res.status(common_1.HttpStatus.OK).send(`
|
|
33
|
+
<h1>Authorization successful!</h1>
|
|
34
|
+
<p>Your Microsoft account has been linked successfully.</p>
|
|
35
|
+
<p>You can close this tab now.</p>
|
|
36
|
+
<script>
|
|
37
|
+
// Optionally notify the parent window
|
|
38
|
+
if (window.opener) {
|
|
39
|
+
window.opener.postMessage('microsoft-auth-success', '*');
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
42
|
+
`);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error('Authentication failed:', error);
|
|
46
|
+
throw new common_1.InternalServerErrorException('Authentication failed. Please try again.');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
exports.MicrosoftAuthController = MicrosoftAuthController;
|
|
51
|
+
__decorate([
|
|
52
|
+
(0, common_1.Get)('callback'),
|
|
53
|
+
(0, swagger_1.ApiOperation)({
|
|
54
|
+
summary: 'Microsoft OAuth callback handler',
|
|
55
|
+
description: 'Processes the callback from Microsoft OAuth authentication flow. Exchanges the authorization code for access and refresh tokens, saves them for the user, and sets up necessary webhooks for calendar synchronization. The user ID is extracted from the state parameter.',
|
|
56
|
+
}),
|
|
57
|
+
(0, swagger_1.ApiQuery)({
|
|
58
|
+
name: 'code',
|
|
59
|
+
description: 'Authorization code from Microsoft',
|
|
60
|
+
required: true,
|
|
61
|
+
type: String,
|
|
62
|
+
example: 'M.R3_BAY.c0def4c2-12bf-0b29-9a3a-f8a1c4f56789',
|
|
63
|
+
}),
|
|
64
|
+
(0, swagger_1.ApiQuery)({
|
|
65
|
+
name: 'state',
|
|
66
|
+
description: 'Base64 encoded state containing user ID and CSRF token',
|
|
67
|
+
required: true,
|
|
68
|
+
type: String,
|
|
69
|
+
example: 'eyJ1c2VySWQiOiI3IiwiY3NyZiI6IjEyMzQ1In0',
|
|
70
|
+
}),
|
|
71
|
+
(0, swagger_1.ApiResponse)({
|
|
72
|
+
status: 200,
|
|
73
|
+
description: 'Authentication successful, tokens saved and webhooks created',
|
|
74
|
+
content: {
|
|
75
|
+
'text/html': {
|
|
76
|
+
example: '<h1>Authorization successful!</h1><p>Your Microsoft account has been linked successfully.</p>',
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
}),
|
|
80
|
+
(0, swagger_1.ApiResponse)({
|
|
81
|
+
status: 400,
|
|
82
|
+
description: 'Invalid or missing code/state parameters',
|
|
83
|
+
}),
|
|
84
|
+
(0, swagger_1.ApiResponse)({
|
|
85
|
+
status: 500,
|
|
86
|
+
description: 'Server error during authentication process',
|
|
87
|
+
}),
|
|
88
|
+
(0, swagger_1.ApiProduces)('text/html'),
|
|
89
|
+
__param(0, (0, common_1.Query)('code')),
|
|
90
|
+
__param(1, (0, common_1.Query)('state')),
|
|
91
|
+
__param(2, (0, common_1.Res)()),
|
|
92
|
+
__metadata("design:type", Function),
|
|
93
|
+
__metadata("design:paramtypes", [String, String, Object]),
|
|
94
|
+
__metadata("design:returntype", Promise)
|
|
95
|
+
], MicrosoftAuthController.prototype, "callback", null);
|
|
96
|
+
exports.MicrosoftAuthController = MicrosoftAuthController = __decorate([
|
|
97
|
+
(0, swagger_1.ApiTags)('Microsoft Auth'),
|
|
98
|
+
(0, common_1.Controller)('auth/microsoft'),
|
|
99
|
+
__metadata("design:paramtypes", [microsoft_auth_service_1.MicrosoftAuthService])
|
|
100
|
+
], MicrosoftAuthController);
|
|
101
|
+
//# sourceMappingURL=microsoft-auth.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"microsoft-auth.controller.js","sourceRoot":"","sources":["../../src/controllers/microsoft-auth.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAQwB;AAExB,6CAA4F;AAC5F,+EAA0E;AAInE,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;IAClC,YAA6B,oBAA0C;QAA1C,yBAAoB,GAApB,oBAAoB,CAAsB;IAAG,CAAC;IA4DrE,AAAN,KAAK,CAAC,QAAQ,CAAgB,IAAY,EAAkB,KAAa,EAAS,GAAa;QAC7F,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,4BAAmB,CAAC,kBAAkB,CAAC,CAAC;QACpD,CAAC;QAED,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,4BAAmB,CAAC,6BAA6B,CAAC,CAAC;QAC/D,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAGlE,OAAO,GAAG,CAAC,MAAM,CAAC,mBAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;;;;;;;;;;OAUrC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;YAC/C,MAAM,IAAI,qCAA4B,CAAC,0CAA0C,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;CACF,CAAA;AA1FY,0DAAuB;AA6D5B;IAvCL,IAAA,YAAG,EAAC,UAAU,CAAC;IACf,IAAA,sBAAY,EAAC;QACZ,OAAO,EAAE,kCAAkC;QAC3C,WAAW,EACT,2QAA2Q;KAC9Q,CAAC;IACD,IAAA,kBAAQ,EAAC;QACR,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,mCAAmC;QAChD,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,+CAA+C;KACzD,CAAC;IACD,IAAA,kBAAQ,EAAC;QACR,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,wDAAwD;QACrE,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,yCAAyC;KACnD,CAAC;IACD,IAAA,qBAAW,EAAC;QACX,MAAM,EAAE,GAAG;QACX,WAAW,EAAE,8DAA8D;QAC3E,OAAO,EAAE;YACP,WAAW,EAAE;gBACX,OAAO,EACL,+FAA+F;aAClG;SACF;KACF,CAAC;IACD,IAAA,qBAAW,EAAC;QACX,MAAM,EAAE,GAAG;QACX,WAAW,EAAE,0CAA0C;KACxD,CAAC;IACD,IAAA,qBAAW,EAAC;QACX,MAAM,EAAE,GAAG;QACX,WAAW,EAAE,4CAA4C;KAC1D,CAAC;IACD,IAAA,qBAAW,EAAC,WAAW,CAAC;IACT,WAAA,IAAA,cAAK,EAAC,MAAM,CAAC,CAAA;IAAgB,WAAA,IAAA,cAAK,EAAC,OAAO,CAAC,CAAA;IAAiB,WAAA,IAAA,YAAG,GAAE,CAAA;;;;uDA4BhF;kCAzFU,uBAAuB;IAFnC,IAAA,iBAAO,EAAC,gBAAgB,CAAC;IACzB,IAAA,mBAAU,EAAC,gBAAgB,CAAC;qCAEwB,6CAAoB;GAD5D,uBAAuB,CA0FnC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Response, Request } from 'express';
|
|
2
|
+
import { OutlookService } from '../services/outlook.service';
|
|
3
|
+
import { OutlookWebhookNotificationDto } from '../dto/outlook-webhook-notification.dto';
|
|
4
|
+
export declare class OutlookController {
|
|
5
|
+
private readonly outlookService;
|
|
6
|
+
constructor(outlookService: OutlookService);
|
|
7
|
+
handleOutlookWebhook(validationToken: string, notificationBody: OutlookWebhookNotificationDto, req: Request, res: Response): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.OutlookController = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
18
|
+
const outlook_service_1 = require("../services/outlook.service");
|
|
19
|
+
const outlook_webhook_notification_dto_1 = require("../dto/outlook-webhook-notification.dto");
|
|
20
|
+
let OutlookController = class OutlookController {
|
|
21
|
+
constructor(outlookService) {
|
|
22
|
+
this.outlookService = outlookService;
|
|
23
|
+
}
|
|
24
|
+
async handleOutlookWebhook(validationToken, notificationBody, req, res) {
|
|
25
|
+
if (validationToken) {
|
|
26
|
+
console.log('Handling Microsoft Graph validation request with token:', validationToken);
|
|
27
|
+
const decodedToken = decodeURIComponent(validationToken);
|
|
28
|
+
res.set('Content-Type', 'text/plain; charset=utf-8');
|
|
29
|
+
res.send(decodedToken);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
console.log('Received webhook notification:', JSON.stringify(notificationBody));
|
|
34
|
+
if (Array.isArray(notificationBody.value)) {
|
|
35
|
+
const processedEvents = new Set();
|
|
36
|
+
let hasSuccessfullyProcessed = false;
|
|
37
|
+
for (const item of notificationBody.value) {
|
|
38
|
+
const resourceData = item.resourceData;
|
|
39
|
+
if (resourceData.id && processedEvents.has(resourceData.id)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (resourceData.id) {
|
|
43
|
+
processedEvents.add(resourceData.id);
|
|
44
|
+
}
|
|
45
|
+
if (resourceData.id && ['deleted', 'created', 'updated'].includes(item.changeType)) {
|
|
46
|
+
try {
|
|
47
|
+
const changeNotification = {
|
|
48
|
+
subscriptionId: item.subscriptionId,
|
|
49
|
+
subscriptionExpirationDateTime: item.subscriptionExpirationDateTime,
|
|
50
|
+
changeType: item.changeType,
|
|
51
|
+
resource: item.resource,
|
|
52
|
+
resourceData: resourceData,
|
|
53
|
+
clientState: item.clientState,
|
|
54
|
+
tenantId: item.tenantId,
|
|
55
|
+
};
|
|
56
|
+
const result = await this.outlookService.handleOutlookWebhook(changeNotification);
|
|
57
|
+
console.log(`Processed ${item.changeType} event for ${resourceData.id}: ${JSON.stringify(result)}`);
|
|
58
|
+
hasSuccessfullyProcessed = true;
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
console.error(`Error processing ${item.changeType} event ${resourceData.id}:`, error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
console.log(`Skipping notification of type: ${item.changeType}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
res.json({
|
|
69
|
+
success: true,
|
|
70
|
+
message: hasSuccessfullyProcessed
|
|
71
|
+
? `Successfully processed events`
|
|
72
|
+
: `Received notifications, but no events were processed`,
|
|
73
|
+
});
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
res.json({
|
|
77
|
+
success: true,
|
|
78
|
+
message: `Received webhook notification in unexpected format`,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
console.error('Error processing webhook notification:', error);
|
|
83
|
+
res.status(500).json({
|
|
84
|
+
success: false,
|
|
85
|
+
message: 'Error processing webhook notification',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
exports.OutlookController = OutlookController;
|
|
91
|
+
__decorate([
|
|
92
|
+
(0, common_1.Post)('webhook'),
|
|
93
|
+
(0, common_1.HttpCode)(200),
|
|
94
|
+
(0, swagger_1.ApiResponse)({
|
|
95
|
+
status: 200,
|
|
96
|
+
description: 'Webhook notification processed successfully',
|
|
97
|
+
}),
|
|
98
|
+
(0, swagger_1.ApiBody)({
|
|
99
|
+
description: 'Microsoft Graph webhook notification payload',
|
|
100
|
+
type: outlook_webhook_notification_dto_1.OutlookWebhookNotificationDto,
|
|
101
|
+
required: false,
|
|
102
|
+
}),
|
|
103
|
+
__param(0, (0, common_1.Query)('validationToken')),
|
|
104
|
+
__param(1, (0, common_1.Body)()),
|
|
105
|
+
__param(2, (0, common_1.Req)()),
|
|
106
|
+
__param(3, (0, common_1.Res)()),
|
|
107
|
+
__metadata("design:type", Function),
|
|
108
|
+
__metadata("design:paramtypes", [String, outlook_webhook_notification_dto_1.OutlookWebhookNotificationDto, Object, Object]),
|
|
109
|
+
__metadata("design:returntype", Promise)
|
|
110
|
+
], OutlookController.prototype, "handleOutlookWebhook", null);
|
|
111
|
+
exports.OutlookController = OutlookController = __decorate([
|
|
112
|
+
(0, swagger_1.ApiTags)('Outlook'),
|
|
113
|
+
(0, common_1.Controller)('outlook'),
|
|
114
|
+
(0, common_1.Injectable)(),
|
|
115
|
+
__metadata("design:paramtypes", [outlook_service_1.OutlookService])
|
|
116
|
+
], OutlookController);
|
|
117
|
+
//# sourceMappingURL=outlook.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outlook.controller.js","sourceRoot":"","sources":["../../src/controllers/outlook.controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare class OutlookResourceData {
|
|
2
|
+
'@odata.type'?: string;
|
|
3
|
+
'@odata.id'?: string;
|
|
4
|
+
'@odata.etag'?: string;
|
|
5
|
+
id: string;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
}
|
|
8
|
+
export declare class OutlookWebhookNotificationItemDto {
|
|
9
|
+
subscriptionId: string;
|
|
10
|
+
subscriptionExpirationDateTime: string;
|
|
11
|
+
changeType: string;
|
|
12
|
+
resource: string;
|
|
13
|
+
resourceData: OutlookResourceData;
|
|
14
|
+
clientState?: string;
|
|
15
|
+
tenantId?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare class OutlookWebhookNotificationDto {
|
|
18
|
+
value: OutlookWebhookNotificationItemDto[];
|
|
19
|
+
}
|