File size: 4,584 Bytes
84818f7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import {
  Controller,
  Get,
  Post,
  Delete,
  Body,
  Param,
  Req,
  UseGuards,
  ParseIntPipe,
  HttpCode,
  HttpStatus,
} from '@nestjs/common';
import {
  ApiTags,
  ApiOperation,
  ApiParam,
  ApiBody,
  ApiResponse,
  ApiBearerAuth,
} from '@nestjs/swagger';
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../../auth/guards/roles.guard';
import { CalendarIntegrationsService } from '../services';
import { ConnectCalendarDto } from '../dto';

@ApiTags('πŸ”— Calendar Integrations')
@ApiBearerAuth('JWT-auth')
@Controller('api/calendar/integrations')
@UseGuards(JwtAuthGuard, RolesGuard)
export class CalendarIntegrationsController {
  constructor(private readonly integrationsService: CalendarIntegrationsService) {}

  @Get()
  @ApiOperation({
    summary: 'List calendar integrations',
    description: `
## List User's Calendar Integrations

Returns all external calendar integrations for the current user.

### Access Control
- **Authentication Required**: βœ… Yes (Bearer Token)
- **Roles**: ALL

### Supported Calendar Types
- \`google\`: Google Calendar
- \`outlook\`: Microsoft Outlook Calendar
- \`ical\`: iCal/Apple Calendar

### Response Includes
- Integration ID
- Calendar type
- Sync status (active, error, disabled)
- Last sync timestamp
    `,
  })
  @ApiResponse({ status: 200, description: 'List of calendar integrations' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  async findAll(@Req() req: any) {
    const userId = req.user.userId || req.user.id;
    return this.integrationsService.findAll(userId);
  }

  @Post('connect')
  @HttpCode(HttpStatus.CREATED)
  @ApiOperation({
    summary: 'Connect external calendar',
    description: `
## Connect External Calendar

Links an external calendar service to the user's EduVerse account.

### Access Control
- **Authentication Required**: βœ… Yes (Bearer Token)
- **Roles**: ALL

### OAuth Flow
1. Frontend initiates OAuth flow with calendar provider
2. User authorizes EduVerse access
3. Frontend receives authorization code
4. Frontend calls this endpoint with the code

### Supported Calendars
- **Google Calendar**: Full sync support
- **Outlook Calendar**: Full sync support
- **iCal**: Import/export support
    `,
  })
  @ApiBody({ type: ConnectCalendarDto })
  @ApiResponse({ status: 201, description: 'Calendar connected successfully' })
  @ApiResponse({ status: 400, description: 'Invalid authorization code' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  async connect(@Body() dto: ConnectCalendarDto, @Req() req: any) {
    const userId = req.user.userId || req.user.id;
    return this.integrationsService.connect(dto, userId);
  }

  @Post(':id/sync')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({
    summary: 'Sync calendar',
    description: `
## Trigger Manual Calendar Sync

Manually triggers synchronization with the external calendar.

### Access Control
- **Authentication Required**: βœ… Yes (Bearer Token)
- **Roles**: ALL (own integrations only)

### Sync Process
- Imports events from external calendar
- Exports EduVerse events to external calendar
- Updates sync timestamp
    `,
  })
  @ApiParam({ name: 'id', description: 'Integration ID', type: Number, example: 1 })
  @ApiResponse({ status: 200, description: 'Sync initiated successfully' })
  @ApiResponse({ status: 404, description: 'Integration not found' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  async sync(@Param('id', ParseIntPipe) id: number, @Req() req: any) {
    const userId = req.user.userId || req.user.id;
    return this.integrationsService.sync(id, userId);
  }

  @Delete(':id')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({
    summary: 'Disconnect calendar',
    description: `
## Disconnect External Calendar

Removes the integration with an external calendar service.

### Access Control
- **Authentication Required**: βœ… Yes (Bearer Token)
- **Roles**: ALL (own integrations only)

### What Happens
- Removes stored tokens
- Stops future syncs
- Does NOT delete events already in EduVerse
    `,
  })
  @ApiParam({ name: 'id', description: 'Integration ID', type: Number, example: 1 })
  @ApiResponse({ status: 200, description: 'Calendar disconnected successfully' })
  @ApiResponse({ status: 404, description: 'Integration not found' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  async disconnect(@Param('id', ParseIntPipe) id: number, @Req() req: any) {
    const userId = req.user.userId || req.user.id;
    return this.integrationsService.disconnect(id, userId);
  }
}