feat: Add token-based authorization to category deletion and enhance user registration with error handling and audit logging.

This commit is contained in:
JakkrapartXD 2026-02-12 17:55:45 +07:00
parent 45941fbe6c
commit af14610442
16 changed files with 1003 additions and 236 deletions

View file

@ -83,167 +83,201 @@ export class AuthService {
* User registration
*/
async register(data: RegisterRequest): Promise<RegisterResponse> {
const { username, email, password, first_name, last_name, prefix, phone } = data;
try {
const { username, email, password, first_name, last_name, prefix, phone } = data;
// Check if username already exists
const existingUsername = await prisma.user.findUnique({
where: { username }
});
// Check if username already exists
const existingUsername = await prisma.user.findUnique({
where: { username }
});
if (existingUsername) {
throw new ValidationError('Username already exists');
}
// Check if email already exists
const existingEmail = await prisma.user.findUnique({
where: { email }
});
if (existingEmail) {
throw new ValidationError('Email already exists');
}
// Check if phone number already exists in user profiles
const existingPhone = await prisma.userProfile.findFirst({
where: { phone }
});
if (existingPhone) {
throw new ValidationError('Phone number already exists');
}
// Get STUDENT role
const studentRole = await prisma.role.findUnique({
where: { code: 'STUDENT' }
});
if (!studentRole) {
logger.error('STUDENT role not found in database');
throw new Error('System configuration error');
}
// Hash password
const hashedPassword = await bcrypt.hash(password, 10);
// Create user with profile
const user = await prisma.user.create({
data: {
username,
email,
password: hashedPassword,
role_id: studentRole.id,
profile: {
create: {
prefix: prefix ? prefix as Prisma.InputJsonValue : Prisma.JsonNull,
first_name,
last_name,
phone
}
}
},
include: {
role: true,
profile: true
if (existingUsername) {
throw new ValidationError('Username already exists');
}
});
logger.info('New user registered', { userId: user.id, username: user.username });
// Check if email already exists
const existingEmail = await prisma.user.findUnique({
where: { email }
});
// Audit log - REGISTER (Student)
auditService.log({
userId: user.id,
action: AuditAction.CREATE,
entityType: 'User',
entityId: user.id,
newValue: { username: user.username, email: user.email, role: 'STUDENT' }
});
if (existingEmail) {
throw new ValidationError('Email already exists');
}
return {
user: this.formatUserResponseSync(user),
message: 'Registration successful'
};
// Check if phone number already exists in user profiles
const existingPhone = await prisma.userProfile.findFirst({
where: { phone }
});
if (existingPhone) {
throw new ValidationError('Phone number already exists');
}
// Get STUDENT role
const studentRole = await prisma.role.findUnique({
where: { code: 'STUDENT' }
});
if (!studentRole) {
logger.error('STUDENT role not found in database');
throw new Error('System configuration error');
}
// Hash password
const hashedPassword = await bcrypt.hash(password, 10);
// Create user with profile
const user = await prisma.user.create({
data: {
username,
email,
password: hashedPassword,
role_id: studentRole.id,
profile: {
create: {
prefix: prefix ? prefix as Prisma.InputJsonValue : Prisma.JsonNull,
first_name,
last_name,
phone
}
}
},
include: {
role: true,
profile: true
}
});
logger.info('New user registered', { userId: user.id, username: user.username });
// Audit log - REGISTER (Student)
auditService.log({
userId: user.id,
action: AuditAction.CREATE,
entityType: 'User',
entityId: user.id,
newValue: { username: user.username, email: user.email, role: 'STUDENT' }
});
return {
user: this.formatUserResponseSync(user),
message: 'Registration successful'
};
} catch (error) {
logger.error('Failed to register user', { error });
await auditService.logSync({
userId: 0,
action: AuditAction.ERROR,
entityType: 'User',
entityId: 0,
metadata: {
operation: 'register_user',
email: data.email,
username: data.username,
error: error instanceof Error ? error.message : String(error)
}
});
throw error;
}
}
async registerInstructor(data: RegisterRequest): Promise<RegisterResponse> {
const { username, email, password, first_name, last_name, prefix, phone } = data;
try {
const { username, email, password, first_name, last_name, prefix, phone } = data;
// Check if username already exists
const existingUsername = await prisma.user.findUnique({
where: { username }
});
// Check if username already exists
const existingUsername = await prisma.user.findUnique({
where: { username }
});
if (existingUsername) {
throw new ValidationError('Username already exists');
}
// Check if email already exists
const existingEmail = await prisma.user.findUnique({
where: { email }
});
if (existingEmail) {
throw new ValidationError('Email already exists');
}
// Check if phone number already exists in user profiles
const existingPhone = await prisma.userProfile.findFirst({
where: { phone }
});
if (existingPhone) {
throw new ValidationError('Phone number already exists');
}
// Get INSTRUCTOR role
const instructorRole = await prisma.role.findUnique({
where: { code: 'INSTRUCTOR' }
});
if (!instructorRole) {
logger.error('INSTRUCTOR role not found in database');
throw new Error('System configuration error');
}
// Hash password
const hashedPassword = await bcrypt.hash(password, 10);
// Create user with profile
const user = await prisma.user.create({
data: {
username,
email,
password: hashedPassword,
role_id: instructorRole.id,
profile: {
create: {
prefix: prefix ? prefix as Prisma.InputJsonValue : Prisma.JsonNull,
first_name,
last_name,
phone
}
}
},
include: {
role: true,
profile: true
if (existingUsername) {
throw new ValidationError('Username already exists');
}
});
logger.info('New user registered', { userId: user.id, username: user.username });
// Check if email already exists
const existingEmail = await prisma.user.findUnique({
where: { email }
});
// Audit log - REGISTER (Instructor)
auditService.log({
userId: user.id,
action: AuditAction.CREATE,
entityType: 'User',
entityId: user.id,
newValue: { username: user.username, email: user.email, role: 'INSTRUCTOR' }
});
if (existingEmail) {
throw new ValidationError('Email already exists');
}
return {
user: this.formatUserResponseSync(user),
message: 'Registration successful'
};
// Check if phone number already exists in user profiles
const existingPhone = await prisma.userProfile.findFirst({
where: { phone }
});
if (existingPhone) {
throw new ValidationError('Phone number already exists');
}
// Get INSTRUCTOR role
const instructorRole = await prisma.role.findUnique({
where: { code: 'INSTRUCTOR' }
});
if (!instructorRole) {
logger.error('INSTRUCTOR role not found in database');
throw new Error('System configuration error');
}
// Hash password
const hashedPassword = await bcrypt.hash(password, 10);
// Create user with profile
const user = await prisma.user.create({
data: {
username,
email,
password: hashedPassword,
role_id: instructorRole.id,
profile: {
create: {
prefix: prefix ? prefix as Prisma.InputJsonValue : Prisma.JsonNull,
first_name,
last_name,
phone
}
}
},
include: {
role: true,
profile: true
}
});
logger.info('New user registered', { userId: user.id, username: user.username });
// Audit log - REGISTER (Instructor)
auditService.log({
userId: user.id,
action: AuditAction.CREATE,
entityType: 'User',
entityId: user.id,
newValue: { username: user.username, email: user.email, role: 'INSTRUCTOR' }
});
return {
user: this.formatUserResponseSync(user),
message: 'Registration successful'
};
} catch (error) {
logger.error('Failed to register instructor', { error });
await auditService.logSync({
userId: 0,
action: AuditAction.ERROR,
entityType: 'User',
entityId: 0,
metadata: {
operation: 'register_instructor',
email: data.email,
username: data.username,
error: error instanceof Error ? error.message : String(error)
}
});
throw error;
}
}
/**