mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-09 12:12:25 +09:00
85 lines
3.5 KiB
TypeScript
85 lines
3.5 KiB
TypeScript
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
import {AdminAuditReadActions} from '@app/api/admin/AdminAuditActions';
|
|
import {recordAdminRead, recordAdminWrite} from '@app/api/admin/AdminAuditRecorder';
|
|
import {createChannelID, createGuildID} from '@app/api/BrandedTypes';
|
|
import {requireAdminACL} from '@app/api/middleware/AdminMiddleware';
|
|
import {RateLimitMiddleware} from '@app/api/middleware/RateLimitMiddleware';
|
|
import {OpenAPI} from '@app/api/middleware/ResponseTypeMiddleware';
|
|
import {AdminRateLimitConfigs} from '@app/api/rate_limit_configs/AdminRateLimitConfig';
|
|
import type {HonoApp} from '@app/api/types/HonoEnv';
|
|
import {Validator} from '@app/api/Validator';
|
|
import {AdminACLs} from '@fluxer/constants/src/AdminACLs';
|
|
import {InvalidChannelTypeError} from '@fluxer/errors/src/domains/channel/InvalidChannelTypeError';
|
|
import {UnknownChannelError} from '@fluxer/errors/src/domains/channel/UnknownChannelError';
|
|
import {ListGuildThreadsResponse} from '@fluxer/schema/src/domains/admin/AdminThreadSchemas';
|
|
import {ChannelIdParam, GuildIdParam} from '@fluxer/schema/src/domains/common/CommonParamSchemas';
|
|
|
|
export function ThreadAdminController(app: HonoApp) {
|
|
app.get(
|
|
'/admin/guilds/:guild_id/threads',
|
|
RateLimitMiddleware(AdminRateLimitConfigs.ADMIN_LOOKUP),
|
|
requireAdminACL(AdminACLs.GUILD_LOOKUP),
|
|
Validator('param', GuildIdParam),
|
|
OpenAPI({
|
|
operationId: 'list_admin_guild_threads',
|
|
summary: 'List guild threads',
|
|
description:
|
|
'Lists every thread of a guild, active and archived, whether or not the channel threads experiment is active for it. Requires GUILD_LOOKUP permission.',
|
|
responseSchema: ListGuildThreadsResponse,
|
|
statusCode: 200,
|
|
security: 'adminApiKey',
|
|
tags: 'Admin',
|
|
experiment: 'channel_threads',
|
|
}),
|
|
async (ctx) => {
|
|
const guildId = createGuildID(ctx.req.valid('param').guild_id);
|
|
const threads = await ctx.get('threadService').lists.listGuildThreadsForAdmin(guildId);
|
|
await recordAdminRead(ctx, {
|
|
targetType: 'guild',
|
|
targetId: guildId,
|
|
action: AdminAuditReadActions.LIST_GUILD_THREADS,
|
|
metadata: {result_count: threads.length},
|
|
});
|
|
return ctx.json({threads});
|
|
},
|
|
);
|
|
app.delete(
|
|
'/admin/channels/:channel_id',
|
|
RateLimitMiddleware(AdminRateLimitConfigs.ADMIN_MESSAGE_OPERATION),
|
|
requireAdminACL(AdminACLs.MESSAGE_DELETE_ALL),
|
|
Validator('param', ChannelIdParam),
|
|
OpenAPI({
|
|
operationId: 'delete_admin_thread_channel',
|
|
summary: 'Delete a thread',
|
|
description:
|
|
'Deletes a thread channel with its messages and memberships. Only public and private threads can be deleted here. Requires MESSAGE_DELETE_ALL permission.',
|
|
responseSchema: null,
|
|
statusCode: 204,
|
|
security: 'adminApiKey',
|
|
tags: 'Admin',
|
|
experiment: 'channel_threads',
|
|
}),
|
|
async (ctx) => {
|
|
const channelId = createChannelID(ctx.req.valid('param').channel_id);
|
|
const thread = await ctx.get('channelRepository').findUnique(channelId);
|
|
if (!thread) throw new UnknownChannelError();
|
|
if (!thread.isThread()) throw new InvalidChannelTypeError();
|
|
const adminUserId = ctx.get('adminUserId');
|
|
await ctx.get('threadService').deletion.deleteThread({
|
|
thread,
|
|
actorId: adminUserId,
|
|
auditLogReason: ctx.get('auditLogReason'),
|
|
recordGuildAudit: false,
|
|
});
|
|
await recordAdminWrite(ctx, {
|
|
targetType: 'channel',
|
|
targetId: channelId,
|
|
action: 'delete_thread',
|
|
metadata: {guild_id: thread.guildId?.toString(), parent_id: thread.parentId?.toString(), type: thread.type},
|
|
});
|
|
return ctx.body(null, 204);
|
|
},
|
|
);
|
|
}
|