This repository has no description
Something went wrong. Try again.
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263// SPDX-License-Identifier: AGPL-3.0-or-later
import {UnknownGuildError} from '@fluxer/errors/src/domains/guild/UnknownGuildError';import type { ClearGuildFieldsRequest, TransferGuildOwnershipRequest, UpdateGuildNameRequest, UpdateGuildSettingsRequest,} from '@fluxer/schema/src/domains/admin/AdminGuildSchemas';import {createGuildID, createUserID, type GuildID, type UserID} from '../../../BrandedTypes';import type {GuildRow} from '../../../database/types/GuildTypes';import type {IGuildRepositoryAggregate} from '../../../guild/repositories/IGuildRepositoryAggregate';import type {EntityAssetService, PreparedAssetUpload} from '../../../infrastructure/EntityAssetService';import type {Guild} from '../../../models/Guild';import {mapGuildToAdminResponse} from '../../models/GuildTypes';import type {AdminAuditService} from '../AdminAuditService';import type {AdminGuildUpdatePropagator} from './AdminGuildUpdatePropagator';
interface AdminGuildUpdateServiceDeps { guildRepository: IGuildRepositoryAggregate; entityAssetService: EntityAssetService; auditService: AdminAuditService; updatePropagator: AdminGuildUpdatePropagator;}
export class AdminGuildUpdateService { constructor(private readonly deps: AdminGuildUpdateServiceDeps) {}
async updateGuildFeatures({ guildId, addFeatures, removeFeatures, adminUserId, auditLogReason, }: { guildId: GuildID; addFeatures: Array<string>; removeFeatures: Array<string>; adminUserId: UserID; auditLogReason: string | null; }) { const {guildRepository, auditService, updatePropagator} = this.deps; const guild = await guildRepository.findUnique(guildId); if (!guild) { throw new UnknownGuildError(); } const newFeatures = new Set(guild.features); for (const feature of addFeatures) { newFeatures.add(feature); } for (const feature of removeFeatures) { newFeatures.delete(feature); } const updatedGuild = await guildRepository.upsertPartial(guildId, {features: newFeatures}, guild.toRow()); await updatePropagator.dispatchGuildUpdate(guildId, updatedGuild, { adminUserId, reconcileDiscoveryFeature: true, }); await auditService.createAuditLog({ adminUserId, targetType: 'guild', targetId: BigInt(guildId), action: 'update_features', auditLogReason, metadata: new Map([ ['add_features', addFeatures.join(',')], ['remove_features', removeFeatures.join(',')], ['new_features', Array.from(newFeatures).join(',')], ]), }); return { guild: mapGuildToAdminResponse(updatedGuild), }; }
async clearGuildFields(data: ClearGuildFieldsRequest, adminUserId: UserID, auditLogReason: string | null) { const {guildRepository, entityAssetService, auditService, updatePropagator} = this.deps; const guildId = createGuildID(data.guild_id); const guild = await guildRepository.findUnique(guildId); if (!guild) { throw new UnknownGuildError(); } const patch: Partial<GuildRow> = {}; const preparedAssets: Array<PreparedAssetUpload> = []; for (const field of data.fields) { if (field === 'icon') { const prepared = await entityAssetService.prepareAssetUpload({ assetType: 'icon', entityType: 'guild', entityId: guildId, previousHash: guild.iconHash, base64Image: null, errorPath: 'icon', }); preparedAssets.push(prepared); patch.icon_hash = prepared.newHash; } else if (field === 'banner') { const prepared = await entityAssetService.prepareAssetUpload({ assetType: 'banner', entityType: 'guild', entityId: guildId, previousHash: guild.bannerHash, base64Image: null, errorPath: 'banner', }); preparedAssets.push(prepared); patch.banner_hash = prepared.newHash; } else if (field === 'splash') { const prepared = await entityAssetService.prepareAssetUpload({ assetType: 'splash', entityType: 'guild', entityId: guildId, previousHash: guild.splashHash, base64Image: null, errorPath: 'splash', }); preparedAssets.push(prepared); patch.splash_hash = prepared.newHash; } else if (field === 'embed_splash') { const prepared = await entityAssetService.prepareAssetUpload({ assetType: 'embed_splash', entityType: 'guild', entityId: guildId, previousHash: guild.embedSplashHash, base64Image: null, errorPath: 'embed_splash', }); preparedAssets.push(prepared); patch.embed_splash_hash = prepared.newHash; } } let updatedGuild: Guild; try { updatedGuild = Object.keys(patch).length === 0 ? guild : await guildRepository.upsertPartial(guildId, patch, guild.toRow()); } catch (error) { await Promise.allSettled(preparedAssets.map((p) => entityAssetService.rollbackAssetUpload(p))); throw error; } await Promise.allSettled(preparedAssets.map((p) => entityAssetService.commitAssetChange({prepared: p}))); await updatePropagator.dispatchGuildUpdate(guildId, updatedGuild); await auditService.createAuditLog({ adminUserId, targetType: 'guild', targetId: BigInt(guildId), action: 'clear_fields', auditLogReason, metadata: new Map([['fields', data.fields.join(',')]]), }); }
async updateGuildName(data: UpdateGuildNameRequest, adminUserId: UserID, auditLogReason: string | null) { const {guildRepository, auditService, updatePropagator} = this.deps; const guildId = createGuildID(data.guild_id); const guild = await guildRepository.findUnique(guildId); if (!guild) { throw new UnknownGuildError(); } const oldName = guild.name; const updatedGuild = await guildRepository.upsertPartial(guildId, {name: data.name}, guild.toRow()); await updatePropagator.dispatchGuildUpdate(guildId, updatedGuild); await auditService.createAuditLog({ adminUserId, targetType: 'guild', targetId: BigInt(guildId), action: 'update_name', auditLogReason, metadata: new Map([ ['old_name', oldName], ['new_name', data.name], ]), }); return { guild: mapGuildToAdminResponse(updatedGuild), }; }
async updateGuildSettings(data: UpdateGuildSettingsRequest, adminUserId: UserID, auditLogReason: string | null) { const {guildRepository, auditService, updatePropagator} = this.deps; const guildId = createGuildID(data.guild_id); const guild = await guildRepository.findUnique(guildId); if (!guild) { throw new UnknownGuildError(); } const patch: Partial<GuildRow> = {}; const metadata = new Map<string, string>(); if (data.verification_level !== undefined) { patch.verification_level = data.verification_level; metadata.set('verification_level', data.verification_level.toString()); } if (data.mfa_level !== undefined) { patch.mfa_level = data.mfa_level; metadata.set('mfa_level', data.mfa_level.toString()); } if (data.nsfw_level !== undefined) { patch.nsfw_level = data.nsfw_level; metadata.set('nsfw_level', data.nsfw_level.toString()); } if (data.explicit_content_filter !== undefined) { patch.explicit_content_filter = data.explicit_content_filter; metadata.set('explicit_content_filter', data.explicit_content_filter.toString()); } if (data.default_message_notifications !== undefined) { patch.default_message_notifications = data.default_message_notifications; metadata.set('default_message_notifications', data.default_message_notifications.toString()); } if (data.disabled_operations !== undefined) { patch.disabled_operations = data.disabled_operations; metadata.set('disabled_operations', data.disabled_operations.toString()); } const updatedGuild = Object.keys(patch).length === 0 ? guild : await guildRepository.upsertPartial(guildId, patch, guild.toRow()); await updatePropagator.dispatchGuildUpdate(guildId, updatedGuild); await auditService.createAuditLog({ adminUserId, targetType: 'guild', targetId: BigInt(guildId), action: 'update_settings', auditLogReason, metadata, }); return { guild: mapGuildToAdminResponse(updatedGuild), }; }
async transferGuildOwnership( data: TransferGuildOwnershipRequest, adminUserId: UserID, auditLogReason: string | null, ) { const {guildRepository, auditService, updatePropagator} = this.deps; const guildId = createGuildID(data.guild_id); const guild = await guildRepository.findUnique(guildId); if (!guild) { throw new UnknownGuildError(); } const newOwnerId = createUserID(data.new_owner_id); const oldOwnerId = guild.ownerId; const updatedGuild = await guildRepository.upsertPartial( guildId, {owner_id: newOwnerId}, guild.toRow(), oldOwnerId, ); await updatePropagator.dispatchGuildUpdate(guildId, updatedGuild); await auditService.createAuditLog({ adminUserId, targetType: 'guild', targetId: BigInt(guildId), action: 'transfer_ownership', auditLogReason, metadata: new Map([ ['old_owner_id', oldOwnerId.toString()], ['new_owner_id', newOwnerId.toString()], ]), }); return { guild: mapGuildToAdminResponse(updatedGuild), }; }}