Account deletion logic
All checks were successful
Deploy to Server / deploy (push) Successful in 37s

This commit is contained in:
2026-04-09 23:10:23 -05:00
parent bce2afe761
commit efc77ae758
3 changed files with 136 additions and 2 deletions

View File

@@ -7,6 +7,7 @@ import { authRateLimiter, apiRateLimiter } from './auth/rateLimiter.js';
import chemicalsRouter from './routes/chemicals.js';
import protocolsRouter from './routes/protocols.js';
import profileRouter from './routes/profile.js';
import accountRouter from './routes/account.js';
import path from 'path';
import { fileURLToPath } from 'url';
@@ -93,6 +94,7 @@ app.use('/api', apiRateLimiter);
app.use('/api/chemicals', chemicalsRouter);
app.use('/api/protocols', protocolsRouter);
app.use('/api/profile', profileRouter);
app.use('/api/account', accountRouter);
app.get('/api/health', (_req, res) => res.json({ ok: true }));

View File

@@ -0,0 +1,57 @@
import { Router } from 'express';
import { pool } from '../db/pool.js';
import { requireAuth } from '../auth/middleware.js';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const uploadsDir = process.env.UPLOADS_DIR || path.join(__dirname, '../../uploads');
const router = Router();
router.use(requireAuth);
// POST /api/account/delete
router.post('/delete', async (req, res) => {
const userId = req.user!.id;
const client = await pool.connect();
try {
await client.query('BEGIN');
// 1. Delete all chemicals for this user
await client.query('DELETE FROM chemicals WHERE user_id = $1', [userId]);
// 2. Delete all protocols for this user
await client.query('DELETE FROM protocols WHERE user_id = $1', [userId]);
// 3. Delete user profile (has CASCADE, but be explicit)
await client.query('DELETE FROM user_profile WHERE user_id = $1', [userId]);
// 4. Delete sessions and accounts (CASCADE from user, but be explicit)
await client.query('DELETE FROM session WHERE "userId" = $1', [userId]);
await client.query('DELETE FROM account WHERE "userId" = $1', [userId]);
await client.query('DELETE FROM verification WHERE identifier = $1', [userId]);
// 5. Delete the user record itself
await client.query('DELETE FROM "user" WHERE id = $1', [userId]);
await client.query('COMMIT');
// 6. Clean up uploaded files outside the transaction
const userUploadsDir = path.join(uploadsDir, userId);
if (fs.existsSync(userUploadsDir)) {
fs.rmSync(userUploadsDir, { recursive: true, force: true });
}
res.json({ deleted: true });
} catch (err) {
await client.query('ROLLBACK');
console.error('Account deletion failed:', err);
res.status(500).json({ error: 'Account deletion failed' });
} finally {
client.release();
}
});
export default router;