Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions backend/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ThrottlerModule } from '@nestjs/throttler';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './modules/auth/auth.module';
import { AdminModule } from './modules/admin/admin.module';
import { AnalyticsModule } from './modules/analytics/analytics.module';
import { ContactModule } from './modules/contact/contact.module';
import { InstagramModule } from './modules/instagram/instagram.module';
import { CloudinaryModule } from './modules/cloudinary/cloudinary.module';

@Module({
imports: [
Expand All @@ -12,6 +19,14 @@ import { AppService } from './app.service';
envFilePath: '.env',
}),

// Rate Limiting
ThrottlerModule.forRoot([
{
ttl: +(process.env.THROTTLE_TTL || 60) * 1000,
limit: +(process.env.THROTTLE_LIMIT || 100),
},
]),

// Database
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
Expand All @@ -33,6 +48,14 @@ import { AppService } from './app.service';
};
},
}),

// Feature Modules
AuthModule,
AdminModule,
AnalyticsModule,
ContactModule,
InstagramModule,
CloudinaryModule,
],
controllers: [AppController],
providers: [AppService],
Expand Down
70 changes: 0 additions & 70 deletions backend/src/harouns-ux/admin-user.entity.ts

This file was deleted.

26 changes: 0 additions & 26 deletions backend/src/harouns-ux/admin-users.module.ts

This file was deleted.

32 changes: 0 additions & 32 deletions backend/src/harouns-ux/auth.module.ts

This file was deleted.

22 changes: 7 additions & 15 deletions backend/src/modules/admin/admin.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class AdminService {

// Prevent creating another SUPER_ADMIN
if (createUserDto.role === AdminRole.SUPER_ADMIN) {
throw new BadRequestException('Cannot create another super admin');
throw new ForbiddenException('Cannot create another super admin');
}

// Check if username already exists in this restaurant
Expand Down Expand Up @@ -86,14 +86,6 @@ export class AdminService {

await this.adminUserRepository.save(user);

// const savedUser = await this.adminUserRepository.save(user);

// // Reload user with restaurant relation to get restaurant details
// const userWithRestaurant = await this.adminUserRepository.findOne({
// where: { id: savedUser.id },
// relations: ['restaurant'],
// });

return {
message: 'User created successfully',
user: {
Expand Down Expand Up @@ -153,12 +145,12 @@ export class AdminService {

// Prevent toggling own status
if (admin.id === requesterId) {
throw new BadRequestException('Cannot toggle your own status');
throw new ForbiddenException('Cannot toggle your own status');
}

// Prevent toggling SUPER_ADMIN status
if (admin.role === AdminRole.SUPER_ADMIN) {
throw new BadRequestException('Cannot toggle super admin status');
throw new ForbiddenException('Cannot toggle super admin status');
}

await this.adminUserRepository.update(adminId, { isActive });
Expand All @@ -185,12 +177,12 @@ export class AdminService {

// Prevent assigning SUPER_ADMIN role
if (role === AdminRole.SUPER_ADMIN) {
throw new BadRequestException('Cannot assign super admin role');
throw new ForbiddenException('Cannot assign super admin role');
}

// Find admin in this restaurant
const admin = await this.adminUserRepository.findOne({
where: { id: adminId, restaurantId }, // ADD restaurantId filter
where: { id: adminId, restaurantId },
});

if (!admin) {
Expand All @@ -199,12 +191,12 @@ export class AdminService {

// Prevent changing SUPER_ADMIN role
if (admin.role === AdminRole.SUPER_ADMIN) {
throw new BadRequestException('Cannot change Super Admin role');
throw new ForbiddenException('Cannot change Super Admin role');
}

// Prevent changing own role
if (admin.id === requesterId) {
throw new BadRequestException('Cannot change your own role');
throw new ForbiddenException('Cannot change your own role');
}

await this.adminUserRepository.update(adminId, { role: role as AdminRole });
Expand Down
3 changes: 3 additions & 0 deletions backend/src/modules/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
HttpStatus,
Patch,
} from '@nestjs/common';
import { Throttle } from '@nestjs/throttler';
import { AuthService } from './auth.service';
import { LoginDto, RegisterAdminDto, ChangePasswordDto } from './auth.dto';
import { JwtAuthGuard } from './jwt-auth.guard';
Expand All @@ -21,12 +22,14 @@ export class AuthController {

@Post('login')
@HttpCode(HttpStatus.OK)
@Throttle({ default: { limit: 5, ttl: 60000 } })
async login(@Body() loginDto: LoginDto) {
return await this.authService.login(loginDto);
}

@Post('register')
@HttpCode(HttpStatus.CREATED)
@Throttle({ default: { limit: 3, ttl: 60000 } })
async register(@Body() registerAdminDto: RegisterAdminDto) {
return await this.authService.register(registerAdminDto);
}
Expand Down
27 changes: 25 additions & 2 deletions backend/src/modules/auth/auth.dto.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,70 @@
// backend/src/modules/auth/auth.dto.ts
import { IsString, IsEmail, MinLength, MaxLength } from 'class-validator';
import {
IsString,
IsEmail,
MinLength,
MaxLength,
Matches,
} from 'class-validator';
import { Transform } from 'class-transformer';

export class LoginDto {
@IsString()
@Transform(({ value }) => value?.trim())
username: string;

@IsString()
@MinLength(6)
@MinLength(8)
@MaxLength(128)
password: string;
}

export class RegisterAdminDto {
@IsString()
@MinLength(3)
@MaxLength(100)
@Matches(/^[a-zA-Z0-9_-]+$/, {
message: 'Username can only contain letters, numbers, hyphens, and underscores',
})
@Transform(({ value }) => value?.trim())
username: string;

@IsEmail()
@Transform(({ value }) => value?.trim().toLowerCase())
email: string;

@IsString()
@MinLength(8)
@MaxLength(128)
password: string;

@IsString()
@MinLength(3)
@MaxLength(255)
@Transform(({ value }) => value?.trim())
restaurantName: string;

@IsString()
@MinLength(10)
@MaxLength(20)
@Matches(/^[0-9+\-() ]+$/, {
message: 'Phone number can only contain digits, +, -, (, ) and spaces',
})
restaurantPhone: string;

@IsEmail()
@Transform(({ value }) => value?.trim().toLowerCase())
restaurantEmail: string;
}

export class ChangePasswordDto {
@IsString()
@MinLength(8)
@MaxLength(128)
currentPassword: string;

@IsString()
@MinLength(8)
@MaxLength(128)
newPassword: string;
}
2 changes: 1 addition & 1 deletion backend/src/modules/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { Restaurant } from '../restaurant/restaurant.entity';
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
secret: configService.get('JWT_SECRET') || 'your-secret-key',
secret: configService.getOrThrow('JWT_SECRET'),
signOptions: {
expiresIn: configService.get('JWT_EXPIRES_IN') || '1d',
},
Expand Down
Loading