import { Body, Controller, Delete, ForbiddenException, Get, HttpCode, Param, Patch, Post, UseGuards, } from '@nestjs/common' import { Types } from 'mongoose' import { ActorService } from '../../auth/actor.service.js' import { CurrentUser } from '../../auth/current-user.decorator.js' import { JwtAuthGuard } from '../../auth/jwt-auth.guard.js' import type { AuthentikJwtPayload } from '../../auth/jwt-payload.interface.js' import { TenantsService } from '../../tenants/tenants.service.js' import { CreateWebhookDto, UpdateWebhookDto } from './dto/webhook-dtos.js' import { WebhooksService } from './webhooks.service.js' // Tenant webhook administration. Same base path + gating as the rest of the // scheduling admin surface (platformAdmin OR a member of the tenant). The // signing secret is returned in full on create/get/rotate so the tenant can // configure their receiver's HMAC verification. @Controller('api/v1/tenants/:slug/scheduling/webhooks') @UseGuards(JwtAuthGuard) export class WebhooksController { constructor( private readonly actor: ActorService, private readonly tenants: TenantsService, private readonly webhooks: WebhooksService, ) {} private async gate(slug: string, jwt: AuthentikJwtPayload): Promise { const actor = await this.actor.resolve(jwt) const tenant = await this.tenants.findOneBySlug(slug) if (!actor.platformAdmin && !actor.tenantIds.some((id) => id.equals(tenant._id))) { throw new ForbiddenException(`No access to tenant "${slug}"`) } return tenant._id } @Get() async list(@Param('slug') slug: string, @CurrentUser() jwt: AuthentikJwtPayload) { return this.webhooks.list(await this.gate(slug, jwt)) } @Post() async create(@Param('slug') slug: string, @Body() dto: CreateWebhookDto, @CurrentUser() jwt: AuthentikJwtPayload) { return this.webhooks.create(await this.gate(slug, jwt), dto) } @Patch(':id') async update( @Param('slug') slug: string, @Param('id') id: string, @Body() dto: UpdateWebhookDto, @CurrentUser() jwt: AuthentikJwtPayload, ) { return this.webhooks.update(await this.gate(slug, jwt), id, dto) } @Post(':id/rotate-secret') async rotateSecret(@Param('slug') slug: string, @Param('id') id: string, @CurrentUser() jwt: AuthentikJwtPayload) { return this.webhooks.rotateSecret(await this.gate(slug, jwt), id) } @Get(':id/deliveries') async deliveries(@Param('slug') slug: string, @Param('id') id: string, @CurrentUser() jwt: AuthentikJwtPayload) { return this.webhooks.listDeliveries(await this.gate(slug, jwt), id) } @Delete(':id') @HttpCode(204) async remove(@Param('slug') slug: string, @Param('id') id: string, @CurrentUser() jwt: AuthentikJwtPayload) { await this.webhooks.remove(await this.gate(slug, jwt), id) } }