diff --git a/controllers/auth/auth.js b/controllers/auth/auth.js index 1519b58..9dd5806 100644 --- a/controllers/auth/auth.js +++ b/controllers/auth/auth.js @@ -31,6 +31,15 @@ export const registerAdmin = async (req, res) => { return response(400, null, "Password is required!", res); } + if (PASSWORD.length < 8) { + return response( + 400, + null, + "Password must be at least 8 characters long!", + res + ); + } + if (!CONFIRM_PASSWORD) { return response(400, null, "Confirm Password is required!", res); } @@ -63,6 +72,11 @@ export const registerAdmin = async (req, res) => { } catch (error) { console.log(error); + if (error.name === "SequelizeValidationError") { + const validationErrors = error.errors.map((err) => err.message); + return response(400, null, validationErrors.join("; "), res); + } + if (error.name === "SequelizeUniqueConstraintError") { return response(400, null, "Email already registered!", res); } @@ -90,6 +104,15 @@ export const registerTeacher = async (req, res) => { return response(400, null, "Password is required!", res); } + if (PASSWORD.length < 8) { + return response( + 400, + null, + "Password must be at least 8 characters long!", + res + ); + } + if (!CONFIRM_PASSWORD) { return response(400, null, "Confirm Password is required!", res); } @@ -272,21 +295,31 @@ export const registerTeacher = async (req, res) => { response(200, null, "Teacher registered! Please verify your email.", res); } catch (error) { - console.log(error); await transaction.rollback(); - if (error.name === "SequelizeUniqueConstraintError") { - const field = error.original.sqlMessage.match(/for key '(.+)'/)[1]; + if (error.name === "SequelizeValidationError") { + const validationErrors = error.errors.map((err) => err.message); + return response(400, null, validationErrors.join("; "), res); + } - if (field === "teacher_unique_nip") { + if (error.name === "SequelizeUniqueConstraintError") { + const tableMatch = + error.original.sqlMessage.match(/for key '(.+)\.(.+)'/); + const tableName = tableMatch ? tableMatch[1] : null; + const constraintName = tableMatch ? tableMatch[2] : null; + + if (tableName === "users" && constraintName === "user_unique_email") { + return response(400, null, "Email already registered!", res); + } + + if (tableName === "teacher" && constraintName === "teacher_unique_nip") { return response(400, null, "NIP already registered!", res); } - if (field === "user_unique_email") { - return response(400, null, "Email already registered!", res); - } + return response(400, null, "Unique constraint violation!", res); } + console.error(error); response(500, null, "Internal Server Error", res); } }; @@ -310,6 +343,15 @@ export const registerStudent = async (req, res) => { return response(400, null, "Password is required!", res); } + if (PASSWORD.length < 8) { + return response( + 400, + null, + "Password must be at least 8 characters long!", + res + ); + } + if (!CONFIRM_PASSWORD) { return response(400, null, "Confirm Password is required!", res); } @@ -492,21 +534,31 @@ export const registerStudent = async (req, res) => { response(200, null, "Student registered! Please verify your email.", res); } catch (error) { - console.log(error); await transaction.rollback(); - if (error.name === "SequelizeUniqueConstraintError") { - const field = error.original.sqlMessage.match(/for key '(.+)'/)[1]; + if (error.name === "SequelizeValidationError") { + const validationErrors = error.errors.map((err) => err.message); + return response(400, null, validationErrors.join("; "), res); + } - if (field === "student_unique_nisn") { + if (error.name === "SequelizeUniqueConstraintError") { + const tableMatch = + error.original.sqlMessage.match(/for key '(.+)\.(.+)'/); + const tableName = tableMatch ? tableMatch[1] : null; + const constraintName = tableMatch ? tableMatch[2] : null; + + if (tableName === "users" && constraintName === "user_unique_email") { + return response(400, null, "Email already registered!", res); + } + + if (tableName === "student" && constraintName === "student_unique_nisn") { return response(400, null, "NISN already registered!", res); } - if (field === "user_unique_email") { - return response(400, null, "Email already registered!", res); - } + return response(400, null, "Unique constraint violation!", res); } + console.error(error); response(500, null, "Internal Server Error", res); } }; @@ -545,6 +597,15 @@ export const registerTeacherForAdmin = async (req, res) => { return response(400, null, "Password is required!", res); } + if (PASSWORD.length < 8) { + return response( + 400, + null, + "Password must be at least 8 characters long!", + res + ); + } + if (!CONFIRM_PASSWORD) { return response(400, null, "Confirm Password is required!", res); } @@ -594,16 +655,26 @@ export const registerTeacherForAdmin = async (req, res) => { console.log(error); await transaction.rollback(); - if (error.name === "SequelizeUniqueConstraintError") { - const field = error.original.sqlMessage.match(/for key '(.+)'/)[1]; + if (error.name === "SequelizeValidationError") { + const validationErrors = error.errors.map((err) => err.message); + return response(400, null, validationErrors.join("; "), res); + } - if (field === "teacher_unique_nip") { + if (error.name === "SequelizeUniqueConstraintError") { + const tableMatch = + error.original.sqlMessage.match(/for key '(.+)\.(.+)'/); + const tableName = tableMatch ? tableMatch[1] : null; + const constraintName = tableMatch ? tableMatch[2] : null; + + if (tableName === "users" && constraintName === "user_unique_email") { + return response(400, null, "Email already registered!", res); + } + + if (tableName === "teacher" && constraintName === "teacher_unique_nip") { return response(400, null, "NIP already registered!", res); } - if (field === "user_unique_email") { - return response(400, null, "Email already registered!", res); - } + return response(400, null, "Unique constraint violation!", res); } response(500, null, "Internal Server Error", res); @@ -667,16 +738,26 @@ export const registerStudentForAdminAndTeacher = async (req, res) => { await transaction.rollback(); - if (error.name === "SequelizeUniqueConstraintError") { - const field = error.original.sqlMessage.match(/for key '(.+)'/)[1]; + if (error.name === "SequelizeValidationError") { + const validationErrors = error.errors.map((err) => err.message); + return response(400, null, validationErrors.join("; "), res); + } - if (field === "student_unique_nisn") { + if (error.name === "SequelizeUniqueConstraintError") { + const tableMatch = + error.original.sqlMessage.match(/for key '(.+)\.(.+)'/); + const tableName = tableMatch ? tableMatch[1] : null; + const constraintName = tableMatch ? tableMatch[2] : null; + + if (tableName === "users" && constraintName === "user_unique_email") { + return response(400, null, "Email already registered!", res); + } + + if (tableName === "student" && constraintName === "student_unique_nisn") { return response(400, null, "NISN already registered!", res); } - if (field === "user_unique_email") { - return response(400, null, "Email already registered!", res); - } + return response(400, null, "Unique constraint violation!", res); } response(500, null, "Internal Server Error", res); @@ -844,6 +925,12 @@ export const registerStudentCSV = async (req, res) => { } catch (error) { console.error(error); await transaction.rollback(); + + if (error.name === "SequelizeValidationError") { + const validationErrors = error.errors.map((err) => err.message); + return response(400, null, validationErrors.join("; "), res); + } + response(500, null, "Internal Server Error", res); } }; @@ -1196,6 +1283,15 @@ export const resetPassword = async (req, res) => { return response(400, null, "New password is required!", res); } + if (NEW_PASSWORD.length < 8) { + return response( + 400, + null, + "Password must be at least 8 characters long!", + res + ); + } + if (!CONFIRM_NEW_PASSWORD) { return response(400, null, "Confirm new password is required!", res); } diff --git a/controllers/usersControllers/user.js b/controllers/usersControllers/user.js index 810c1e8..fcaccf6 100644 --- a/controllers/usersControllers/user.js +++ b/controllers/usersControllers/user.js @@ -523,6 +523,32 @@ export const updateUserById = async (req, res) => { } catch (error) { clearFileBuffers({ PICTURE }); await transaction.rollback(); + + if (error.name === "SequelizeValidationError") { + const validationErrors = error.errors.map((err) => err.message); + return response(400, null, validationErrors.join("; "), res); + } + + if (error.name === "SequelizeUniqueConstraintError") { + const tableMatch = + error.original.sqlMessage.match(/for key '(.+)\.(.+)'/); + const tableName = tableMatch ? tableMatch[1] : null; + const constraintName = tableMatch ? tableMatch[2] : null; + + if (tableName === "users" && constraintName === "user_unique_email") { + return response(400, null, "Email already registered!", res); + } + + if (tableName === "student" && constraintName === "student_unique_nisn") { + return response(400, null, "NISN already registered!", res); + } + + if (tableName === "teacher" && constraintName === "teacher_unique_nip") { + return response(400, null, "NIP already registered!", res); + } + + return response(400, null, "Unique constraint violation!", res); + } console.log(error); return response(500, null, "Internal Server Error", res); } @@ -537,6 +563,15 @@ export const updateUserPasswordById = async (req, res) => { return response(400, null, "All fields must be filled.", res); } + if (PASSWORD.length < 8) { + return response( + 400, + null, + "Password must be at least 8 characters long!", + res + ); + } + if (PASSWORD !== CONFIRM_PASSWORD) { return response( 400, diff --git a/models/usersModels/studentModel.js b/models/usersModels/studentModel.js index 03744b7..257bb38 100644 --- a/models/usersModels/studentModel.js +++ b/models/usersModels/studentModel.js @@ -38,6 +38,12 @@ const StudentModel = (DataTypes) => { unique: true, validate: { notEmpty: true, + is10Digits(value) { + const stringValue = value.toString(); + if (stringValue.length !== 10) { + throw new Error("NISN must be exactly 10 digits long"); + } + }, }, }, }, diff --git a/models/usersModels/teacherModel.js b/models/usersModels/teacherModel.js index 0c63c94..d96102d 100644 --- a/models/usersModels/teacherModel.js +++ b/models/usersModels/teacherModel.js @@ -30,6 +30,12 @@ const TeacherModel = (DataTypes) => { unique: true, validate: { notEmpty: true, + is16Digits(value) { + const stringValue = value.toString(); + if (stringValue.length !== 16) { + throw new Error("NIP must be exactly 16 digits long"); + } + }, }, }, }, diff --git a/models/usersModels/userModel.js b/models/usersModels/userModel.js index eaf02c6..1bf27dc 100644 --- a/models/usersModels/userModel.js +++ b/models/usersModels/userModel.js @@ -20,19 +20,28 @@ const UserModel = (DataTypes) => { notEmpty: true, }, }, + PASSWORD: { + type: DataTypes.STRING(100), + allowNull: false, + validate: { + notEmpty: true, + len: { + args: [8, 100], + msg: "Password must be at least 8 characters long", + }, + }, + }, EMAIL: { type: DataTypes.STRING(100), allowNull: false, unique: true, validate: { notEmpty: true, - isEmail: true, + isEmail: { + msg: "Email must be a valid email address", + }, }, }, - PASSWORD: { - type: DataTypes.STRING(100), - allowNull: false, - }, ROLE: { type: DataTypes.STRING(100), allowNull: true,