import { Args, ID, Mutation, Query, Resolver } from '@nestjs/graphql'; import { User } from '@task-stream/api/identity/domain'; import { CurrentUser } from '@task-stream/api/identity/presenters'; import { AlertIntegration, AlertsService, } from '@task-stream/api/tracker/application'; import { alertWebhookPath } from '../common/alert-webhook'; import { AlertSettingsInput } from './inputs'; import { AlertIntegrationGql } from './types'; /** Alerts → bugs: the project's secret URL (owners and admins configure it). */ @Resolver(() => AlertIntegrationGql) export class AlertResolver { constructor(private readonly alerts: AlertsService) {} @Query(() => AlertIntegrationGql) async alertIntegration( @CurrentUser() me: User, @Args('projectId', { type: () => ID }) projectId: string, ) { return withPath(projectId, await this.alerts.get(me.id, projectId)); } @Mutation(() => AlertIntegrationGql, { description: 'Turn alerts → bugs on, or change the type and priority it opens (the URL stays)', }) async saveAlertIntegration( @CurrentUser() me: User, @Args('projectId', { type: () => ID }) projectId: string, @Args('input') input: AlertSettingsInput, ) { return withPath( projectId, await this.alerts.save(me.id, projectId, { typeId: input.typeId, priority: input.priority, }), ); } @Mutation(() => AlertIntegrationGql, { description: 'A new secret URL; the old one stops working at once', }) async rotateAlertToken( @CurrentUser() me: User, @Args('projectId', { type: () => ID }) projectId: string, ) { return withPath(projectId, await this.alerts.rotateToken(me.id, projectId)); } @Mutation(() => Boolean, { description: 'Turn it off; the bugs it opened stay', }) async disableAlertIntegration( @CurrentUser() me: User, @Args('projectId', { type: () => ID }) projectId: string, ) { await this.alerts.disable(me.id, projectId); return true; } } function withPath(projectId: string, integration: AlertIntegration) { const { token, ...rest } = integration; return { ...rest, webhookPath: token ? alertWebhookPath(projectId, token) : null, }; }