feat: outgoing webhooks
Owners and admins can point a project at other systems: a signed JSON POST (HMAC-SHA256 of the body) when tickets, comments, releases or sprints change, filtered by event or family. Deliveries are retried a couple of times, the last one is shown, and a ping can be sent from the settings. Private addresses are refused unless WEBHOOKS_ALLOW_PRIVATE is set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import {
|
||||
Webhook,
|
||||
WebhookDelivery,
|
||||
WebhooksGateway,
|
||||
} from '@task-stream/web/tracker/domain';
|
||||
import { map, Observable } from 'rxjs';
|
||||
import {
|
||||
CreateWebhookDocument,
|
||||
DeleteWebhookDocument,
|
||||
TestWebhookDocument,
|
||||
UpdateWebhookDocument,
|
||||
WebhookEventsDocument,
|
||||
WebhooksDocument,
|
||||
} from '../graphql/generated';
|
||||
import { GraphqlOperations } from './graphql-operations';
|
||||
|
||||
@Injectable()
|
||||
export class GraphqlWebhooksGateway extends WebhooksGateway {
|
||||
private readonly gql = inject(GraphqlOperations);
|
||||
|
||||
list(projectId: string): Observable<Webhook[]> {
|
||||
return this.gql
|
||||
.query(WebhooksDocument, { projectId })
|
||||
.pipe(map((d) => d.webhooks as Webhook[]));
|
||||
}
|
||||
|
||||
events(): Observable<string[]> {
|
||||
return this.gql
|
||||
.query(WebhookEventsDocument, {})
|
||||
.pipe(map((d) => d.webhookEvents));
|
||||
}
|
||||
|
||||
create(
|
||||
projectId: string,
|
||||
url: string,
|
||||
events: string[],
|
||||
): Observable<{ id: string; secret: string }> {
|
||||
return this.gql
|
||||
.mutate(CreateWebhookDocument, { input: { projectId, url, events } })
|
||||
.pipe(map((d) => d.createWebhook));
|
||||
}
|
||||
|
||||
update(
|
||||
webhookId: string,
|
||||
changes: { url?: string; events?: string[]; active?: boolean },
|
||||
): Observable<Webhook> {
|
||||
return this.gql
|
||||
.mutate(UpdateWebhookDocument, { input: { webhookId, ...changes } })
|
||||
.pipe(map((d) => d.updateWebhook as Webhook));
|
||||
}
|
||||
|
||||
remove(webhookId: string): Observable<void> {
|
||||
return this.gql
|
||||
.mutate(DeleteWebhookDocument, { webhookId })
|
||||
.pipe(map(() => undefined));
|
||||
}
|
||||
|
||||
test(webhookId: string): Observable<WebhookDelivery> {
|
||||
return this.gql
|
||||
.mutate(TestWebhookDocument, { webhookId })
|
||||
.pipe(map((d) => d.testWebhook));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user