@hed-hog/core 0.0.347 → 0.0.350
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/auth.controller.d.ts +1 -1
- package/dist/auth/auth.service.d.ts +1 -1
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +3 -0
- package/dist/core.module.js.map +1 -1
- package/dist/dashboard/dashboard-user/dashboard-user.controller.d.ts +3 -3
- package/dist/dashboard/dashboard-user/dashboard-user.service.d.ts +3 -3
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/guards/mcp-auth.guard.d.ts +6 -1
- package/dist/mcp/guards/mcp-auth.guard.d.ts.map +1 -1
- package/dist/mcp/guards/mcp-auth.guard.js +29 -2
- package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
- package/dist/mcp/mcp-api-key.controller.d.ts +32 -0
- package/dist/mcp/mcp-api-key.controller.d.ts.map +1 -0
- package/dist/mcp/mcp-api-key.controller.js +64 -0
- package/dist/mcp/mcp-api-key.controller.js.map +1 -0
- package/dist/mcp/mcp-api-key.service.d.ts +27 -0
- package/dist/mcp/mcp-api-key.service.d.ts.map +1 -0
- package/dist/mcp/mcp-api-key.service.js +74 -0
- package/dist/mcp/mcp-api-key.service.js.map +1 -0
- package/dist/mcp/mcp-registry.service.d.ts +1 -2
- package/dist/mcp/mcp-registry.service.d.ts.map +1 -1
- package/dist/mcp/mcp-registry.service.js +6 -2
- package/dist/mcp/mcp-registry.service.js.map +1 -1
- package/dist/mcp/mcp.module.d.ts.map +1 -1
- package/dist/mcp/mcp.module.js +8 -1
- package/dist/mcp/mcp.module.js.map +1 -1
- package/dist/mcp-chat/mcp-chat.controller.d.ts +4 -0
- package/dist/mcp-chat/mcp-chat.controller.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.controller.js +46 -0
- package/dist/mcp-chat/mcp-chat.controller.js.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.d.ts +6 -1
- package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.js +125 -17
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
- package/dist/notification/dto/create-notification.dto.d.ts +26 -0
- package/dist/notification/dto/create-notification.dto.d.ts.map +1 -0
- package/dist/notification/dto/create-notification.dto.js +86 -0
- package/dist/notification/dto/create-notification.dto.js.map +1 -0
- package/dist/notification/dto/update-progress.dto.d.ts +6 -0
- package/dist/notification/dto/update-progress.dto.d.ts.map +1 -0
- package/dist/notification/dto/update-progress.dto.js +33 -0
- package/dist/notification/dto/update-progress.dto.js.map +1 -0
- package/dist/notification/notification.controller.d.ts +108 -0
- package/dist/notification/notification.controller.d.ts.map +1 -0
- package/dist/notification/notification.controller.js +118 -0
- package/dist/notification/notification.controller.js.map +1 -0
- package/dist/notification/notification.module.d.ts +3 -0
- package/dist/notification/notification.module.d.ts.map +1 -0
- package/dist/notification/notification.module.js +29 -0
- package/dist/notification/notification.module.js.map +1 -0
- package/dist/notification/notification.service.d.ts +98 -0
- package/dist/notification/notification.service.d.ts.map +1 -0
- package/dist/notification/notification.service.js +123 -0
- package/dist/notification/notification.service.js.map +1 -0
- package/dist/profile/profile.controller.d.ts +1 -1
- package/dist/profile/profile.service.d.ts +1 -1
- package/dist/setting/dto/update-setting-list.dto.d.ts +9 -0
- package/dist/setting/dto/update-setting-list.dto.d.ts.map +1 -0
- package/dist/setting/dto/update-setting-list.dto.js +44 -0
- package/dist/setting/dto/update-setting-list.dto.js.map +1 -0
- package/dist/setting/setting.controller.d.ts +19 -0
- package/dist/setting/setting.controller.d.ts.map +1 -1
- package/dist/setting/setting.controller.js +12 -0
- package/dist/setting/setting.controller.js.map +1 -1
- package/dist/setting/setting.service.d.ts +19 -0
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +79 -0
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/task/task.service.d.ts +12 -0
- package/dist/task/task.service.d.ts.map +1 -1
- package/dist/task/task.service.js +60 -0
- package/dist/task/task.service.js.map +1 -1
- package/dist/user/user.controller.d.ts +2 -2
- package/dist/user/user.service.d.ts +3 -3
- package/dist/webhook-integration/webhook-integration.service.d.ts +4 -0
- package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.js +184 -34
- package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
- package/dist/webhook-integration/webhook-utils.d.ts +1 -0
- package/dist/webhook-integration/webhook-utils.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-utils.js +38 -0
- package/dist/webhook-integration/webhook-utils.js.map +1 -1
- package/hedhog/data/menu.yaml +48 -4
- package/hedhog/data/route.yaml +133 -0
- package/hedhog/data/setting_group.yaml +45 -0
- package/hedhog/data/setting_subgroup.yaml +16 -0
- package/hedhog/frontend/app/account/components/mcp-tokens.tsx.ejs +285 -0
- package/hedhog/frontend/app/account/layout.tsx.ejs +32 -55
- package/hedhog/frontend/app/account/mcp-tokens/page.tsx.ejs +5 -0
- package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +2098 -1835
- package/hedhog/frontend/app/mcp_chat/chat-components.tsx.ejs +595 -0
- package/hedhog/frontend/app/mcp_chat/chat-types.ts.ejs +16 -0
- package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +554 -383
- package/hedhog/frontend/app/setting-list/page.tsx.ejs +649 -0
- package/hedhog/frontend/app/users/page.tsx.ejs +445 -203
- package/hedhog/frontend/app/users/user-sheet.tsx.ejs +16 -37
- package/hedhog/frontend/messages/en.json +241 -2
- package/hedhog/frontend/messages/pt.json +241 -2
- package/hedhog/table/mcp_api_key.yaml +30 -0
- package/hedhog/table/notification.yaml +72 -0
- package/hedhog/table/webhook_action_log.yaml +49 -0
- package/package.json +2 -2
- package/src/core.module.ts +3 -0
- package/src/index.ts +5 -0
- package/src/mcp/guards/mcp-auth.guard.ts +64 -32
- package/src/mcp/mcp-api-key.controller.ts +42 -0
- package/src/mcp/mcp-api-key.service.ts +66 -0
- package/src/mcp/mcp-registry.service.ts +75 -69
- package/src/mcp/mcp.module.ts +43 -36
- package/src/mcp-chat/mcp-chat.controller.ts +113 -60
- package/src/mcp-chat/mcp-chat.service.ts +494 -332
- package/src/notification/dto/create-notification.dto.ts +71 -0
- package/src/notification/dto/update-progress.dto.ts +16 -0
- package/src/notification/notification.controller.ts +71 -0
- package/src/notification/notification.module.ts +16 -0
- package/src/notification/notification.service.ts +124 -0
- package/src/setting/dto/update-setting-list.dto.ts +32 -0
- package/src/setting/setting.controller.ts +9 -0
- package/src/setting/setting.service.ts +91 -0
- package/src/task/task.service.ts +72 -0
- package/src/webhook-integration/webhook-integration.service.ts +934 -735
- package/src/webhook-integration/webhook-utils.ts +136 -79
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IsBoolean,
|
|
3
|
+
IsDateString,
|
|
4
|
+
IsEnum,
|
|
5
|
+
IsNumber,
|
|
6
|
+
IsObject,
|
|
7
|
+
IsOptional,
|
|
8
|
+
IsString,
|
|
9
|
+
Max,
|
|
10
|
+
Min,
|
|
11
|
+
} from 'class-validator';
|
|
12
|
+
|
|
13
|
+
export enum NotificationType {
|
|
14
|
+
Info = 'info',
|
|
15
|
+
Success = 'success',
|
|
16
|
+
Warning = 'warning',
|
|
17
|
+
Error = 'error',
|
|
18
|
+
Progress = 'progress',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export enum NotificationActionType {
|
|
22
|
+
Url = 'url',
|
|
23
|
+
Sheet = 'sheet',
|
|
24
|
+
Modal = 'modal',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class CreateNotificationDto {
|
|
28
|
+
@IsNumber()
|
|
29
|
+
user_id: number;
|
|
30
|
+
|
|
31
|
+
@IsString()
|
|
32
|
+
title: string;
|
|
33
|
+
|
|
34
|
+
@IsOptional()
|
|
35
|
+
@IsString()
|
|
36
|
+
body?: string;
|
|
37
|
+
|
|
38
|
+
@IsOptional()
|
|
39
|
+
@IsString()
|
|
40
|
+
icon?: string;
|
|
41
|
+
|
|
42
|
+
@IsOptional()
|
|
43
|
+
@IsEnum(NotificationType)
|
|
44
|
+
type?: NotificationType;
|
|
45
|
+
|
|
46
|
+
@IsOptional()
|
|
47
|
+
@IsEnum(NotificationActionType)
|
|
48
|
+
action_type?: NotificationActionType;
|
|
49
|
+
|
|
50
|
+
@IsOptional()
|
|
51
|
+
@IsObject()
|
|
52
|
+
action_data?: Record<string, unknown>;
|
|
53
|
+
|
|
54
|
+
@IsOptional()
|
|
55
|
+
@IsString()
|
|
56
|
+
action_url?: string;
|
|
57
|
+
|
|
58
|
+
@IsOptional()
|
|
59
|
+
@IsBoolean()
|
|
60
|
+
auto_remove?: boolean;
|
|
61
|
+
|
|
62
|
+
@IsOptional()
|
|
63
|
+
@IsNumber()
|
|
64
|
+
@Min(0)
|
|
65
|
+
@Max(100)
|
|
66
|
+
progress?: number;
|
|
67
|
+
|
|
68
|
+
@IsOptional()
|
|
69
|
+
@IsDateString()
|
|
70
|
+
started_at?: string;
|
|
71
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IsBoolean, IsNumber, IsOptional, IsString, Max, Min } from 'class-validator';
|
|
2
|
+
|
|
3
|
+
export class UpdateProgressDto {
|
|
4
|
+
@IsNumber()
|
|
5
|
+
@Min(0)
|
|
6
|
+
@Max(100)
|
|
7
|
+
progress: number;
|
|
8
|
+
|
|
9
|
+
@IsOptional()
|
|
10
|
+
@IsString()
|
|
11
|
+
body?: string;
|
|
12
|
+
|
|
13
|
+
@IsOptional()
|
|
14
|
+
@IsBoolean()
|
|
15
|
+
success?: boolean;
|
|
16
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Role, User } from '@hed-hog/api';
|
|
2
|
+
import { Pagination } from '@hed-hog/api-pagination';
|
|
3
|
+
import {
|
|
4
|
+
Body,
|
|
5
|
+
Controller,
|
|
6
|
+
Delete,
|
|
7
|
+
Get,
|
|
8
|
+
Param,
|
|
9
|
+
ParseIntPipe,
|
|
10
|
+
Patch,
|
|
11
|
+
Post,
|
|
12
|
+
} from '@nestjs/common';
|
|
13
|
+
import { CreateNotificationDto } from './dto/create-notification.dto';
|
|
14
|
+
import { UpdateProgressDto } from './dto/update-progress.dto';
|
|
15
|
+
import { NotificationService } from './notification.service';
|
|
16
|
+
|
|
17
|
+
@Role()
|
|
18
|
+
@Controller('notification')
|
|
19
|
+
export class NotificationController {
|
|
20
|
+
constructor(private readonly notificationService: NotificationService) {}
|
|
21
|
+
|
|
22
|
+
@Get()
|
|
23
|
+
async list(@User() { id }, @Pagination() paginationParams) {
|
|
24
|
+
return this.notificationService.list(id, paginationParams);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Get('unread-count')
|
|
28
|
+
async unreadCount(@User() { id }) {
|
|
29
|
+
return this.notificationService.unreadCount(id);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@Patch('read-all')
|
|
33
|
+
async markAllRead(@User() { id }) {
|
|
34
|
+
return this.notificationService.markAllRead(id);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@Patch(':id/read')
|
|
38
|
+
async markRead(
|
|
39
|
+
@User() { id: userId },
|
|
40
|
+
@Param('id', ParseIntPipe) id: number,
|
|
41
|
+
) {
|
|
42
|
+
return this.notificationService.markRead(userId, id);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@Patch(':id/progress')
|
|
46
|
+
async updateProgress(
|
|
47
|
+
@User() { id: userId },
|
|
48
|
+
@Param('id', ParseIntPipe) id: number,
|
|
49
|
+
@Body() dto: UpdateProgressDto,
|
|
50
|
+
) {
|
|
51
|
+
return this.notificationService.updateProgress(userId, id, dto);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@Delete()
|
|
55
|
+
async deleteAll(@User() { id }) {
|
|
56
|
+
return this.notificationService.deleteAll(id);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@Delete(':id')
|
|
60
|
+
async delete(
|
|
61
|
+
@User() { id: userId },
|
|
62
|
+
@Param('id', ParseIntPipe) id: number,
|
|
63
|
+
) {
|
|
64
|
+
return this.notificationService.delete(userId, id);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@Post()
|
|
68
|
+
async create(@Body() data: CreateNotificationDto) {
|
|
69
|
+
return this.notificationService.create(data);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { PaginationModule } from '@hed-hog/api-pagination';
|
|
2
|
+
import { PrismaModule } from '@hed-hog/api-prisma';
|
|
3
|
+
import { forwardRef, Module } from '@nestjs/common';
|
|
4
|
+
import { NotificationController } from './notification.controller';
|
|
5
|
+
import { NotificationService } from './notification.service';
|
|
6
|
+
|
|
7
|
+
@Module({
|
|
8
|
+
imports: [
|
|
9
|
+
forwardRef(() => PrismaModule),
|
|
10
|
+
forwardRef(() => PaginationModule),
|
|
11
|
+
],
|
|
12
|
+
controllers: [NotificationController],
|
|
13
|
+
providers: [NotificationService],
|
|
14
|
+
exports: [NotificationService],
|
|
15
|
+
})
|
|
16
|
+
export class NotificationModule {}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { PaginationService } from '@hed-hog/api-pagination';
|
|
2
|
+
import { PrismaService } from '@hed-hog/api-prisma';
|
|
3
|
+
import {
|
|
4
|
+
ForbiddenException,
|
|
5
|
+
forwardRef,
|
|
6
|
+
Inject,
|
|
7
|
+
Injectable,
|
|
8
|
+
NotFoundException,
|
|
9
|
+
} from '@nestjs/common';
|
|
10
|
+
import { CreateNotificationDto } from './dto/create-notification.dto';
|
|
11
|
+
import { UpdateProgressDto } from './dto/update-progress.dto';
|
|
12
|
+
|
|
13
|
+
@Injectable()
|
|
14
|
+
export class NotificationService {
|
|
15
|
+
constructor(
|
|
16
|
+
@Inject(forwardRef(() => PrismaService))
|
|
17
|
+
private readonly prisma: PrismaService,
|
|
18
|
+
@Inject(forwardRef(() => PaginationService))
|
|
19
|
+
private readonly pagination: PaginationService,
|
|
20
|
+
) {}
|
|
21
|
+
|
|
22
|
+
async list(userId: number, paginationParams: any) {
|
|
23
|
+
return this.pagination.paginate(
|
|
24
|
+
this.prisma.notification,
|
|
25
|
+
paginationParams,
|
|
26
|
+
{
|
|
27
|
+
where: { user_id: userId },
|
|
28
|
+
orderBy: { created_at: 'desc' },
|
|
29
|
+
},
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async unreadCount(userId: number) {
|
|
34
|
+
const count = await this.prisma.notification.count({
|
|
35
|
+
where: { user_id: userId, status: 'unread' },
|
|
36
|
+
});
|
|
37
|
+
return { count };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async markRead(userId: number, id: number) {
|
|
41
|
+
const notification = await this.assertOwnership(userId, id);
|
|
42
|
+
if (notification.auto_remove) {
|
|
43
|
+
return this.prisma.notification.delete({ where: { id } });
|
|
44
|
+
}
|
|
45
|
+
return this.prisma.notification.update({
|
|
46
|
+
where: { id },
|
|
47
|
+
data: { status: 'read' },
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async markAllRead(userId: number) {
|
|
52
|
+
await this.prisma.notification.deleteMany({
|
|
53
|
+
where: { user_id: userId, status: 'unread', auto_remove: true },
|
|
54
|
+
});
|
|
55
|
+
return this.prisma.notification.updateMany({
|
|
56
|
+
where: { user_id: userId, status: 'unread' },
|
|
57
|
+
data: { status: 'read' },
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async delete(userId: number, id: number) {
|
|
62
|
+
await this.assertOwnership(userId, id);
|
|
63
|
+
return this.prisma.notification.delete({ where: { id } });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async deleteAll(userId: number) {
|
|
67
|
+
return this.prisma.notification.deleteMany({ where: { user_id: userId } });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async create(data: CreateNotificationDto) {
|
|
71
|
+
return this.prisma.notification.create({
|
|
72
|
+
data: {
|
|
73
|
+
user_id: data.user_id,
|
|
74
|
+
title: data.title,
|
|
75
|
+
body: data.body,
|
|
76
|
+
icon: data.icon,
|
|
77
|
+
type: (data.type as any) ?? 'info',
|
|
78
|
+
action_type: (data.action_type as any) ?? 'url',
|
|
79
|
+
action_data: data.action_data as any,
|
|
80
|
+
action_url: data.action_url,
|
|
81
|
+
auto_remove: data.auto_remove ?? false,
|
|
82
|
+
progress: data.progress,
|
|
83
|
+
started_at: data.started_at ? new Date(data.started_at) : undefined,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async updateProgress(userId: number, id: number, dto: UpdateProgressDto) {
|
|
89
|
+
await this.assertOwnership(userId, id);
|
|
90
|
+
const finished = dto.progress >= 100;
|
|
91
|
+
return this.prisma.notification.update({
|
|
92
|
+
where: { id },
|
|
93
|
+
data: {
|
|
94
|
+
progress: dto.progress,
|
|
95
|
+
body: dto.body,
|
|
96
|
+
type: finished ? (dto.success === false ? 'error' : 'success') as any : undefined,
|
|
97
|
+
finished_at: finished ? new Date() : undefined,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async clearOldNotifications(retentionDays: number, batchLimit: number) {
|
|
103
|
+
return this.prisma.$executeRawUnsafe(
|
|
104
|
+
`WITH del AS (
|
|
105
|
+
SELECT id FROM notification
|
|
106
|
+
WHERE created_at < NOW() - INTERVAL '${retentionDays} days'
|
|
107
|
+
ORDER BY id
|
|
108
|
+
LIMIT ${batchLimit}
|
|
109
|
+
)
|
|
110
|
+
DELETE FROM notification n
|
|
111
|
+
USING del WHERE n.id = del.id`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private async assertOwnership(userId: number, id: number) {
|
|
116
|
+
const notification = await this.prisma.notification.findUnique({
|
|
117
|
+
where: { id },
|
|
118
|
+
select: { user_id: true, auto_remove: true },
|
|
119
|
+
});
|
|
120
|
+
if (!notification) throw new NotFoundException();
|
|
121
|
+
if (notification.user_id !== userId) throw new ForbiddenException();
|
|
122
|
+
return notification;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Type } from 'class-transformer';
|
|
2
|
+
import {
|
|
3
|
+
IsArray,
|
|
4
|
+
IsInt,
|
|
5
|
+
IsOptional,
|
|
6
|
+
IsString,
|
|
7
|
+
Length,
|
|
8
|
+
ValidateNested,
|
|
9
|
+
} from 'class-validator';
|
|
10
|
+
|
|
11
|
+
export class UpdateSettingListItemDTO {
|
|
12
|
+
@IsOptional()
|
|
13
|
+
@Type(() => Number)
|
|
14
|
+
@IsInt()
|
|
15
|
+
id?: number;
|
|
16
|
+
|
|
17
|
+
@IsString()
|
|
18
|
+
@Length(1, 255)
|
|
19
|
+
value: string;
|
|
20
|
+
|
|
21
|
+
@IsOptional()
|
|
22
|
+
@Type(() => Number)
|
|
23
|
+
@IsInt()
|
|
24
|
+
order?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class UpdateSettingListDTO {
|
|
28
|
+
@IsArray()
|
|
29
|
+
@ValidateNested({ each: true })
|
|
30
|
+
@Type(() => UpdateSettingListItemDTO)
|
|
31
|
+
options: UpdateSettingListItemDTO[];
|
|
32
|
+
}
|
|
@@ -27,6 +27,7 @@ import { DeleteDTO } from './dto/delete.dto';
|
|
|
27
27
|
import { ExportDto } from './dto/export.dto';
|
|
28
28
|
import { SettingUserDTO } from './dto/setting-user.dto';
|
|
29
29
|
import { SettingDTO } from './dto/setting.dto';
|
|
30
|
+
import { UpdateSettingListDTO } from './dto/update-setting-list.dto';
|
|
30
31
|
import { UpdateDTO } from './dto/update.dto';
|
|
31
32
|
import { SettingService } from './setting.service';
|
|
32
33
|
|
|
@@ -124,6 +125,14 @@ export class SettingsController {
|
|
|
124
125
|
return this.settingService.updateFromSlug(slug, data);
|
|
125
126
|
}
|
|
126
127
|
|
|
128
|
+
@Put(':settingId/options')
|
|
129
|
+
async updateSettingListOptions(
|
|
130
|
+
@Param('settingId', ParseIntPipe) settingId: number,
|
|
131
|
+
@Body() data: UpdateSettingListDTO,
|
|
132
|
+
) {
|
|
133
|
+
return this.settingService.updateSettingListOptions(settingId, data);
|
|
134
|
+
}
|
|
135
|
+
|
|
127
136
|
@Put()
|
|
128
137
|
async setManySettings(@Body() data: SettingDTO) {
|
|
129
138
|
return this.settingService.setManySettings(data);
|
|
@@ -15,6 +15,7 @@ import { IntegrationDeveloperApiService } from '../integration/services/integrat
|
|
|
15
15
|
import { CreateDTO } from './dto/create.dto';
|
|
16
16
|
import { DeleteDTO } from './dto/delete.dto';
|
|
17
17
|
import { SettingDTO } from './dto/setting.dto';
|
|
18
|
+
import { UpdateSettingListDTO } from './dto/update-setting-list.dto';
|
|
18
19
|
import { UpdateDTO } from './dto/update.dto';
|
|
19
20
|
|
|
20
21
|
type SettingChangeEventInput = {
|
|
@@ -497,6 +498,21 @@ export class SettingService {
|
|
|
497
498
|
},
|
|
498
499
|
},
|
|
499
500
|
},
|
|
501
|
+
setting_subgroup: {
|
|
502
|
+
include: {
|
|
503
|
+
setting_subgroup_locale: {
|
|
504
|
+
where: {
|
|
505
|
+
locale: {
|
|
506
|
+
code: locale,
|
|
507
|
+
},
|
|
508
|
+
},
|
|
509
|
+
select: {
|
|
510
|
+
name: true,
|
|
511
|
+
description: true,
|
|
512
|
+
},
|
|
513
|
+
},
|
|
514
|
+
},
|
|
515
|
+
},
|
|
500
516
|
setting_locale: {
|
|
501
517
|
where: {
|
|
502
518
|
locale: {
|
|
@@ -508,6 +524,16 @@ export class SettingService {
|
|
|
508
524
|
description: true,
|
|
509
525
|
},
|
|
510
526
|
},
|
|
527
|
+
setting_list: {
|
|
528
|
+
select: {
|
|
529
|
+
id: true,
|
|
530
|
+
order: true,
|
|
531
|
+
value: true,
|
|
532
|
+
},
|
|
533
|
+
orderBy: {
|
|
534
|
+
order: 'asc',
|
|
535
|
+
},
|
|
536
|
+
},
|
|
511
537
|
},
|
|
512
538
|
},
|
|
513
539
|
'setting_locale',
|
|
@@ -518,12 +544,77 @@ export class SettingService {
|
|
|
518
544
|
'setting_group_locale',
|
|
519
545
|
setting.setting_group,
|
|
520
546
|
);
|
|
547
|
+
|
|
548
|
+
if (setting.setting_subgroup) {
|
|
549
|
+
setting.setting_subgroup = itemTranslations(
|
|
550
|
+
'setting_subgroup_locale',
|
|
551
|
+
setting.setting_subgroup,
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
setting.subgroupId ??=
|
|
556
|
+
setting.subgroup_id ?? setting.setting_subgroup?.id ?? null;
|
|
557
|
+
|
|
521
558
|
return setting;
|
|
522
559
|
});
|
|
523
560
|
|
|
524
561
|
return result;
|
|
525
562
|
}
|
|
526
563
|
|
|
564
|
+
async updateSettingListOptions(settingId: number, data: UpdateSettingListDTO) {
|
|
565
|
+
this.clearCache();
|
|
566
|
+
|
|
567
|
+
const setting = await this.prismaService.setting.findUnique({
|
|
568
|
+
where: { id: settingId },
|
|
569
|
+
select: {
|
|
570
|
+
id: true,
|
|
571
|
+
component: true,
|
|
572
|
+
},
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
if (!setting) {
|
|
576
|
+
throw new NotFoundException(`Setting with ID ${settingId} not found.`);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const component = String(setting.component ?? '').toLowerCase();
|
|
580
|
+
if (component !== 'combobox' && component !== 'checkbox') {
|
|
581
|
+
throw new BadRequestException(
|
|
582
|
+
'Only combobox and checkbox settings support list options.',
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
const options = (data.options ?? [])
|
|
587
|
+
.map((option, index) => ({
|
|
588
|
+
value: option.value?.trim() ?? '',
|
|
589
|
+
order: option.order ?? index + 1,
|
|
590
|
+
}))
|
|
591
|
+
.filter((option) => option.value.length > 0);
|
|
592
|
+
|
|
593
|
+
const updatedSetting = await this.prismaService.setting.update({
|
|
594
|
+
where: { id: settingId },
|
|
595
|
+
data: {
|
|
596
|
+
setting_list: {
|
|
597
|
+
deleteMany: {},
|
|
598
|
+
create: options,
|
|
599
|
+
},
|
|
600
|
+
},
|
|
601
|
+
include: {
|
|
602
|
+
setting_list: {
|
|
603
|
+
select: {
|
|
604
|
+
id: true,
|
|
605
|
+
order: true,
|
|
606
|
+
value: true,
|
|
607
|
+
},
|
|
608
|
+
orderBy: {
|
|
609
|
+
order: 'asc',
|
|
610
|
+
},
|
|
611
|
+
},
|
|
612
|
+
},
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
return updatedSetting;
|
|
616
|
+
}
|
|
617
|
+
|
|
527
618
|
async get(settingId: number) {
|
|
528
619
|
const setting = await this.prismaService.setting.findUnique({
|
|
529
620
|
where: { id: settingId },
|
package/src/task/task.service.ts
CHANGED
|
@@ -36,6 +36,12 @@ export class TasksService {
|
|
|
36
36
|
await this.clearUnverifiedMfaWithExpiredChallenges();
|
|
37
37
|
this.logger.verbose('++++++++++++++++++++++++++++++++++');
|
|
38
38
|
|
|
39
|
+
await this.clearExpiredWebhookLogs();
|
|
40
|
+
this.logger.verbose('++++++++++++++++++++++++++++++++++');
|
|
41
|
+
|
|
42
|
+
await this.clearOldNotifications();
|
|
43
|
+
this.logger.verbose('++++++++++++++++++++++++++++++++++');
|
|
44
|
+
|
|
39
45
|
this.logger.verbose('Finished scheduled cleanup tasks');
|
|
40
46
|
this.logger.verbose('++++++++++++++++++++++++++++++++++');
|
|
41
47
|
}
|
|
@@ -225,4 +231,70 @@ export class TasksService {
|
|
|
225
231
|
`Unverified MFA with expired challenges cleaned up in ${Date.now() - startAt}ms`,
|
|
226
232
|
);
|
|
227
233
|
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Limpa logs antigos de execução de webhooks de entrada com base na política
|
|
237
|
+
* de retenção configurada em settings.
|
|
238
|
+
*
|
|
239
|
+
* Remove registros da tabela webhook_call_log que:
|
|
240
|
+
* - Foram criados há mais dias do que o valor de webhook-log-retention-days
|
|
241
|
+
*
|
|
242
|
+
* Os registros relacionados em webhook_action_log são removidos em cascata
|
|
243
|
+
* pelo relacionamento FK com onDelete CASCADE.
|
|
244
|
+
*/
|
|
245
|
+
private async clearExpiredWebhookLogs(): Promise<void> {
|
|
246
|
+
const settings = await this.settingService.getSettingValues([
|
|
247
|
+
'cleanup-batch-limit',
|
|
248
|
+
'webhook-log-retention-days',
|
|
249
|
+
]);
|
|
250
|
+
const batchLimit = Number(settings['cleanup-batch-limit']) || 20000;
|
|
251
|
+
const retentionDays = Number(settings['webhook-log-retention-days']) || 30;
|
|
252
|
+
this.logger.verbose('Starting cleanup of expired webhook call logs');
|
|
253
|
+
const startAt = Date.now();
|
|
254
|
+
|
|
255
|
+
await this.prismaService.$executeRaw`
|
|
256
|
+
WITH del AS (
|
|
257
|
+
SELECT id
|
|
258
|
+
FROM webhook_call_log
|
|
259
|
+
WHERE created_at < (now() - ${Prisma.sql`INTERVAL '${Prisma.raw(String(retentionDays))} days'`})
|
|
260
|
+
ORDER BY id
|
|
261
|
+
LIMIT ${batchLimit}
|
|
262
|
+
)
|
|
263
|
+
DELETE FROM webhook_call_log wcl
|
|
264
|
+
USING del
|
|
265
|
+
WHERE wcl.id = del.id
|
|
266
|
+
`;
|
|
267
|
+
|
|
268
|
+
this.logger.verbose(
|
|
269
|
+
`Expired webhook call logs cleaned up in ${Date.now() - startAt}ms`,
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
private async clearOldNotifications(): Promise<void> {
|
|
274
|
+
const settings = await this.settingService.getSettingValues([
|
|
275
|
+
'cleanup-batch-limit',
|
|
276
|
+
'notification-retention-days',
|
|
277
|
+
]);
|
|
278
|
+
const batchLimit = Number(settings['cleanup-batch-limit']) || 20000;
|
|
279
|
+
const retentionDays = Number(settings['notification-retention-days']) || 30;
|
|
280
|
+
this.logger.verbose('Starting cleanup of old notifications');
|
|
281
|
+
const startAt = Date.now();
|
|
282
|
+
|
|
283
|
+
await this.prismaService.$executeRaw`
|
|
284
|
+
WITH del AS (
|
|
285
|
+
SELECT id
|
|
286
|
+
FROM notification
|
|
287
|
+
WHERE created_at < (now() - ${Prisma.sql`INTERVAL '${Prisma.raw(String(retentionDays))} days'`})
|
|
288
|
+
ORDER BY id
|
|
289
|
+
LIMIT ${batchLimit}
|
|
290
|
+
)
|
|
291
|
+
DELETE FROM notification n
|
|
292
|
+
USING del
|
|
293
|
+
WHERE n.id = del.id
|
|
294
|
+
`;
|
|
295
|
+
|
|
296
|
+
this.logger.verbose(
|
|
297
|
+
`Old notifications cleaned up in ${Date.now() - startAt}ms`,
|
|
298
|
+
);
|
|
299
|
+
}
|
|
228
300
|
}
|