feat: Implement account deletion feature with UI and API integration
Some checks failed
Deploy tt-tagebuch / deploy (push) Has been cancelled
Some checks failed
Deploy tt-tagebuch / deploy (push) Has been cancelled
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { register, activateUser, login, logout, requestPasswordReset, resetPassword } from '../services/authService.js';
|
||||
import { register, activateUser, login, logout, deleteOwnAccount, requestPasswordReset, resetPassword } from '../services/authService.js';
|
||||
|
||||
const registerUser = async (req, res, next) => {
|
||||
try {
|
||||
@@ -45,6 +45,16 @@ const logoutUser = async (req, res, next) => {
|
||||
}
|
||||
};
|
||||
|
||||
const deleteAccount = async (req, res, next) => {
|
||||
try {
|
||||
const { password } = req.body || {};
|
||||
const result = await deleteOwnAccount(req.user?.id, password);
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
const forgotPassword = async (req, res, next) => {
|
||||
try {
|
||||
const { email } = req.body;
|
||||
@@ -65,4 +75,4 @@ const resetUserPassword = async (req, res, next) => {
|
||||
}
|
||||
};
|
||||
|
||||
export { registerUser, activate, loginUser, logoutUser, forgotPassword, resetUserPassword };
|
||||
export { registerUser, activate, loginUser, logoutUser, deleteAccount, forgotPassword, resetUserPassword };
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import express from 'express';
|
||||
import { registerUser, activate, loginUser, logoutUser, forgotPassword, resetUserPassword } from '../controllers/authController.js';
|
||||
import { registerUser, activate, loginUser, logoutUser, deleteAccount, forgotPassword, resetUserPassword } from '../controllers/authController.js';
|
||||
import { authenticate } from '../middleware/authMiddleware.js';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@@ -7,6 +8,7 @@ router.post('/register', registerUser);
|
||||
router.get('/activate/:activationCode', activate);
|
||||
router.post('/login', loginUser);
|
||||
router.post('/logout', logoutUser);
|
||||
router.delete('/account', authenticate, deleteAccount);
|
||||
router.post('/forgot-password', forgotPassword);
|
||||
router.post('/reset-password', resetUserPassword);
|
||||
|
||||
|
||||
@@ -149,6 +149,11 @@ const SEO_ROUTE_CONFIG = {
|
||||
description: 'Datenschutzerklärung von Trainingstagebuch.',
|
||||
robots: 'index,follow',
|
||||
},
|
||||
'/konto-loeschen': {
|
||||
title: 'Konto und Daten löschen | Trainingstagebuch',
|
||||
description: 'Informationen zur Löschung des Benutzerkontos und personenbezogener Daten im Trainingstagebuch.',
|
||||
robots: 'index,follow',
|
||||
},
|
||||
};
|
||||
|
||||
const SEO_NOINDEX_PREFIXES = [
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
import bcrypt from 'bcrypt';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import sequelize from '../database.js';
|
||||
import User from '../models/User.js';
|
||||
import UserToken from '../models/UserToken.js';
|
||||
import UserClub from '../models/UserClub.js';
|
||||
import Log from '../models/Log.js';
|
||||
import ApiLog from '../models/ApiLog.js';
|
||||
import MyTischtennis from '../models/MyTischtennis.js';
|
||||
import MyTischtennisUpdateHistory from '../models/MyTischtennisUpdateHistory.js';
|
||||
import MyTischtennisFetchLog from '../models/MyTischtennisFetchLog.js';
|
||||
import ClickTtAccount from '../models/ClickTtAccount.js';
|
||||
import BillingUserSetting from '../models/BillingUserSetting.js';
|
||||
import BillingTemplate from '../models/BillingTemplate.js';
|
||||
import BillingRun from '../models/BillingRun.js';
|
||||
import crypto from 'crypto';
|
||||
import { sendActivationEmail, sendPasswordResetEmail } from './emailService.js';
|
||||
|
||||
@@ -106,6 +117,47 @@ const logout = async (token) => {
|
||||
return { message: 'Logout erfolgreich' };
|
||||
};
|
||||
|
||||
const deleteOwnAccount = async (userId, password) => {
|
||||
if (!userId || !password) {
|
||||
const err = new Error('Passwort ist erforderlich');
|
||||
err.status = 400;
|
||||
throw err;
|
||||
}
|
||||
|
||||
const user = await User.findByPk(userId);
|
||||
const validPassword = user && await bcrypt.compare(password, user.password);
|
||||
if (!validPassword) {
|
||||
const err = new Error('Ungültiges Passwort');
|
||||
err.status = 401;
|
||||
throw err;
|
||||
}
|
||||
|
||||
await sequelize.transaction(async (transaction) => {
|
||||
await UserToken.destroy({ where: { userId }, transaction });
|
||||
await UserClub.destroy({ where: { userId }, transaction });
|
||||
await Log.destroy({ where: { userId }, transaction });
|
||||
await ApiLog.update({ userId: null }, { where: { userId }, transaction });
|
||||
await MyTischtennis.destroy({ where: { userId }, transaction });
|
||||
await MyTischtennisUpdateHistory.destroy({ where: { userId }, transaction });
|
||||
await MyTischtennisFetchLog.destroy({ where: { userId }, transaction });
|
||||
await ClickTtAccount.destroy({ where: { userId }, transaction });
|
||||
await BillingUserSetting.destroy({ where: { userId }, transaction });
|
||||
await BillingTemplate.update({ createdByUserId: null }, { where: { createdByUserId: userId }, transaction });
|
||||
await BillingRun.update(
|
||||
{
|
||||
createdByUserId: null,
|
||||
selfRecipientName: 'Gelöschter Benutzer',
|
||||
iban: null,
|
||||
},
|
||||
{ where: { selfRecipientUserId: userId }, transaction },
|
||||
);
|
||||
await BillingRun.update({ createdByUserId: null }, { where: { createdByUserId: userId }, transaction });
|
||||
await user.destroy({ transaction });
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
};
|
||||
|
||||
const requestPasswordReset = async (email) => {
|
||||
if (!email) {
|
||||
const err = new Error('E-Mail-Adresse ist erforderlich.');
|
||||
@@ -182,4 +234,4 @@ const resetPassword = async (token, newPassword) => {
|
||||
return { message: 'Passwort wurde erfolgreich geändert.' };
|
||||
};
|
||||
|
||||
export { register, activateUser, login, logout, requestPasswordReset, resetPassword };
|
||||
export { register, activateUser, login, logout, deleteOwnAccount, requestPasswordReset, resetPassword };
|
||||
|
||||
Reference in New Issue
Block a user