Add account deletion feature and privacy section
Implement a new endpoint for account deletion in AuthController, allowing users to permanently delete their accounts and associated data. Update AuthService to handle account deletion logic, including confirmation checks and data removal from the database. Enhance frontend with new views and components for account deletion and privacy information, including links in the side menu and profile view. Update mobile app to support account deletion and privacy sections, improving user experience and compliance with data protection standards.
This commit is contained in:
@@ -257,7 +257,31 @@ class AuthController {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Eigenen Account und personenbezogene Daten löschen
|
||||
* DELETE /api/auth/account
|
||||
*/
|
||||
async deleteAccount(req, res) {
|
||||
try {
|
||||
const userId = req.user.userId;
|
||||
const { confirmation } = req.body;
|
||||
|
||||
await authService.deleteAccount(userId, confirmation);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Account wurde gelöscht'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Löschen des Accounts:', error);
|
||||
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new AuthController();
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ router.post('/logout', authenticateToken, authController.logout.bind(authControl
|
||||
router.get('/me', authenticateToken, authController.getCurrentUser.bind(authController));
|
||||
router.post('/change-password', authenticateToken, authController.changePassword.bind(authController));
|
||||
router.get('/validate', authenticateToken, authController.validateToken.bind(authController));
|
||||
router.delete('/account', authenticateToken, authController.deleteAccount.bind(authController));
|
||||
router.post('/google/link-url', authenticateToken, oauthController.createGoogleLinkUrl.bind(oauthController));
|
||||
router.post('/oauth/link-current', authenticateToken, oauthController.linkPendingToCurrentUser.bind(oauthController));
|
||||
router.get('/identities', authenticateToken, oauthController.getIdentities.bind(oauthController));
|
||||
|
||||
@@ -2,6 +2,7 @@ const bcrypt = require('bcrypt');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const crypto = require('crypto');
|
||||
const nodemailer = require('nodemailer');
|
||||
const { Op } = require('sequelize');
|
||||
const database = require('../config/database');
|
||||
|
||||
/**
|
||||
@@ -667,6 +668,86 @@ ${frontendUrl}
|
||||
return true;
|
||||
}
|
||||
|
||||
async destroyOptional(model, where, transaction) {
|
||||
try {
|
||||
return await model.destroy({ where, transaction });
|
||||
} catch (error) {
|
||||
if (error.original?.code === 'ER_NO_SUCH_TABLE') {
|
||||
return 0;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Eigenen Account inkl. personenbezogener Daten löschen.
|
||||
* @param {number} userId - Benutzer-ID
|
||||
* @param {string} confirmation - Muss "ACCOUNT LÖSCHEN" sein
|
||||
* @returns {Promise<boolean>} Erfolg
|
||||
*/
|
||||
async deleteAccount(userId, confirmation) {
|
||||
if (confirmation !== 'ACCOUNT LÖSCHEN') {
|
||||
throw new Error('Bitte bestätigen Sie die Löschung mit "ACCOUNT LÖSCHEN"');
|
||||
}
|
||||
|
||||
const {
|
||||
User,
|
||||
AuthInfo,
|
||||
AuthToken,
|
||||
AuthIdentity,
|
||||
Worklog,
|
||||
Timefix,
|
||||
WeeklyWorktime,
|
||||
Vacation,
|
||||
Sick,
|
||||
Timewish,
|
||||
Invitation,
|
||||
Watcher
|
||||
} = database.getModels();
|
||||
|
||||
return database.sequelize.transaction(async (transaction) => {
|
||||
const user = await User.findByPk(userId, { transaction });
|
||||
if (!user) {
|
||||
throw new Error('Benutzer nicht gefunden');
|
||||
}
|
||||
|
||||
const authInfo = await AuthInfo.findOne({
|
||||
where: { user_id: userId },
|
||||
transaction
|
||||
});
|
||||
|
||||
if (authInfo) {
|
||||
await AuthToken.destroy({ where: { auth_info_id: authInfo.id }, transaction });
|
||||
await AuthIdentity.destroy({ where: { auth_info_id: authInfo.id }, transaction });
|
||||
}
|
||||
|
||||
await this.destroyOptional(Watcher, { user_id: userId }, transaction);
|
||||
await this.destroyOptional(Invitation, { inviter_user_id: userId }, transaction);
|
||||
|
||||
await WeeklyWorktime.destroy({ where: { user_id: userId }, transaction });
|
||||
await Timewish.destroy({ where: { user_id: userId }, transaction });
|
||||
await Vacation.destroy({ where: { user_id: userId }, transaction });
|
||||
await Sick.destroy({ where: { user_id: userId }, transaction });
|
||||
await Timefix.destroy({ where: { user_id: userId }, transaction });
|
||||
|
||||
await Worklog.destroy({
|
||||
where: {
|
||||
user_id: userId,
|
||||
relatedTo_id: { [Op.ne]: null }
|
||||
},
|
||||
transaction
|
||||
});
|
||||
await Worklog.destroy({ where: { user_id: userId }, transaction });
|
||||
|
||||
if (authInfo) {
|
||||
await AuthInfo.destroy({ where: { id: authInfo.id }, transaction });
|
||||
}
|
||||
|
||||
await User.destroy({ where: { id: userId }, transaction });
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Benutzer-Profil abrufen
|
||||
* @param {number} userId - Benutzer-ID
|
||||
@@ -700,4 +781,3 @@ ${frontendUrl}
|
||||
}
|
||||
|
||||
module.exports = new AuthService();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user