forked from StellarSplit/StellarSplit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwebhooks.service.ts
More file actions
125 lines (104 loc) · 3.5 KB
/
Copy pathwebhooks.service.ts
File metadata and controls
125 lines (104 loc) · 3.5 KB
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
import {
Injectable,
NotFoundException,
BadRequestException,
Logger,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Webhook, WebhookEventType } from './webhook.entity';
import { CreateWebhookDto } from './dto/create-webhook.dto';
import { UpdateWebhookDto } from './dto/update-webhook.dto';
@Injectable()
export class WebhooksService {
private readonly logger = new Logger(WebhooksService.name);
constructor(
@InjectRepository(Webhook)
private readonly webhookRepository: Repository<Webhook>,
) {}
async create(createWebhookDto: CreateWebhookDto): Promise<Webhook> {
// Validate URL is reachable (basic check)
if (!this.isValidUrl(createWebhookDto.url)) {
throw new BadRequestException('Invalid webhook URL');
}
const webhook = this.webhookRepository.create({
...createWebhookDto,
isActive: true,
failureCount: 0,
});
return await this.webhookRepository.save(webhook);
}
async findAll(userId?: string): Promise<Webhook[]> {
const where = userId ? { userId } : {};
return await this.webhookRepository.find({
where,
order: { createdAt: 'DESC' },
relations: ['deliveries'],
});
}
async findOne(id: string): Promise<Webhook> {
const webhook = await this.webhookRepository.findOne({
where: { id },
relations: ['deliveries'],
});
if (!webhook) {
throw new NotFoundException(`Webhook with ID ${id} not found`);
}
return webhook;
}
async findByUserId(userId: string): Promise<Webhook[]> {
return await this.webhookRepository.find({
where: { userId },
order: { createdAt: 'DESC' },
});
}
async findByEventType(eventType: WebhookEventType): Promise<Webhook[]> {
return await this.webhookRepository
.createQueryBuilder('webhook')
.where('webhook.isActive = :isActive', { isActive: true })
.andWhere('webhook.events @> :event', {
event: JSON.stringify([eventType]),
})
.getMany();
}
async update(id: string, updateWebhookDto: UpdateWebhookDto): Promise<Webhook> {
const webhook = await this.findOne(id);
if (updateWebhookDto.url && !this.isValidUrl(updateWebhookDto.url)) {
throw new BadRequestException('Invalid webhook URL');
}
Object.assign(webhook, updateWebhookDto);
return await this.webhookRepository.save(webhook);
}
async remove(id: string): Promise<void> {
const webhook = await this.findOne(id);
await this.webhookRepository.remove(webhook);
}
async incrementFailureCount(id: string): Promise<void> {
const webhook = await this.findOne(id);
webhook.failureCount += 1;
// Deactivate if failure count exceeds threshold (e.g., 10 failures)
if (webhook.failureCount >= 10) {
webhook.isActive = false;
this.logger.warn(`Webhook ${id} deactivated due to excessive failures`);
}
await this.webhookRepository.save(webhook);
}
async resetFailureCount(id: string): Promise<void> {
const webhook = await this.findOne(id);
webhook.failureCount = 0;
await this.webhookRepository.save(webhook);
}
async updateLastTriggered(id: string): Promise<void> {
const webhook = await this.findOne(id);
webhook.lastTriggeredAt = new Date();
await this.webhookRepository.save(webhook);
}
private isValidUrl(url: string): boolean {
try {
const parsed = new URL(url);
return ['http:', 'https:'].includes(parsed.protocol);
} catch {
return false;
}
}
}