diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index f1c2ffb..6992d0a 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -42,7 +42,7 @@ model AuditLog { model User { id String @id @default(uuid()) - email String @unique + email String username String @unique password String isActive Boolean @default(true) diff --git a/backend/src/modules/auth/auth.controller.ts b/backend/src/modules/auth/auth.controller.ts index 4717bc5..da8af0f 100644 --- a/backend/src/modules/auth/auth.controller.ts +++ b/backend/src/modules/auth/auth.controller.ts @@ -21,8 +21,18 @@ export const authController = { login: async (req: Request, res: Response) => { try { + const { email, password } = req.body + + if (!email || !password) { + return res.status(400).json({ + success: false, + message: 'الرجاء إدخال البريد/اسم المستخدم وكلمة المرور' + }) + } + const result = await authService.login(email, password) + res.status(200).json({ success: true, message: 'تم تسجيل الدخول بنجاح', @@ -94,4 +104,4 @@ export const authController = { }) } } -} +} \ No newline at end of file diff --git a/backend/src/modules/auth/auth.service.ts b/backend/src/modules/auth/auth.service.ts index 1bf8b7c..28a7108 100644 --- a/backend/src/modules/auth/auth.service.ts +++ b/backend/src/modules/auth/auth.service.ts @@ -47,26 +47,60 @@ class AuthService { }; } + async login(email: string, password: string) { - // Find user with employee info and permissions - const user = await prisma.user.findUnique({ - where: { email }, - include: { - employee: { - include: { - position: { - include: { - permissions: true, + const identifier = (email || '').toString().trim(); + const isEmail = identifier.includes('@'); + + let user: any = null; + + if (isEmail) { + // email may be duplicated => use findMany and validate + const users = await prisma.user.findMany({ + where: { email: identifier }, + include: { + employee: { + include: { + position: { + include: { permissions: true }, }, + department: true, }, - department: true, }, }, - }, - }); + }); - if (!user) { - throw new AppError(401, 'بيانات الدخول غير صحيحة - Invalid credentials'); + if (users.length === 0) { + throw new AppError(401, 'بيانات الدخول غير صحيحة - Invalid credentials'); + } + + if (users.length > 1) { + throw new AppError( + 400, + 'هذا البريد مستخدم لأكثر من حساب. الرجاء تسجيل الدخول باسم المستخدم - Email shared, use username' + ); + } + + user = users[0]; + } else { + // username is unique => findUnique OK + user = await prisma.user.findUnique({ + where: { username: identifier }, + include: { + employee: { + include: { + position: { + include: { permissions: true }, + }, + department: true, + }, + }, + }, + }); + + if (!user) { + throw new AppError(401, 'بيانات الدخول غير صحيحة - Invalid credentials'); + } } // Check if user is active @@ -84,7 +118,7 @@ class AuthService { if (!isPasswordValid) { // Increment failed login attempts - const failedAttempts = user.failedLoginAttempts + 1; + const failedAttempts = (user.failedLoginAttempts || 0) + 1; const updateData: any = { failedLoginAttempts: failedAttempts }; // Lock account after 5 failed attempts @@ -276,5 +310,4 @@ class AuthService { } } -export const authService = new AuthService(); - +export const authService = new AuthService(); \ No newline at end of file