initial commit
This commit is contained in:
155
fluxer_api/src/admin/controllers/ArchiveAdminController.ts
Normal file
155
fluxer_api/src/admin/controllers/ArchiveAdminController.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {createGuildID, createUserID} from '~/BrandedTypes';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {MissingACLError} from '~/Errors';
|
||||
import {requireAdminACL, requireAnyAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {Validator} from '~/Validator';
|
||||
import type {ListArchivesRequest} from '../models';
|
||||
import {
|
||||
ListArchivesRequest as ListArchivesSchema,
|
||||
TriggerGuildArchiveRequest,
|
||||
TriggerUserArchiveRequest,
|
||||
} from '../models';
|
||||
|
||||
const canViewArchive = (adminAcls: Set<string>, subjectType: 'user' | 'guild'): boolean => {
|
||||
if (adminAcls.has(AdminACLs.WILDCARD) || adminAcls.has(AdminACLs.ARCHIVE_VIEW_ALL)) return true;
|
||||
if (subjectType === 'user') return adminAcls.has(AdminACLs.ARCHIVE_TRIGGER_USER);
|
||||
return adminAcls.has(AdminACLs.ARCHIVE_TRIGGER_GUILD);
|
||||
};
|
||||
|
||||
export const ArchiveAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/archives/user',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.ARCHIVE_TRIGGER_USER),
|
||||
Validator('json', TriggerUserArchiveRequest),
|
||||
async (ctx) => {
|
||||
const adminArchiveService = ctx.get('adminArchiveService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const body = ctx.req.valid('json');
|
||||
const result = await adminArchiveService.triggerUserArchive(createUserID(BigInt(body.user_id)), adminUserId);
|
||||
return ctx.json(result, 200);
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/archives/guild',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.ARCHIVE_TRIGGER_GUILD),
|
||||
Validator('json', TriggerGuildArchiveRequest),
|
||||
async (ctx) => {
|
||||
const adminArchiveService = ctx.get('adminArchiveService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const body = ctx.req.valid('json');
|
||||
const result = await adminArchiveService.triggerGuildArchive(createGuildID(BigInt(body.guild_id)), adminUserId);
|
||||
return ctx.json(result, 200);
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/archives/list',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAnyAdminACL([AdminACLs.ARCHIVE_VIEW_ALL, AdminACLs.ARCHIVE_TRIGGER_USER, AdminACLs.ARCHIVE_TRIGGER_GUILD]),
|
||||
Validator('json', ListArchivesSchema),
|
||||
async (ctx) => {
|
||||
const adminArchiveService = ctx.get('adminArchiveService');
|
||||
const adminAcls = ctx.get('adminUserAcls');
|
||||
const body = ctx.req.valid('json') as ListArchivesRequest;
|
||||
|
||||
if (
|
||||
body.subject_type === 'all' &&
|
||||
!adminAcls.has(AdminACLs.ARCHIVE_VIEW_ALL) &&
|
||||
!adminAcls.has(AdminACLs.WILDCARD)
|
||||
) {
|
||||
throw new MissingACLError(AdminACLs.ARCHIVE_VIEW_ALL);
|
||||
}
|
||||
|
||||
if (
|
||||
body.subject_type !== 'all' &&
|
||||
!canViewArchive(adminAcls, body.subject_type) &&
|
||||
!adminAcls.has(AdminACLs.WILDCARD)
|
||||
) {
|
||||
throw new MissingACLError(
|
||||
body.subject_type === 'user' ? AdminACLs.ARCHIVE_TRIGGER_USER : AdminACLs.ARCHIVE_TRIGGER_GUILD,
|
||||
);
|
||||
}
|
||||
|
||||
const result = await adminArchiveService.listArchives({
|
||||
subjectType: body.subject_type as 'user' | 'guild' | 'all',
|
||||
subjectId: body.subject_id ? BigInt(body.subject_id) : undefined,
|
||||
requestedBy: body.requested_by ? BigInt(body.requested_by) : undefined,
|
||||
limit: body.limit,
|
||||
includeExpired: body.include_expired,
|
||||
});
|
||||
|
||||
return ctx.json({archives: result}, 200);
|
||||
},
|
||||
);
|
||||
|
||||
app.get(
|
||||
'/admin/archives/:subjectType/:subjectId/:archiveId',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAnyAdminACL([AdminACLs.ARCHIVE_VIEW_ALL, AdminACLs.ARCHIVE_TRIGGER_USER, AdminACLs.ARCHIVE_TRIGGER_GUILD]),
|
||||
async (ctx) => {
|
||||
const adminArchiveService = ctx.get('adminArchiveService');
|
||||
const adminAcls = ctx.get('adminUserAcls');
|
||||
const subjectType = ctx.req.param('subjectType') as 'user' | 'guild';
|
||||
|
||||
if (!canViewArchive(adminAcls, subjectType) && !adminAcls.has(AdminACLs.WILDCARD)) {
|
||||
throw new MissingACLError(
|
||||
subjectType === 'user' ? AdminACLs.ARCHIVE_TRIGGER_USER : AdminACLs.ARCHIVE_TRIGGER_GUILD,
|
||||
);
|
||||
}
|
||||
|
||||
const subjectId = BigInt(ctx.req.param('subjectId'));
|
||||
const archiveId = BigInt(ctx.req.param('archiveId'));
|
||||
|
||||
const archive = await adminArchiveService.getArchive(subjectType, subjectId, archiveId);
|
||||
return ctx.json({archive}, 200);
|
||||
},
|
||||
);
|
||||
|
||||
app.get(
|
||||
'/admin/archives/:subjectType/:subjectId/:archiveId/download',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAnyAdminACL([AdminACLs.ARCHIVE_VIEW_ALL, AdminACLs.ARCHIVE_TRIGGER_USER, AdminACLs.ARCHIVE_TRIGGER_GUILD]),
|
||||
async (ctx) => {
|
||||
const adminArchiveService = ctx.get('adminArchiveService');
|
||||
const adminAcls = ctx.get('adminUserAcls');
|
||||
const subjectType = ctx.req.param('subjectType') as 'user' | 'guild';
|
||||
|
||||
if (!canViewArchive(adminAcls, subjectType) && !adminAcls.has(AdminACLs.WILDCARD)) {
|
||||
throw new MissingACLError(
|
||||
subjectType === 'user' ? AdminACLs.ARCHIVE_TRIGGER_USER : AdminACLs.ARCHIVE_TRIGGER_GUILD,
|
||||
);
|
||||
}
|
||||
|
||||
const subjectId = BigInt(ctx.req.param('subjectId'));
|
||||
const archiveId = BigInt(ctx.req.param('archiveId'));
|
||||
|
||||
const result = await adminArchiveService.getDownloadUrl(subjectType, subjectId, archiveId);
|
||||
return ctx.json(result, 200);
|
||||
},
|
||||
);
|
||||
};
|
||||
41
fluxer_api/src/admin/controllers/AssetAdminController.ts
Normal file
41
fluxer_api/src/admin/controllers/AssetAdminController.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {AdminRateLimitConfigs} from '~/rate_limit_configs/AdminRateLimitConfig';
|
||||
import {Validator} from '~/Validator';
|
||||
import {PurgeGuildAssetsRequest} from '../AdminModel';
|
||||
|
||||
export const AssetAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/assets/purge',
|
||||
RateLimitMiddleware(AdminRateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.ASSET_PURGE),
|
||||
Validator('json', PurgeGuildAssetsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.purgeGuildAssets(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
};
|
||||
50
fluxer_api/src/admin/controllers/AuditLogAdminController.ts
Normal file
50
fluxer_api/src/admin/controllers/AuditLogAdminController.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {Validator} from '~/Validator';
|
||||
import {ListAuditLogsRequest, SearchAuditLogsRequest} from '../AdminModel';
|
||||
|
||||
export const AuditLogAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/audit-logs',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_AUDIT_LOG),
|
||||
requireAdminACL(AdminACLs.AUDIT_LOG_VIEW),
|
||||
Validator('json', ListAuditLogsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
return ctx.json(await adminService.listAuditLogs(ctx.req.valid('json')));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/audit-logs/search',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_AUDIT_LOG),
|
||||
requireAdminACL(AdminACLs.AUDIT_LOG_VIEW),
|
||||
Validator('json', SearchAuditLogsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
return ctx.json(await adminService.searchAuditLogs(ctx.req.valid('json')));
|
||||
},
|
||||
);
|
||||
};
|
||||
139
fluxer_api/src/admin/controllers/BanAdminController.ts
Normal file
139
fluxer_api/src/admin/controllers/BanAdminController.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {Validator} from '~/Validator';
|
||||
import {BanEmailRequest, BanIpRequest, BanPhoneRequest} from '../AdminModel';
|
||||
|
||||
export const BanAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/bans/ip/add',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_BAN_OPERATION),
|
||||
requireAdminACL(AdminACLs.BAN_IP_ADD),
|
||||
Validator('json', BanIpRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.banIp(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/bans/ip/remove',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_BAN_OPERATION),
|
||||
requireAdminACL(AdminACLs.BAN_IP_REMOVE),
|
||||
Validator('json', BanIpRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.unbanIp(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/bans/ip/check',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_BAN_OPERATION),
|
||||
requireAdminACL(AdminACLs.BAN_IP_CHECK),
|
||||
Validator('json', BanIpRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
return ctx.json(await adminService.checkIpBan(ctx.req.valid('json')));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/bans/email/add',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_BAN_OPERATION),
|
||||
requireAdminACL(AdminACLs.BAN_EMAIL_ADD),
|
||||
Validator('json', BanEmailRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.banEmail(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/bans/email/remove',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_BAN_OPERATION),
|
||||
requireAdminACL(AdminACLs.BAN_EMAIL_REMOVE),
|
||||
Validator('json', BanEmailRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.unbanEmail(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/bans/email/check',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_BAN_OPERATION),
|
||||
requireAdminACL(AdminACLs.BAN_EMAIL_CHECK),
|
||||
Validator('json', BanEmailRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
return ctx.json(await adminService.checkEmailBan(ctx.req.valid('json')));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/bans/phone/add',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_BAN_OPERATION),
|
||||
requireAdminACL(AdminACLs.BAN_PHONE_ADD),
|
||||
Validator('json', BanPhoneRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.banPhone(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/bans/phone/remove',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_BAN_OPERATION),
|
||||
requireAdminACL(AdminACLs.BAN_PHONE_REMOVE),
|
||||
Validator('json', BanPhoneRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.unbanPhone(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/bans/phone/check',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_BAN_OPERATION),
|
||||
requireAdminACL(AdminACLs.BAN_PHONE_CHECK),
|
||||
Validator('json', BanPhoneRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
return ctx.json(await adminService.checkPhoneBan(ctx.req.valid('json')));
|
||||
},
|
||||
);
|
||||
};
|
||||
85
fluxer_api/src/admin/controllers/BulkAdminController.ts
Normal file
85
fluxer_api/src/admin/controllers/BulkAdminController.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {Validator} from '~/Validator';
|
||||
import {
|
||||
BulkAddGuildMembersRequest,
|
||||
BulkScheduleUserDeletionRequest,
|
||||
BulkUpdateGuildFeaturesRequest,
|
||||
BulkUpdateUserFlagsRequest,
|
||||
} from '../AdminModel';
|
||||
|
||||
export const BulkAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/bulk/update-user-flags',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_BULK_OPERATION),
|
||||
requireAdminACL(AdminACLs.BULK_UPDATE_USER_FLAGS),
|
||||
Validator('json', BulkUpdateUserFlagsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.bulkUpdateUserFlags(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/bulk/update-guild-features',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_BULK_OPERATION),
|
||||
requireAdminACL(AdminACLs.BULK_UPDATE_GUILD_FEATURES),
|
||||
Validator('json', BulkUpdateGuildFeaturesRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.bulkUpdateGuildFeatures(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/bulk/add-guild-members',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_BULK_OPERATION),
|
||||
requireAdminACL(AdminACLs.BULK_ADD_GUILD_MEMBERS),
|
||||
Validator('json', BulkAddGuildMembersRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.bulkAddGuildMembers(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/bulk/schedule-user-deletion',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_BULK_OPERATION),
|
||||
requireAdminACL(AdminACLs.BULK_DELETE_USERS),
|
||||
Validator('json', BulkScheduleUserDeletionRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.bulkScheduleUserDeletion(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
};
|
||||
66
fluxer_api/src/admin/controllers/CodesAdminController.ts
Normal file
66
fluxer_api/src/admin/controllers/CodesAdminController.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {Config} from '~/Config';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {ProductType} from '~/stripe/ProductRegistry';
|
||||
import {Validator} from '~/Validator';
|
||||
import {GenerateBetaCodesRequest, GenerateGiftCodesRequest, type GiftProductType} from '../models/CodeRequestTypes';
|
||||
|
||||
const trimTrailingSlash = (value: string): string => (value.endsWith('/') ? value.slice(0, -1) : value);
|
||||
|
||||
const giftDurations: Record<GiftProductType, number> = {
|
||||
[ProductType.GIFT_1_MONTH]: 1,
|
||||
[ProductType.GIFT_1_YEAR]: 12,
|
||||
[ProductType.GIFT_VISIONARY]: 0,
|
||||
};
|
||||
|
||||
export const CodesAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/codes/beta',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_CODE_GENERATION),
|
||||
requireAdminACL(AdminACLs.BETA_CODES_GENERATE),
|
||||
Validator('json', GenerateBetaCodesRequest),
|
||||
async (ctx) => {
|
||||
const {count} = ctx.req.valid('json');
|
||||
const codes = await ctx.get('adminService').generateBetaCodes(count);
|
||||
return ctx.json({codes});
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/codes/gift',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_CODE_GENERATION),
|
||||
requireAdminACL(AdminACLs.GIFT_CODES_GENERATE),
|
||||
Validator('json', GenerateGiftCodesRequest),
|
||||
async (ctx) => {
|
||||
const {count, product_type} = ctx.req.valid('json');
|
||||
const durationMonths = giftDurations[product_type];
|
||||
const codes = await ctx.get('adminService').generateGiftCodes(count, durationMonths);
|
||||
const baseUrl = trimTrailingSlash(Config.endpoints.gift);
|
||||
return ctx.json({
|
||||
codes: codes.map((code) => `${baseUrl}/${code}`),
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
||||
111
fluxer_api/src/admin/controllers/FeatureFlagAdminController.ts
Normal file
111
fluxer_api/src/admin/controllers/FeatureFlagAdminController.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {ALL_FEATURE_FLAGS, FeatureFlags} from '~/constants/FeatureFlags';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {z} from '~/Schema';
|
||||
import {Validator} from '~/Validator';
|
||||
|
||||
export const FeatureFlagAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/feature-flags/get',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.FEATURE_FLAG_VIEW),
|
||||
async (ctx) => {
|
||||
const featureFlagService = ctx.get('featureFlagService');
|
||||
const config = featureFlagService.getConfigForSession();
|
||||
|
||||
return ctx.json({
|
||||
feature_flags: config,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/feature-flags/update',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.FEATURE_FLAG_MANAGE),
|
||||
Validator(
|
||||
'json',
|
||||
z.object({
|
||||
flag: z.enum([FeatureFlags.MESSAGE_SCHEDULING, FeatureFlags.EXPRESSION_PACKS]),
|
||||
guild_ids: z.string(),
|
||||
}),
|
||||
),
|
||||
async (ctx) => {
|
||||
const {flag, guild_ids} = ctx.req.valid('json');
|
||||
const featureFlagService = ctx.get('featureFlagService');
|
||||
|
||||
const guildIdArray = guild_ids
|
||||
.split(',')
|
||||
.map((id) => id.trim())
|
||||
.filter((id) => id.length > 0);
|
||||
const guildIdSet = new Set(guildIdArray);
|
||||
|
||||
await featureFlagService.setFeatureGuildIds(flag, guildIdSet);
|
||||
|
||||
const updatedConfig = featureFlagService.getConfigForSession();
|
||||
|
||||
return ctx.json({
|
||||
feature_flags: updatedConfig,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/feature-flags/list',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.FEATURE_FLAG_VIEW),
|
||||
async (ctx) => {
|
||||
return ctx.json({
|
||||
flags: ALL_FEATURE_FLAGS.map((flag) => ({
|
||||
key: flag,
|
||||
label: getFeatureFlagLabel(flag),
|
||||
description: getFeatureFlagDescription(flag),
|
||||
})),
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
function getFeatureFlagLabel(flag: string): string {
|
||||
switch (flag) {
|
||||
case FeatureFlags.MESSAGE_SCHEDULING:
|
||||
return 'Message Scheduling';
|
||||
case FeatureFlags.EXPRESSION_PACKS:
|
||||
return 'Expression Packs';
|
||||
default:
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
|
||||
function getFeatureFlagDescription(flag: string): string {
|
||||
switch (flag) {
|
||||
case FeatureFlags.MESSAGE_SCHEDULING:
|
||||
return 'Allows users to schedule messages to be sent later';
|
||||
case FeatureFlags.EXPRESSION_PACKS:
|
||||
return 'Allows users to create and share emoji/sticker packs';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
65
fluxer_api/src/admin/controllers/GatewayAdminController.ts
Normal file
65
fluxer_api/src/admin/controllers/GatewayAdminController.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {createGuildID} from '~/BrandedTypes';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {Int64Type, z} from '~/Schema';
|
||||
import {Validator} from '~/Validator';
|
||||
import {GetProcessMemoryStatsRequest} from '../AdminModel';
|
||||
|
||||
export const GatewayAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/gateway/memory-stats',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.GATEWAY_MEMORY_STATS),
|
||||
Validator('json', GetProcessMemoryStatsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const body = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.getGuildMemoryStats(body.limit));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/gateway/reload-all',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GATEWAY_RELOAD),
|
||||
requireAdminACL(AdminACLs.GATEWAY_RELOAD_ALL),
|
||||
Validator('json', z.object({guild_ids: z.array(Int64Type)})),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const body = ctx.req.valid('json');
|
||||
const guildIds = body.guild_ids.map((id) => createGuildID(id));
|
||||
return ctx.json(await adminService.reloadAllGuilds(guildIds));
|
||||
},
|
||||
);
|
||||
|
||||
app.get(
|
||||
'/admin/gateway/stats',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.GATEWAY_MEMORY_STATS),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
return ctx.json(await adminService.getNodeStats());
|
||||
},
|
||||
);
|
||||
};
|
||||
242
fluxer_api/src/admin/controllers/GuildAdminController.ts
Normal file
242
fluxer_api/src/admin/controllers/GuildAdminController.ts
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import z from 'zod';
|
||||
import type {HonoApp} from '~/App';
|
||||
import {createGuildID} from '~/BrandedTypes';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {AdminRateLimitConfigs} from '~/rate_limit_configs/AdminRateLimitConfig';
|
||||
import {Int64Type} from '~/Schema';
|
||||
import {Validator} from '~/Validator';
|
||||
import {
|
||||
ClearGuildFieldsRequest,
|
||||
DeleteGuildRequest,
|
||||
ForceAddUserToGuildRequest,
|
||||
ListGuildMembersRequest,
|
||||
LookupGuildRequest,
|
||||
ReloadGuildRequest,
|
||||
ShutdownGuildRequest,
|
||||
TransferGuildOwnershipRequest,
|
||||
UpdateGuildFeaturesRequest,
|
||||
UpdateGuildNameRequest,
|
||||
UpdateGuildSettingsRequest,
|
||||
UpdateGuildVanityRequest,
|
||||
} from '../AdminModel';
|
||||
|
||||
export const GuildAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/guilds/lookup',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.GUILD_LOOKUP),
|
||||
Validator('json', LookupGuildRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
return ctx.json(await adminService.lookupGuild(ctx.req.valid('json')));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/guilds/list-members',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.GUILD_LIST_MEMBERS),
|
||||
Validator('json', ListGuildMembersRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
return ctx.json(await adminService.listGuildMembers(ctx.req.valid('json')));
|
||||
},
|
||||
);
|
||||
|
||||
app.get(
|
||||
'/admin/guilds/:guild_id/emojis',
|
||||
RateLimitMiddleware(AdminRateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.ASSET_PURGE),
|
||||
Validator('param', z.object({guild_id: Int64Type})),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const guildId = createGuildID(ctx.req.valid('param').guild_id);
|
||||
return ctx.json(await adminService.listGuildEmojis(guildId));
|
||||
},
|
||||
);
|
||||
|
||||
app.get(
|
||||
'/admin/guilds/:guild_id/stickers',
|
||||
RateLimitMiddleware(AdminRateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.ASSET_PURGE),
|
||||
Validator('param', z.object({guild_id: Int64Type})),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const guildId = createGuildID(ctx.req.valid('param').guild_id);
|
||||
return ctx.json(await adminService.listGuildStickers(guildId));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/guilds/clear-fields',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.GUILD_UPDATE_SETTINGS),
|
||||
Validator('json', ClearGuildFieldsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.clearGuildFields(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/guilds/update-features',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.GUILD_UPDATE_FEATURES),
|
||||
Validator('json', UpdateGuildFeaturesRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
const body = ctx.req.valid('json');
|
||||
const guildId = createGuildID(body.guild_id);
|
||||
return ctx.json(
|
||||
await adminService.updateGuildFeatures({
|
||||
guildId,
|
||||
addFeatures: body.add_features,
|
||||
removeFeatures: body.remove_features,
|
||||
adminUserId,
|
||||
auditLogReason,
|
||||
}),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/guilds/update-name',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.GUILD_UPDATE_NAME),
|
||||
Validator('json', UpdateGuildNameRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.updateGuildName(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/guilds/update-settings',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.GUILD_UPDATE_SETTINGS),
|
||||
Validator('json', UpdateGuildSettingsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.updateGuildSettings(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/guilds/transfer-ownership',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.GUILD_TRANSFER_OWNERSHIP),
|
||||
Validator('json', TransferGuildOwnershipRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.transferGuildOwnership(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/guilds/update-vanity',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.GUILD_UPDATE_VANITY),
|
||||
Validator('json', UpdateGuildVanityRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.updateGuildVanity(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/guilds/force-add-user',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.GUILD_FORCE_ADD_MEMBER),
|
||||
Validator('json', ForceAddUserToGuildRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
const requestCache = ctx.get('requestCache');
|
||||
return ctx.json(
|
||||
await adminService.forceAddUserToGuild({
|
||||
data: ctx.req.valid('json'),
|
||||
requestCache,
|
||||
adminUserId,
|
||||
auditLogReason,
|
||||
}),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/guilds/reload',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.GUILD_RELOAD),
|
||||
Validator('json', ReloadGuildRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
const body = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.reloadGuild(body.guild_id, adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/guilds/shutdown',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.GUILD_SHUTDOWN),
|
||||
Validator('json', ShutdownGuildRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
const body = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.shutdownGuild(body.guild_id, adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/guilds/delete',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.GUILD_DELETE),
|
||||
Validator('json', DeleteGuildRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
const body = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.deleteGuild(body.guild_id, adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {InstanceConfigRepository} from '~/instance/InstanceConfigRepository';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {z} from '~/Schema';
|
||||
import {Validator} from '~/Validator';
|
||||
|
||||
const instanceConfigRepository = new InstanceConfigRepository();
|
||||
|
||||
export const InstanceConfigAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/instance-config/get',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.INSTANCE_CONFIG_VIEW),
|
||||
async (ctx) => {
|
||||
const config = await instanceConfigRepository.getInstanceConfig();
|
||||
const isActiveNow = instanceConfigRepository.isManualReviewActiveNow(config);
|
||||
|
||||
return ctx.json({
|
||||
manual_review_enabled: config.manualReviewEnabled,
|
||||
manual_review_schedule_enabled: config.manualReviewScheduleEnabled,
|
||||
manual_review_schedule_start_hour_utc: config.manualReviewScheduleStartHourUtc,
|
||||
manual_review_schedule_end_hour_utc: config.manualReviewScheduleEndHourUtc,
|
||||
manual_review_active_now: isActiveNow,
|
||||
registration_alerts_webhook_url: config.registrationAlertsWebhookUrl,
|
||||
system_alerts_webhook_url: config.systemAlertsWebhookUrl,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/instance-config/update',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.INSTANCE_CONFIG_UPDATE),
|
||||
Validator(
|
||||
'json',
|
||||
z.object({
|
||||
manual_review_enabled: z.boolean().optional(),
|
||||
manual_review_schedule_enabled: z.boolean().optional(),
|
||||
manual_review_schedule_start_hour_utc: z.number().min(0).max(23).optional(),
|
||||
manual_review_schedule_end_hour_utc: z.number().min(0).max(23).optional(),
|
||||
registration_alerts_webhook_url: z.string().url().nullable().optional(),
|
||||
system_alerts_webhook_url: z.string().url().nullable().optional(),
|
||||
}),
|
||||
),
|
||||
async (ctx) => {
|
||||
const data = ctx.req.valid('json');
|
||||
|
||||
if (data.manual_review_enabled !== undefined) {
|
||||
await instanceConfigRepository.setManualReviewEnabled(data.manual_review_enabled);
|
||||
}
|
||||
|
||||
if (
|
||||
data.manual_review_schedule_enabled !== undefined ||
|
||||
data.manual_review_schedule_start_hour_utc !== undefined ||
|
||||
data.manual_review_schedule_end_hour_utc !== undefined
|
||||
) {
|
||||
const currentConfig = await instanceConfigRepository.getInstanceConfig();
|
||||
|
||||
const scheduleEnabled = data.manual_review_schedule_enabled ?? currentConfig.manualReviewScheduleEnabled;
|
||||
const startHour = data.manual_review_schedule_start_hour_utc ?? currentConfig.manualReviewScheduleStartHourUtc;
|
||||
const endHour = data.manual_review_schedule_end_hour_utc ?? currentConfig.manualReviewScheduleEndHourUtc;
|
||||
|
||||
await instanceConfigRepository.setManualReviewSchedule(scheduleEnabled, startHour, endHour);
|
||||
}
|
||||
|
||||
if (data.registration_alerts_webhook_url !== undefined) {
|
||||
await instanceConfigRepository.setRegistrationAlertsWebhookUrl(data.registration_alerts_webhook_url);
|
||||
}
|
||||
|
||||
if (data.system_alerts_webhook_url !== undefined) {
|
||||
await instanceConfigRepository.setSystemAlertsWebhookUrl(data.system_alerts_webhook_url);
|
||||
}
|
||||
|
||||
const updatedConfig = await instanceConfigRepository.getInstanceConfig();
|
||||
const isActiveNow = instanceConfigRepository.isManualReviewActiveNow(updatedConfig);
|
||||
|
||||
return ctx.json({
|
||||
manual_review_enabled: updatedConfig.manualReviewEnabled,
|
||||
manual_review_schedule_enabled: updatedConfig.manualReviewScheduleEnabled,
|
||||
manual_review_schedule_start_hour_utc: updatedConfig.manualReviewScheduleStartHourUtc,
|
||||
manual_review_schedule_end_hour_utc: updatedConfig.manualReviewScheduleEndHourUtc,
|
||||
manual_review_active_now: isActiveNow,
|
||||
registration_alerts_webhook_url: updatedConfig.registrationAlertsWebhookUrl,
|
||||
system_alerts_webhook_url: updatedConfig.systemAlertsWebhookUrl,
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
||||
108
fluxer_api/src/admin/controllers/MessageAdminController.ts
Normal file
108
fluxer_api/src/admin/controllers/MessageAdminController.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {Validator} from '~/Validator';
|
||||
import {
|
||||
DeleteAllUserMessagesRequest,
|
||||
DeleteMessageRequest,
|
||||
LookupMessageByAttachmentRequest,
|
||||
LookupMessageRequest,
|
||||
MessageShredRequest,
|
||||
MessageShredStatusRequest,
|
||||
} from '../AdminModel';
|
||||
|
||||
export const MessageAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/messages/lookup',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_MESSAGE_OPERATION),
|
||||
requireAdminACL(AdminACLs.MESSAGE_LOOKUP),
|
||||
Validator('json', LookupMessageRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
return ctx.json(await adminService.lookupMessage(ctx.req.valid('json')));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/messages/lookup-by-attachment',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_MESSAGE_OPERATION),
|
||||
requireAdminACL(AdminACLs.MESSAGE_LOOKUP),
|
||||
Validator('json', LookupMessageByAttachmentRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
return ctx.json(await adminService.lookupMessageByAttachment(ctx.req.valid('json')));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/messages/delete',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_MESSAGE_OPERATION),
|
||||
requireAdminACL(AdminACLs.MESSAGE_DELETE),
|
||||
Validator('json', DeleteMessageRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.deleteMessage(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/messages/shred',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_MESSAGE_OPERATION),
|
||||
requireAdminACL(AdminACLs.MESSAGE_SHRED),
|
||||
Validator('json', MessageShredRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.queueMessageShred(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/messages/delete-all',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_MESSAGE_OPERATION),
|
||||
requireAdminACL(AdminACLs.MESSAGE_DELETE_ALL),
|
||||
Validator('json', DeleteAllUserMessagesRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.deleteAllUserMessages(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/messages/shred-status',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_MESSAGE_OPERATION),
|
||||
requireAdminACL(AdminACLs.MESSAGE_SHRED),
|
||||
Validator('json', MessageShredStatusRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const body = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.getMessageShredStatus(body.job_id));
|
||||
},
|
||||
);
|
||||
};
|
||||
101
fluxer_api/src/admin/controllers/ReportAdminController.ts
Normal file
101
fluxer_api/src/admin/controllers/ReportAdminController.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {createReportID} from '~/BrandedTypes';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {createStringType, Int64Type, z} from '~/Schema';
|
||||
import {Validator} from '~/Validator';
|
||||
import {SearchReportsRequest} from '../AdminModel';
|
||||
|
||||
export const ReportAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/reports/list',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.REPORT_VIEW),
|
||||
Validator(
|
||||
'json',
|
||||
z.object({
|
||||
status: z.number().optional(),
|
||||
limit: z.number().optional(),
|
||||
offset: z.number().optional(),
|
||||
}),
|
||||
),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const {status, limit, offset} = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.listReports(status ?? 0, limit, offset));
|
||||
},
|
||||
);
|
||||
|
||||
app.get(
|
||||
'/admin/reports/:report_id',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.REPORT_VIEW),
|
||||
Validator('param', z.object({report_id: Int64Type})),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const {report_id} = ctx.req.valid('param');
|
||||
const report = await adminService.getReport(createReportID(report_id));
|
||||
return ctx.json(report);
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/reports/resolve',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.REPORT_RESOLVE),
|
||||
Validator(
|
||||
'json',
|
||||
z.object({
|
||||
report_id: Int64Type,
|
||||
public_comment: createStringType(0, 512).optional(),
|
||||
}),
|
||||
),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
const {report_id, public_comment} = ctx.req.valid('json');
|
||||
return ctx.json(
|
||||
await adminService.resolveReport(
|
||||
createReportID(report_id),
|
||||
adminUserId,
|
||||
public_comment || null,
|
||||
auditLogReason,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/reports/search',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.REPORT_VIEW),
|
||||
Validator('json', SearchReportsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const body = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.searchReports(body));
|
||||
},
|
||||
);
|
||||
};
|
||||
83
fluxer_api/src/admin/controllers/SearchAdminController.ts
Normal file
83
fluxer_api/src/admin/controllers/SearchAdminController.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {Validator} from '~/Validator';
|
||||
import {
|
||||
GetIndexRefreshStatusRequest,
|
||||
RefreshSearchIndexRequest,
|
||||
SearchGuildsRequest,
|
||||
SearchUsersRequest,
|
||||
} from '../AdminModel';
|
||||
|
||||
export const SearchAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/guilds/search',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.GUILD_LOOKUP),
|
||||
Validator('json', SearchGuildsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const body = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.searchGuilds(body));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/search',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.USER_LOOKUP),
|
||||
Validator('json', SearchUsersRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const body = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.searchUsers(body));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/search/refresh-index',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.GUILD_LOOKUP),
|
||||
Validator('json', RefreshSearchIndexRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
const body = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.refreshSearchIndex(body, adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/search/refresh-status',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.GUILD_LOOKUP),
|
||||
Validator('json', GetIndexRefreshStatusRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const body = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.getIndexRefreshStatus(body.job_id));
|
||||
},
|
||||
);
|
||||
};
|
||||
374
fluxer_api/src/admin/controllers/UserAdminController.ts
Normal file
374
fluxer_api/src/admin/controllers/UserAdminController.ts
Normal file
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {createUserID} from '~/BrandedTypes';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {Validator} from '~/Validator';
|
||||
import {
|
||||
CancelBulkMessageDeletionRequest,
|
||||
ChangeDobRequest,
|
||||
ChangeEmailRequest,
|
||||
ChangeUsernameRequest,
|
||||
ClearUserFieldsRequest,
|
||||
DisableForSuspiciousActivityRequest,
|
||||
DisableMfaRequest,
|
||||
ListUserChangeLogRequest,
|
||||
ListUserGuildsRequest,
|
||||
ListUserSessionsRequest,
|
||||
LookupUserRequest,
|
||||
ScheduleAccountDeletionRequest,
|
||||
SendPasswordResetRequest,
|
||||
SetUserAclsRequest,
|
||||
SetUserBotStatusRequest,
|
||||
SetUserSystemStatusRequest,
|
||||
TempBanUserRequest,
|
||||
TerminateSessionsRequest,
|
||||
UnlinkPhoneRequest,
|
||||
UpdateSuspiciousActivityFlagsRequest,
|
||||
UpdateUserFlagsRequest,
|
||||
VerifyUserEmailRequest,
|
||||
} from '../AdminModel';
|
||||
|
||||
export const UserAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/users/lookup',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.USER_LOOKUP),
|
||||
Validator('json', LookupUserRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
return ctx.json(await adminService.lookupUser(ctx.req.valid('json')));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/list-guilds',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.USER_LIST_GUILDS),
|
||||
Validator('json', ListUserGuildsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
return ctx.json(await adminService.listUserGuilds(ctx.req.valid('json')));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/disable-mfa',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_MFA),
|
||||
Validator('json', DisableMfaRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
await adminService.disableMfa(ctx.req.valid('json'), adminUserId, auditLogReason);
|
||||
return ctx.body(null, 204);
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/clear-fields',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_PROFILE),
|
||||
Validator('json', ClearUserFieldsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.clearUserFields(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/set-bot-status',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_BOT_STATUS),
|
||||
Validator('json', SetUserBotStatusRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.setUserBotStatus(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/set-system-status',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_BOT_STATUS),
|
||||
Validator('json', SetUserSystemStatusRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.setUserSystemStatus(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/verify-email',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_EMAIL),
|
||||
Validator('json', VerifyUserEmailRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.verifyUserEmail(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/send-password-reset',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_EMAIL),
|
||||
Validator('json', SendPasswordResetRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
await adminService.sendPasswordReset(ctx.req.valid('json'), adminUserId, auditLogReason);
|
||||
return ctx.body(null, 204);
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/change-username',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_USERNAME),
|
||||
Validator('json', ChangeUsernameRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.changeUsername(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/change-email',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_EMAIL),
|
||||
Validator('json', ChangeEmailRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.changeEmail(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/terminate-sessions',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_FLAGS),
|
||||
Validator('json', TerminateSessionsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.terminateSessions(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/temp-ban',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_TEMP_BAN),
|
||||
Validator('json', TempBanUserRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.tempBanUser(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/unban',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_TEMP_BAN),
|
||||
Validator('json', DisableMfaRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.unbanUser(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/schedule-deletion',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_DELETE),
|
||||
Validator('json', ScheduleAccountDeletionRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.scheduleAccountDeletion(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/cancel-deletion',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_DELETE),
|
||||
Validator('json', DisableMfaRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.cancelAccountDeletion(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/cancel-bulk-message-deletion',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_CANCEL_BULK_MESSAGE_DELETION),
|
||||
Validator('json', CancelBulkMessageDeletionRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.cancelBulkMessageDeletion(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/set-acls',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.ACL_SET_USER),
|
||||
Validator('json', SetUserAclsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.setUserAcls(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/update-flags',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_FLAGS),
|
||||
Validator('json', UpdateUserFlagsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
const body = ctx.req.valid('json');
|
||||
const userId = createUserID(body.user_id);
|
||||
return ctx.json(
|
||||
await adminService.updateUserFlags({
|
||||
userId,
|
||||
data: {addFlags: body.add_flags, removeFlags: body.remove_flags},
|
||||
adminUserId,
|
||||
auditLogReason,
|
||||
}),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/unlink-phone',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_PHONE),
|
||||
Validator('json', UnlinkPhoneRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.unlinkPhone(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/change-dob',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_DOB),
|
||||
Validator('json', ChangeDobRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.changeDob(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/update-suspicious-activity-flags',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_SUSPICIOUS_ACTIVITY),
|
||||
Validator('json', UpdateSuspiciousActivityFlagsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(
|
||||
await adminService.updateSuspiciousActivityFlags(ctx.req.valid('json'), adminUserId, auditLogReason),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/disable-suspicious',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_DISABLE_SUSPICIOUS),
|
||||
Validator('json', DisableForSuspiciousActivityRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(
|
||||
await adminService.disableForSuspiciousActivity(ctx.req.valid('json'), adminUserId, auditLogReason),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/list-sessions',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_LIST_SESSIONS),
|
||||
Validator('json', ListUserSessionsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
const body = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.listUserSessions(body.user_id, adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/users/change-log',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.USER_LOOKUP),
|
||||
Validator('json', ListUserChangeLogRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
return ctx.json(await adminService.listUserChangeLog(ctx.req.valid('json')));
|
||||
},
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {createUserID} from '~/BrandedTypes';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {Int64Type, z} from '~/Schema';
|
||||
import {Validator} from '~/Validator';
|
||||
|
||||
export const VerificationAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/pending-verifications/list',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.USER_LOOKUP),
|
||||
Validator('json', z.object({limit: z.number().default(100)})),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const {limit} = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.listPendingVerifications(limit));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/pending-verifications/approve',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_FLAGS),
|
||||
Validator('json', z.object({user_id: Int64Type})),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
const {user_id} = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.approveRegistration(createUserID(user_id), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/pending-verifications/reject',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_FLAGS),
|
||||
Validator('json', z.object({user_id: Int64Type})),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
const {user_id} = ctx.req.valid('json');
|
||||
return ctx.json(await adminService.rejectRegistration(createUserID(user_id), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/pending-verifications/bulk-approve',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_FLAGS),
|
||||
Validator('json', z.object({user_ids: z.array(Int64Type).min(1)})),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
const {user_ids} = ctx.req.valid('json');
|
||||
const parsedUserIds = user_ids.map(createUserID);
|
||||
return ctx.json(await adminService.bulkApproveRegistrations(parsedUserIds, adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/pending-verifications/bulk-reject',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY),
|
||||
requireAdminACL(AdminACLs.USER_UPDATE_FLAGS),
|
||||
Validator('json', z.object({user_ids: z.array(Int64Type).min(1)})),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
const {user_ids} = ctx.req.valid('json');
|
||||
const parsedUserIds = user_ids.map(createUserID);
|
||||
return ctx.json(await adminService.bulkRejectRegistrations(parsedUserIds, adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
};
|
||||
169
fluxer_api/src/admin/controllers/VoiceAdminController.ts
Normal file
169
fluxer_api/src/admin/controllers/VoiceAdminController.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {AdminACLs} from '~/Constants';
|
||||
import {requireAdminACL} from '~/middleware/AdminMiddleware';
|
||||
import {RateLimitMiddleware} from '~/middleware/RateLimitMiddleware';
|
||||
import {RateLimitConfigs} from '~/RateLimitConfig';
|
||||
import {Validator} from '~/Validator';
|
||||
import {
|
||||
CreateVoiceRegionRequest,
|
||||
CreateVoiceServerRequest,
|
||||
DeleteVoiceRegionRequest,
|
||||
DeleteVoiceServerRequest,
|
||||
GetVoiceRegionRequest,
|
||||
GetVoiceServerRequest,
|
||||
ListVoiceRegionsRequest,
|
||||
ListVoiceServersRequest,
|
||||
UpdateVoiceRegionRequest,
|
||||
UpdateVoiceServerRequest,
|
||||
} from '../AdminModel';
|
||||
|
||||
export const VoiceAdminController = (app: HonoApp) => {
|
||||
app.post(
|
||||
'/admin/voice/regions/list',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.VOICE_REGION_LIST),
|
||||
Validator('json', ListVoiceRegionsRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.listVoiceRegions(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/voice/regions/get',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.VOICE_REGION_LIST),
|
||||
Validator('json', GetVoiceRegionRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.getVoiceRegion(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/voice/regions/create',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.VOICE_REGION_CREATE),
|
||||
Validator('json', CreateVoiceRegionRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.createVoiceRegion(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/voice/regions/update',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.VOICE_REGION_UPDATE),
|
||||
Validator('json', UpdateVoiceRegionRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.updateVoiceRegion(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/voice/regions/delete',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.VOICE_REGION_DELETE),
|
||||
Validator('json', DeleteVoiceRegionRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.deleteVoiceRegion(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/voice/servers/list',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.VOICE_SERVER_LIST),
|
||||
Validator('json', ListVoiceServersRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.listVoiceServers(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/voice/servers/get',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP),
|
||||
requireAdminACL(AdminACLs.VOICE_SERVER_LIST),
|
||||
Validator('json', GetVoiceServerRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.getVoiceServer(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/voice/servers/create',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.VOICE_SERVER_CREATE),
|
||||
Validator('json', CreateVoiceServerRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.createVoiceServer(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/voice/servers/update',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.VOICE_SERVER_UPDATE),
|
||||
Validator('json', UpdateVoiceServerRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.updateVoiceServer(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/admin/voice/servers/delete',
|
||||
RateLimitMiddleware(RateLimitConfigs.ADMIN_GUILD_MODIFY),
|
||||
requireAdminACL(AdminACLs.VOICE_SERVER_DELETE),
|
||||
Validator('json', DeleteVoiceServerRequest),
|
||||
async (ctx) => {
|
||||
const adminService = ctx.get('adminService');
|
||||
const adminUserId = ctx.get('adminUserId');
|
||||
const auditLogReason = ctx.get('auditLogReason');
|
||||
return ctx.json(await adminService.deleteVoiceServer(ctx.req.valid('json'), adminUserId, auditLogReason));
|
||||
},
|
||||
);
|
||||
};
|
||||
55
fluxer_api/src/admin/controllers/index.ts
Normal file
55
fluxer_api/src/admin/controllers/index.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {HonoApp} from '~/App';
|
||||
import {ArchiveAdminController} from './ArchiveAdminController';
|
||||
import {AssetAdminController} from './AssetAdminController';
|
||||
import {AuditLogAdminController} from './AuditLogAdminController';
|
||||
import {BanAdminController} from './BanAdminController';
|
||||
import {BulkAdminController} from './BulkAdminController';
|
||||
import {CodesAdminController} from './CodesAdminController';
|
||||
import {FeatureFlagAdminController} from './FeatureFlagAdminController';
|
||||
import {GatewayAdminController} from './GatewayAdminController';
|
||||
import {GuildAdminController} from './GuildAdminController';
|
||||
import {InstanceConfigAdminController} from './InstanceConfigAdminController';
|
||||
import {MessageAdminController} from './MessageAdminController';
|
||||
import {ReportAdminController} from './ReportAdminController';
|
||||
import {SearchAdminController} from './SearchAdminController';
|
||||
import {UserAdminController} from './UserAdminController';
|
||||
import {VerificationAdminController} from './VerificationAdminController';
|
||||
import {VoiceAdminController} from './VoiceAdminController';
|
||||
|
||||
export const registerAdminControllers = (app: HonoApp) => {
|
||||
UserAdminController(app);
|
||||
CodesAdminController(app);
|
||||
GuildAdminController(app);
|
||||
AssetAdminController(app);
|
||||
BanAdminController(app);
|
||||
InstanceConfigAdminController(app);
|
||||
MessageAdminController(app);
|
||||
BulkAdminController(app);
|
||||
AuditLogAdminController(app);
|
||||
ArchiveAdminController(app);
|
||||
ReportAdminController(app);
|
||||
VoiceAdminController(app);
|
||||
GatewayAdminController(app);
|
||||
SearchAdminController(app);
|
||||
VerificationAdminController(app);
|
||||
FeatureFlagAdminController(app);
|
||||
};
|
||||
Reference in New Issue
Block a user