59 lines
2.9 KiB
TypeScript
59 lines
2.9 KiB
TypeScript
import type { Database } from '@tursodatabase/database';
|
|
import { randomUUID } from 'node:crypto';
|
|
import { deleteUploadedAvatar } from '$lib/server/avatars';
|
|
|
|
export async function softDeleteAccount(
|
|
database: Database,
|
|
userId: string,
|
|
deletedBy: string,
|
|
reason: string | null,
|
|
purgeSecurityData = false
|
|
): Promise<boolean> {
|
|
const user = await (await database.prepare(`
|
|
SELECT users.username,users.login_username,user_profiles.display_name,deleted_accounts.deleted_at
|
|
FROM users LEFT JOIN user_profiles ON user_profiles.user_id=users.id
|
|
LEFT JOIN deleted_accounts ON deleted_accounts.user_id=users.id
|
|
WHERE users.id=?
|
|
`)).get(userId);
|
|
if (!user || user.deleted_at) return false;
|
|
const now = new Date().toISOString();
|
|
const deletedUsername = `deleted-agent-${userId.slice(0, 12)}`;
|
|
|
|
await (await database.prepare(
|
|
'INSERT INTO deleted_accounts(user_id,original_username,deleted_at,deleted_by,reason) VALUES(?,?,?,?,?)'
|
|
)).run(userId, purgeSecurityData ? deletedUsername : String(user.login_username ?? user.username), now, deletedBy, reason);
|
|
await (await database.prepare(
|
|
`UPDATE users SET username=?,login_username=NULL,password_hash=NULL,discord_id=NULL,role='user' WHERE id=?`
|
|
)).run(deletedUsername, userId);
|
|
await (await database.prepare(
|
|
`INSERT INTO user_profiles(user_id,display_name,updated_at) VALUES(?,?,?)
|
|
ON CONFLICT(user_id) DO UPDATE SET display_name=excluded.display_name,updated_at=excluded.updated_at`
|
|
)).run(userId, 'Deleted Agent', now);
|
|
await (await database.prepare('DELETE FROM sessions WHERE user_id=?')).run(userId);
|
|
await (await database.prepare('DELETE FROM magic_link_tokens WHERE user_id=?')).run(userId);
|
|
await (await database.prepare('DELETE FROM webauthn_challenges WHERE user_id=?')).run(userId);
|
|
await (await database.prepare('DELETE FROM passkeys WHERE user_id=?')).run(userId);
|
|
await (await database.prepare('DELETE FROM user_emails WHERE user_id=?')).run(userId);
|
|
await (await database.prepare('DELETE FROM oauth_states WHERE user_id=?')).run(userId);
|
|
await (await database.prepare('DELETE FROM discord_profiles WHERE user_id=?')).run(userId);
|
|
await (await database.prepare('DELETE FROM user_roles WHERE user_id=?')).run(userId);
|
|
await (await database.prepare('DELETE FROM user_permissions WHERE user_id=?')).run(userId);
|
|
await deleteUploadedAvatar(database, userId);
|
|
if (purgeSecurityData) {
|
|
await (await database.prepare('DELETE FROM login_events WHERE user_id=?')).run(userId);
|
|
}
|
|
await (await database.prepare(
|
|
'INSERT INTO audit_log(id,actor_id,entity_type,entity_id,action,before_json,after_json,created_at) VALUES(?,?,?,?,?,?,?,?)'
|
|
)).run(
|
|
randomUUID(),
|
|
deletedBy,
|
|
'user',
|
|
userId,
|
|
'account.soft_deleted',
|
|
purgeSecurityData ? JSON.stringify({ purgedAtOwnerRequest: true }) : JSON.stringify({ username: user.username, displayName: user.display_name }),
|
|
JSON.stringify({ username: deletedUsername, displayName: 'Deleted Agent', reason, securityDataPurged: purgeSecurityData }),
|
|
now
|
|
);
|
|
return true;
|
|
}
|