backend_adaptive_learning/controllers/usersControllers/user.js

657 lines
16 KiB
JavaScript
Raw Normal View History

2024-09-13 13:03:35 +00:00
import response from "../../response.js";
import models from "../../models/index.js";
2024-11-04 04:33:57 +00:00
import bcrypt from "bcryptjs";
2024-09-13 13:03:35 +00:00
import fs from "fs";
import path from "path";
import {
clearFileBuffers,
saveFileToDisk,
} from "../../middlewares/User/uploadUser.js";
export const getUsers = async (req, res) => {
try {
const users = await models.User.findAll({
attributes: {
exclude: ["PASSWORD"],
include: [
[
models.Sequelize.literal(
`COALESCE(\`teachers\`.\`NIP\`, \`students\`.\`NISN\`)`
),
"NIP/NISN",
],
],
},
include: [
{
model: models.Teacher,
as: "teachers",
attributes: [],
},
{
model: models.Student,
as: "students",
attributes: [],
},
],
});
response(200, users, "Success", res);
} catch (error) {
console.log(error);
response(500, null, "Error retrieving users data!", res);
}
};
export const getAdmins = async (req, res) => {
try {
const admins = await models.User.findAll({
where: {
ROLE: "admin",
},
attributes: {
exclude: ["PASSWORD"],
},
});
response(200, admins, "Success", res);
} catch (error) {
console.log(error);
response(500, null, "Error retrieving admin data!", res);
}
};
export const getTeachers = async (req, res) => {
const { page = 1, limit = 10, search = "", sort = "time" } = req.query;
2024-09-13 13:03:35 +00:00
try {
const totalTeachersCount = await models.User.count({
2024-09-13 13:03:35 +00:00
where: {
ROLE: "teacher",
},
});
const { count, rows: teachers } = await models.User.findAndCountAll({
where: {
ROLE: "teacher",
...(search && {
[models.Op.or]: [
{
NAME_USERS: {
[models.Op.like]: `%${search}%`,
},
},
{
EMAIL: {
[models.Op.like]: `%${search}%`,
},
},
{
"$teachers.NIP$": {
[models.Op.like]: `%${search}%`,
},
},
],
}),
},
attributes: ["ID", "NAME_USERS", "EMAIL", "ROLE", "TIME_USERS"],
2024-09-13 13:03:35 +00:00
include: [
{
model: models.Teacher,
as: "teachers",
attributes: ["NIP"],
},
],
distinct: true,
2024-09-13 13:03:35 +00:00
raw: true,
nest: true,
});
const formattedTeachers = teachers.map((teacher) => ({
ID: teacher.ID,
NAME_USERS: teacher.NAME_USERS,
EMAIL: teacher.EMAIL,
NIP: teacher.teachers.NIP,
2024-09-13 13:03:35 +00:00
ROLE: teacher.ROLE,
TIME_USERS: teacher.TIME_USERS,
2024-09-13 13:03:35 +00:00
}));
if (sort === "nip") {
formattedTeachers.sort((a, b) => a.NIP.localeCompare(b.NIP));
} else if (sort === "name") {
formattedTeachers.sort((a, b) =>
a.NAME_USERS.localeCompare(b.NAME_USERS)
);
} else if (sort === "email") {
formattedTeachers.sort((a, b) => a.EMAIL.localeCompare(b.EMAIL));
} else {
formattedTeachers.sort(
(a, b) => new Date(b.TIME_USERS) - new Date(a.TIME_USERS)
);
}
const paginatedTeachers = formattedTeachers.slice(
(page - 1) * limit,
page * limit
);
const totalPages = Math.ceil(count / limit);
const currentPage = parseInt(page);
response(
200,
{
teachers: paginatedTeachers,
currentPage,
totalPages,
totalSearchedItems: count,
totalTeachers: totalTeachersCount,
},
"Teachers retrieved successfully",
res
);
2024-09-13 13:03:35 +00:00
} catch (error) {
console.log(error);
response(500, null, "Error retrieving teacher data!", res);
}
};
export const getStudents = async (req, res) => {
const { page = 1, limit = 10, search = "", sort = "time" } = req.query;
2024-09-13 13:03:35 +00:00
try {
const totalStudentsCount = await models.User.count({
2024-09-13 13:03:35 +00:00
where: {
ROLE: "student",
},
});
const { count, rows: students } = await models.User.findAndCountAll({
where: {
ROLE: "student",
...(search && {
[models.Op.or]: [
{
NAME_USERS: {
[models.Op.like]: `%${search}%`,
},
},
{
EMAIL: {
[models.Op.like]: `%${search}%`,
},
},
{
"$students.NISN$": {
[models.Op.like]: `%${search}%`,
},
},
],
}),
},
attributes: ["ID", "NAME_USERS", "EMAIL", "ROLE", "TIME_USERS"],
2024-09-13 13:03:35 +00:00
include: [
{
model: models.Student,
as: "students",
attributes: ["NISN"],
include: [
{
model: models.Class,
as: "studentClass",
attributes: ["NAME_CLASS"],
},
],
2024-09-13 13:03:35 +00:00
},
],
distinct: true,
2024-09-13 13:03:35 +00:00
raw: true,
nest: true,
});
const formattedStudents = students.map((student) => ({
ID: student.ID,
2024-10-10 03:31:44 +00:00
NISN: student.students.NISN,
2024-09-13 13:03:35 +00:00
NAME_USERS: student.NAME_USERS,
EMAIL: student.EMAIL,
NAME_CLASS: student.students.studentClass.NAME_CLASS,
2024-09-13 13:03:35 +00:00
ROLE: student.ROLE,
TIME_USERS: student.TIME_USERS,
2024-09-13 13:03:35 +00:00
}));
if (sort === "nisn") {
2024-10-23 04:09:33 +00:00
formattedStudents.sort((a, b) =>
String(a.NISN).localeCompare(String(b.NISN))
);
} else if (sort === "name") {
formattedStudents.sort((a, b) =>
a.NAME_USERS.localeCompare(b.NAME_USERS)
);
} else if (sort === "email") {
formattedStudents.sort((a, b) => a.EMAIL.localeCompare(b.EMAIL));
} else {
formattedStudents.sort(
(a, b) => new Date(b.TIME_USERS) - new Date(a.TIME_USERS)
);
}
const paginatedStudents = formattedStudents.slice(
(page - 1) * limit,
page * limit
);
const totalPages = Math.ceil(count / limit);
const currentPage = parseInt(page);
response(
200,
{
students: paginatedStudents,
currentPage,
totalPages,
totalSearchedItems: count,
totalStudents: totalStudentsCount,
},
"Students retrieved successfully",
res
);
2024-09-13 13:03:35 +00:00
} catch (error) {
console.log(error);
response(500, null, "Error retrieving students data!", res);
2024-09-13 13:03:35 +00:00
}
};
export const getUserById = async (req, res) => {
try {
const { id } = req.params;
const userWithDetails = await models.User.findByPk(id, {
2024-09-13 13:03:35 +00:00
attributes: {
exclude: ["PASSWORD"],
},
include: [
{
model: models.Teacher,
as: "teachers",
attributes: ["NIP"],
},
{
model: models.Student,
as: "students",
attributes: ["NISN"],
include: [
{
model: models.Class,
as: "studentClass",
attributes: ["NAME_CLASS"],
},
],
2024-09-13 13:03:35 +00:00
},
],
});
if (!userWithDetails) {
2024-09-13 13:03:35 +00:00
return response(404, null, "User not found", res);
}
let additionalField = null;
if (userWithDetails.ROLE === "teacher") {
additionalField = { NIP: userWithDetails.teachers.NIP };
} else if (userWithDetails.ROLE === "student") {
additionalField = {
NISN: userWithDetails.students.NISN,
NAME_CLASS: userWithDetails.students.studentClass
? userWithDetails.students.studentClass.NAME_CLASS
: null,
};
2024-09-13 13:03:35 +00:00
}
const responseObject = {
ID: userWithDetails.ID,
NAME_USERS: userWithDetails.NAME_USERS,
EMAIL: userWithDetails.EMAIL,
ROLE: userWithDetails.ROLE,
2024-09-13 13:03:35 +00:00
...additionalField,
PICTURE: userWithDetails.PICTURE,
2024-09-13 13:03:35 +00:00
};
response(200, responseObject, "Success", res);
} catch (error) {
console.error(error);
2024-09-13 13:03:35 +00:00
response(500, null, "Error retrieving user data!", res);
}
};
export const getUserByName = async (req, res) => {
try {
const { name } = req.params;
const userWithDetails = await models.User.findOne({
2024-09-13 13:03:35 +00:00
where: { NAME_USERS: name },
attributes: {
exclude: ["PASSWORD"],
},
include: [
{
model: models.Teacher,
as: "teachers",
attributes: ["NIP"],
},
{
model: models.Student,
as: "students",
attributes: ["NISN"],
include: [
{
model: models.Class,
as: "studentClass",
attributes: ["NAME_CLASS"],
},
],
2024-09-13 13:03:35 +00:00
},
],
});
if (!userWithDetails) {
2024-09-13 13:03:35 +00:00
return response(404, null, "User not found", res);
}
let additionalField = null;
if (userWithDetails.ROLE === "teacher") {
additionalField = { NIP: userWithDetails.teachers.NIP };
} else if (userWithDetails.ROLE === "student") {
additionalField = {
NISN: userWithDetails.students.NISN,
NAME_CLASS: userWithDetails.students.studentClass
? userWithDetails.students.studentClass.NAME_CLASS
: null,
};
2024-09-13 13:03:35 +00:00
}
const responseObject = {
ID: userWithDetails.ID,
NAME_USERS: userWithDetails.NAME_USERS,
EMAIL: userWithDetails.EMAIL,
ROLE: userWithDetails.ROLE,
2024-09-13 13:03:35 +00:00
...additionalField,
PICTURE: userWithDetails.PICTURE,
2024-09-13 13:03:35 +00:00
};
response(200, responseObject, "Success", res);
2024-09-13 13:03:35 +00:00
} catch (error) {
console.error(error);
response(500, null, "Error retrieving user data!", res);
2024-09-13 13:03:35 +00:00
}
};
export const updateUserById = async (req, res) => {
const transaction = await models.db.transaction();
const { PICTURE } = req.filesToSave || {};
2024-09-13 13:03:35 +00:00
try {
const { id } = req.params;
const { NAME_USERS, EMAIL, NIP, NISN } = req.body;
2024-09-13 13:03:35 +00:00
const user = await models.User.findByPk(id, {
include: [
{
model: models.Teacher,
as: "teachers",
attributes: ["NIP"],
},
{
model: models.Student,
as: "students",
attributes: ["NISN"],
},
],
transaction,
});
if (!user) {
clearFileBuffers({ PICTURE });
2024-09-13 13:03:35 +00:00
await transaction.rollback();
return response(404, null, "User not found", res);
}
if (user.ROLE === "teacher" && NISN) {
clearFileBuffers({ PICTURE });
2024-09-13 13:03:35 +00:00
await transaction.rollback();
return response(400, null, "Role is teacher, but NISN is provided", res);
}
if (user.ROLE === "student" && NIP) {
clearFileBuffers({ PICTURE });
2024-09-13 13:03:35 +00:00
await transaction.rollback();
return response(400, null, "Role is student, but NIP is provided", res);
}
if (EMAIL && EMAIL !== user.EMAIL) {
2024-09-13 13:03:35 +00:00
const emailExists = await models.User.findOne({
where: { EMAIL: EMAIL },
2024-09-13 13:03:35 +00:00
transaction,
});
if (emailExists) {
clearFileBuffers({ PICTURE });
2024-09-13 13:03:35 +00:00
await transaction.rollback();
return response(400, null, "Email already in use", res);
}
user.EMAIL = EMAIL;
2024-09-13 13:03:35 +00:00
}
user.NAME_USERS = NAME_USERS || user.NAME_USERS;
2024-09-13 13:03:35 +00:00
if (user.ROLE === "teacher" && NIP) {
2024-09-13 13:03:35 +00:00
let teacher = await models.Teacher.findOne({
where: { ID: id },
transaction,
});
if (teacher) {
teacher.NIP = NIP;
2024-09-13 13:03:35 +00:00
await teacher.save({ transaction });
} else {
teacher = await models.Teacher.create(
{ ID: id, NIP: NIP },
2024-09-13 13:03:35 +00:00
{ transaction }
);
}
}
if (user.ROLE === "student" && NISN) {
2024-09-13 13:03:35 +00:00
let student = await models.Student.findOne({
where: { ID: id },
transaction,
});
if (student) {
student.NISN = NISN;
2024-09-13 13:03:35 +00:00
await student.save({ transaction });
} else {
student = await models.Student.create(
{ ID: id, NISN: NISN },
2024-09-13 13:03:35 +00:00
{ transaction }
);
}
}
if (PICTURE) {
2024-09-13 13:03:35 +00:00
if (user.PICTURE) {
const oldPicturePath = path.join("public/uploads/avatar", user.PICTURE);
if (fs.existsSync(oldPicturePath)) {
fs.unlinkSync(oldPicturePath);
}
}
user.PICTURE = saveFileToDisk(PICTURE, user.ID, user.NAME_USERS);
2024-09-13 13:03:35 +00:00
}
await user.save({ transaction });
await user.reload({
include: [
{
model: models.Teacher,
as: "teachers",
attributes: ["NIP"],
},
{
model: models.Student,
as: "students",
attributes: ["NISN"],
},
],
transaction,
});
await transaction.commit();
let userResponse = {
ID: user.ID,
NAME_USERS: user.NAME_USERS,
EMAIL: user.EMAIL,
ROLE: user.ROLE,
PICTURE: user.PICTURE,
};
if (user.ROLE === "student" && user.students) {
userResponse.NISN = user.students.NISN;
} else if (user.ROLE === "teacher" && user.teachers) {
userResponse.NIP = user.teachers.NIP;
}
return response(200, userResponse, "User updated successfully", res);
2024-09-13 13:03:35 +00:00
} catch (error) {
clearFileBuffers({ PICTURE });
2024-09-13 13:03:35 +00:00
await transaction.rollback();
console.log(error);
return response(500, null, "Internal Server Error", res);
}
};
export const updateUserPasswordById = async (req, res) => {
try {
const { id } = req.params;
const { OLD_PASSWORD, PASSWORD, CONFIRM_PASSWORD } = req.body;
2024-09-13 13:03:35 +00:00
if (!OLD_PASSWORD || !PASSWORD || !CONFIRM_PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "All fields must be filled.", res);
}
if (PASSWORD !== CONFIRM_PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(
400,
null,
"New password and confirm password do not match.",
res
);
}
const user = await models.User.findByPk(id);
if (!user) {
return response(404, null, "User not found.", res);
}
const isMatch = await bcrypt.compare(OLD_PASSWORD, user.PASSWORD);
2024-09-13 13:03:35 +00:00
if (!isMatch) {
return response(400, null, "Incorrect old password.", res);
}
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(PASSWORD, salt);
2024-09-13 13:03:35 +00:00
user.PASSWORD = hashedPassword;
await user.save();
response(200, null, "Password updated successfully.", res);
} catch (error) {
response(500, null, "Internal Server Error", res);
}
};
export const deleteUserById = async (req, res) => {
const transaction = await models.db.transaction();
try {
const { id } = req.params;
const user = await models.User.findByPk(id, { transaction });
if (!user) {
await transaction.rollback();
return response(404, null, "User not found", res);
}
if (user.ROLE === "teacher") {
await models.Teacher.destroy({ where: { ID: id }, transaction });
} else if (user.ROLE === "student") {
await models.Student.destroy({ where: { ID: id }, transaction });
}
await user.destroy({ transaction });
await transaction.commit();
return response(200, null, "User deleted successfully", res);
} catch (error) {
await transaction.rollback();
console.log(error);
return response(500, null, "Internal Server Error", res);
}
};
export const getMe = async (req, res) => {
try {
const user = req.user;
2024-09-13 13:03:35 +00:00
const userWithDetails = await models.User.findByPk(user.ID, {
attributes: {
exclude: ["PASSWORD"],
2024-09-13 13:03:35 +00:00
},
include: [
{
model: models.Teacher,
as: "teachers",
attributes: ["NIP"],
2024-09-13 13:03:35 +00:00
},
{
model: models.Student,
as: "students",
attributes: ["NISN"],
include: [
{
model: models.Class,
as: "studentClass",
attributes: ["NAME_CLASS"],
},
],
2024-09-13 13:03:35 +00:00
},
],
});
if (!userWithDetails) {
return response(404, null, "User not found", res);
}
let additionalField = null;
if (userWithDetails.ROLE === "teacher") {
additionalField = { NIP: userWithDetails.teachers.NIP };
} else if (userWithDetails.ROLE === "student") {
additionalField = {
NISN: userWithDetails.students.NISN,
NAME_CLASS: userWithDetails.students.studentClass
? userWithDetails.students.studentClass.NAME_CLASS
: null,
};
2024-09-13 13:03:35 +00:00
}
const responseObject = {
ID: userWithDetails.ID,
NAME_USERS: userWithDetails.NAME_USERS,
EMAIL: userWithDetails.EMAIL,
ROLE: userWithDetails.ROLE,
...additionalField,
PICTURE: userWithDetails.PICTURE,
2024-09-13 13:03:35 +00:00
};
response(200, responseObject, "Success", res);
} catch (error) {
console.error(error);
response(500, null, "Error retrieving user data!", res);
}
};