tududi/backend/modules/admin/repository.js
Chris 542be2c1e9
Fix bug 366 (#764)
* Optimize DB

* Clean up names

* fixup! Clean up names

* fixup! fixup! Clean up names
2026-01-07 18:18:07 +02:00

188 lines
5.1 KiB
JavaScript

'use strict';
const {
User,
Role,
Area,
Project,
Task,
Tag,
Note,
InboxItem,
TaskEvent,
Action,
Permission,
View,
ApiToken,
Notification,
RecurringCompletion,
sequelize,
} = require('../../models');
class AdminRepository {
/**
* Find all users with basic attributes.
*/
async findAllUsers() {
return User.findAll({
attributes: ['id', 'email', 'name', 'surname', 'created_at'],
});
}
/**
* Find all roles.
*/
async findAllRoles() {
return Role.findAll({
attributes: ['user_id', 'is_admin'],
});
}
/**
* Find user by ID.
*/
async findUserById(id, options = {}) {
return User.findByPk(id, options);
}
/**
* Find user by ID with UID attribute only.
*/
async findUserUidById(id) {
return User.findByPk(id, { attributes: ['uid'] });
}
/**
* Create a user.
*/
async createUser(userData) {
return User.create(userData);
}
/**
* Find or create a role.
*/
async findOrCreateRole(userId, isAdmin) {
return Role.findOrCreate({
where: { user_id: userId },
defaults: { user_id: userId, is_admin: isAdmin },
});
}
/**
* Find role by user ID.
*/
async findRoleByUserId(userId, options = {}) {
return Role.findOne({ where: { user_id: userId }, ...options });
}
/**
* Count roles.
*/
async countRoles() {
return Role.count();
}
/**
* Count admin roles.
*/
async countAdminRoles(options = {}) {
return Role.count({ where: { is_admin: true }, ...options });
}
/**
* Delete a user and all associated data in a transaction.
*/
async deleteUserWithData(userId, requesterId) {
const transaction = await sequelize.transaction();
try {
const user = await User.findByPk(userId, { transaction });
if (!user) {
await transaction.rollback();
return { success: false, error: 'User not found', status: 404 };
}
// Prevent deleting the last remaining admin
const targetRole = await Role.findOne({
where: { user_id: userId },
transaction,
});
if (targetRole?.is_admin) {
const adminCount = await Role.count({
where: { is_admin: true },
transaction,
});
if (adminCount <= 1) {
await transaction.rollback();
return {
success: false,
error: 'Cannot delete the last remaining admin',
status: 400,
};
}
}
// Delete all associated data
await TaskEvent.destroy({
where: { user_id: userId },
transaction,
});
const userTasks = await Task.findAll({
where: { user_id: userId },
attributes: ['id'],
transaction,
});
const taskIds = userTasks.map((t) => t.id);
if (taskIds.length > 0) {
await RecurringCompletion.destroy({
where: { task_id: taskIds },
transaction,
});
}
await Task.destroy({ where: { user_id: userId }, transaction });
await Note.destroy({ where: { user_id: userId }, transaction });
await Project.destroy({ where: { user_id: userId }, transaction });
await Area.destroy({ where: { user_id: userId }, transaction });
await Tag.destroy({ where: { user_id: userId }, transaction });
await InboxItem.destroy({
where: { user_id: userId },
transaction,
});
await View.destroy({ where: { user_id: userId }, transaction });
await Notification.destroy({
where: { user_id: userId },
transaction,
});
await ApiToken.destroy({ where: { user_id: userId }, transaction });
await Permission.destroy({
where: { user_id: userId },
transaction,
});
await Permission.destroy({
where: { granted_by_user_id: userId },
transaction,
});
await Action.destroy({
where: { actor_user_id: userId },
transaction,
});
await Action.destroy({
where: { target_user_id: userId },
transaction,
});
await Role.destroy({ where: { user_id: userId }, transaction });
await user.destroy({ transaction });
await transaction.commit();
return { success: true };
} catch (error) {
await transaction.rollback();
throw error;
}
}
}
module.exports = new AdminRepository();