update admin

This commit is contained in:
2026-03-09 16:54:41 +03:30
parent 7c076e32f7
commit d1dfcdba99
6 changed files with 49 additions and 91 deletions
+3 -2
View File
@@ -11,9 +11,10 @@ import { AdminController } from './controllers/admin.controller';
import { UtilsModule } from '../utils/utils.module'; import { UtilsModule } from '../utils/utils.module';
import { RestaurantsModule } from '../restaurants/restaurants.module'; import { RestaurantsModule } from '../restaurants/restaurants.module';
import { AdminRole } from './entities/adminRole.entity'; import { AdminRole } from './entities/adminRole.entity';
import { AdminRoleRepository } from './repositories/admin-role.repository';
@Module({ @Module({
providers: [AdminService, AdminRepository], providers: [AdminService, AdminRepository, AdminRoleRepository],
controllers: [AdminController], controllers: [AdminController],
imports: [ imports: [
MikroOrmModule.forFeature([Admin, Role, Permission, RolePermission, AdminRole]), MikroOrmModule.forFeature([Admin, Role, Permission, RolePermission, AdminRole]),
@@ -23,4 +24,4 @@ import { AdminRole } from './entities/adminRole.entity';
], ],
exports: [AdminService, AdminRepository], exports: [AdminService, AdminRepository],
}) })
export class AdminModule {} export class AdminModule { }
@@ -16,24 +16,20 @@ import { CreateMyRestaurantAdminDto } from '../dto/create-my-restaurant-admin.dt
@ApiTags('admin') @ApiTags('admin')
@Controller() @Controller()
export class AdminController { export class AdminController {
constructor(private readonly adminService: AdminService) {} constructor(private readonly adminService: AdminService) { }
@Get('admin/admins') @Get('admin/admins')
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
@Permissions(Permission.MANAGE_ADMINS) @Permissions(Permission.MANAGE_ADMINS)
@ApiOperation({ summary: 'admin' }) getAll(@RestId() restId: string) {
async getAll(@RestId() restId: string) { return this.adminService.findAllByRestaurantId(restId);
const admin = await this.adminService.findAllByRestaurantId(restId);
return admin;
} }
@Get('admin/admins/profile') @Get('admin/admins/profile')
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
@Permissions(Permission.MANAGE_ADMINS) @Permissions(Permission.MANAGE_ADMINS)
@ApiOperation({ summary: 'admin' }) getMe(@AdminId() adminId: string, @RestId() restId: string) {
async getMe(@AdminId() adminId: string, @RestId() restId: string) { return this.adminService.finAdminById(adminId, restId);
const admin = await this.adminService.findById(adminId, restId);
return admin;
} }
@Post('admin/admins') @Post('admin/admins')
@@ -52,18 +48,16 @@ export class AdminController {
@Permissions(Permission.MANAGE_ADMINS) @Permissions(Permission.MANAGE_ADMINS)
@ApiOperation({ summary: 'Update an admin' }) @ApiOperation({ summary: 'Update an admin' })
@ApiParam({ name: 'adminId', description: 'Admin ID' }) @ApiParam({ name: 'adminId', description: 'Admin ID' })
@ApiBody({ type: UpdateAdminDto }) update(@Param('adminId') adminId: string, @Body() dto: UpdateAdminDto,
update(@Param('adminId') adminId: string, @Body() dto: UpdateAdminDto, @RestId() restId: string): Promise<Admin> { @RestId() restId: string) {
return this.adminService.update(adminId, restId, dto); return this.adminService.update(adminId, restId, dto);
} }
@Get('admin/admins/:adminId') @Get('admin/admins/:adminId')
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
@Permissions(Permission.MANAGE_ADMINS) @Permissions(Permission.MANAGE_ADMINS)
@ApiOperation({ summary: 'Get an admin by ID' }) getById(@Param('adminId') adminId: string, @RestId() restId: string) {
@ApiParam({ name: 'id', description: 'Admin ID' }) return this.adminService.finAdminById(adminId, restId);
getById(@Param('adminId') adminId: string, @RestId() restId: string): Promise<Admin | null> {
return this.adminService.findById(adminId, restId);
} }
@Delete('admin/admins/:adminId') @Delete('admin/admins/:adminId')
@@ -71,7 +65,7 @@ export class AdminController {
@Permissions(Permission.MANAGE_ADMINS) @Permissions(Permission.MANAGE_ADMINS)
@ApiOperation({ summary: 'Delete an admin by ID' }) @ApiOperation({ summary: 'Delete an admin by ID' })
@ApiParam({ name: 'id', description: 'Admin ID' }) @ApiParam({ name: 'id', description: 'Admin ID' })
deleteById(@Param('adminId') adminId: string, @RestId() restId: string): Promise<void> { deleteById(@Param('adminId') adminId: string, @RestId() restId: string) {
return this.adminService.remove(adminId, restId); return this.adminService.remove(adminId, restId);
} }
@@ -80,7 +74,7 @@ export class AdminController {
@Get('super-admin/restaurants/:restaurantId/admins') @Get('super-admin/restaurants/:restaurantId/admins')
@ApiOperation({ summary: 'Get admins for a specific restaurant (Super Admin only)' }) @ApiOperation({ summary: 'Get admins for a specific restaurant (Super Admin only)' })
@ApiParam({ name: 'restaurantId', description: 'Restaurant ID' }) @ApiParam({ name: 'restaurantId', description: 'Restaurant ID' })
getAdminForRestaurant(@Param('restaurantId') restaurantId: string): Promise<Admin[]> { getAdminForRestaurant(@Param('restaurantId') restaurantId: string) {
return this.adminService.getAdminsForRestaurantBySuperAdmin(restaurantId); return this.adminService.getAdminsForRestaurantBySuperAdmin(restaurantId);
} }
@@ -104,7 +98,7 @@ export class AdminController {
revokeAdminFromRestaurant( revokeAdminFromRestaurant(
@Param('restaurantId') restaurantId: string, @Param('restaurantId') restaurantId: string,
@Param('adminId') adminId: string, @Param('adminId') adminId: string,
): Promise<void> { ) {
return this.adminService.remove(adminId, restaurantId); return this.adminService.remove(adminId, restaurantId);
} }
} }
@@ -28,6 +28,4 @@ export class Admin extends BaseEntity {
}) })
roles = new Collection<AdminRole>(this); roles = new Collection<AdminRole>(this);
/** Restaurant-specific role (set when fetched in restaurant context, not persisted) */
role?: AdminRole;
} }
+21 -18
View File
@@ -1,44 +1,47 @@
import { ConflictException, Injectable, NotFoundException } from '@nestjs/common'; import { ConflictException, Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@mikro-orm/nestjs';
import { EntityRepository } from '@mikro-orm/core';
import { Admin } from '../entities/admin.entity'; import { Admin } from '../entities/admin.entity';
import { Role } from '../../roles/entities/role.entity'; import { Role } from '../../roles/entities/role.entity';
import { Restaurant } from '../../restaurants/entities/restaurant.entity'; import { Restaurant } from '../../restaurants/entities/restaurant.entity';
import { wrap } from '@mikro-orm/core';
import { EntityManager } from '@mikro-orm/postgresql'; import { EntityManager } from '@mikro-orm/postgresql';
import { CacheService } from '../../utils/cache.service';
import { CreateMyRestaurantAdminDto } from '../dto/create-my-restaurant-admin.dto'; import { CreateMyRestaurantAdminDto } from '../dto/create-my-restaurant-admin.dto';
import { UpdateAdminDto } from '../dto/update-admin.dto'; import { UpdateAdminDto } from '../dto/update-admin.dto';
import { AdminRole } from '../entities/adminRole.entity'; import { AdminRole } from '../entities/adminRole.entity';
import { normalizePhone } from '../../utils/phone.util'; import { normalizePhone } from '../../utils/phone.util';
import { AdminRepository } from '../repositories/admin.repository';
import { AdminRoleRepository } from '../repositories/admin-role.repository';
@Injectable() @Injectable()
export class AdminService { export class AdminService {
constructor( constructor(
@InjectRepository(Admin) private readonly adminRepository: AdminRepository,
private readonly adminRepository: EntityRepository<Admin>, private readonly adminRoleRepository: AdminRoleRepository,
@InjectRepository(AdminRole)
private readonly adminRoleRepository: EntityRepository<AdminRole>,
private readonly em: EntityManager, private readonly em: EntityManager,
private readonly cacheService: CacheService,
) { } ) { }
async findByPhone(phone: string): Promise<Admin | null> { async findByPhone(phone: string) {
const normalizedPhone = normalizePhone(phone); const normalizedPhone = normalizePhone(phone);
return this.adminRepository.findOne({ phone: normalizedPhone }); return this.adminRepository.findOne({ phone: normalizedPhone });
} }
async findById(adminId: string, restId: string): Promise<Admin | null> { async finAdminById(
adminId: string,
restId: string,
) {
const admin = await this.adminRepository.findOne( const admin = await this.adminRepository.findOne(
{ id: adminId, roles: { restaurant: { id: restId } } }, { id: adminId, roles: { restaurant: { id: restId } } },
{ populate: ['roles', 'roles.role', 'roles.restaurant'] }, { populate: ['roles'], exclude: ['roles'] },
); );
if (!admin) return null; if (!admin) {
const adminRole = admin.roles.getItems().find(r => r.restaurant?.id === restId); throw new NotFoundException('Admin not found');
admin.role = adminRole; }
return admin; const adminPlain = wrap(admin).toObject();
const adminRole = await this.adminRoleRepository.findOne({ admin: admin, restaurant: { id: restId } });
return { ...adminPlain, role: adminRole?.role };
} }
async findAllByRestaurantId(restId: string): Promise<Admin[]> { async findAllByRestaurantId(restId: string) {
return this.adminRepository.find({ roles: { restaurant: { id: restId } } }, { populate: ['roles', 'roles.role'] }); return this.adminRepository.find({ roles: { restaurant: { id: restId } } }, { populate: ['roles', 'roles.role'] });
} }
@@ -122,14 +125,14 @@ export class AdminService {
return admin; return admin;
} }
async getAdminsForRestaurantBySuperAdmin(restId: string): Promise<Admin[]> { async getAdminsForRestaurantBySuperAdmin(restId: string) {
const restaurant = await this.em.findOne(Restaurant, { id: restId }); const restaurant = await this.em.findOne(Restaurant, { id: restId });
if (!restaurant) throw new NotFoundException('Restaurant not found'); if (!restaurant) throw new NotFoundException('Restaurant not found');
return this.adminRepository.find({ roles: { restaurant: restaurant } }, { populate: ['roles', 'roles.role'] }); return this.adminRepository.find({ roles: { restaurant: restaurant } }, { populate: ['roles', 'roles.role'] });
} }
async update(adminId: string, restId: string, dto: UpdateAdminDto): Promise<Admin> { async update(adminId: string, restId: string, dto: UpdateAdminDto) {
const admin = await this.adminRepository.findOne( const admin = await this.adminRepository.findOne(
{ id: adminId, roles: { restaurant: { id: restId } } }, { id: adminId, roles: { restaurant: { id: restId } } },
{ populate: ['roles', 'roles.role', 'roles.restaurant'] }, { populate: ['roles', 'roles.role', 'roles.restaurant'] },
@@ -0,0 +1,13 @@
import { EntityManager, EntityRepository } from '@mikro-orm/postgresql';
import { AdminRole } from '../entities/adminRole.entity';
import { Injectable } from '@nestjs/common';
@Injectable()
export class AdminRoleRepository extends EntityRepository<AdminRole> {
constructor(
readonly em: EntityManager,
) {
super(em, AdminRole);
}
}
@@ -1,51 +0,0 @@
import type { Admin } from '../entities/admin.entity';
export interface AdminDetailResponse {
id: string;
firstName?: string;
lastName?: string;
phone: string;
role: {
id: string;
name: string;
};
permissions: string[];
restaurant?: {
id: string;
name: string;
slug: string;
};
}
export class AdminDetailTransformer {
static transform(admin: Admin): AdminDetailResponse | null {
if (!admin) {
return null;
}
// Extract role information (prefer restaurant-specific role when set)
const adminRole = admin.role ?? admin.roles.getItems().find(r => r.role);
const role = adminRole?.role;
if (!role) {
return null;
}
return {
id: admin.id,
firstName: admin.firstName,
lastName: admin.lastName,
phone: admin.phone,
role: {
id: role.id,
name: role.name,
},
permissions: role.permissions.getItems().map(p => p.name) || [],
restaurant: {
id: adminRole?.restaurant?.id || role.restaurant?.id || '',
name: adminRole?.restaurant?.name || role.restaurant?.name || '',
slug: adminRole?.restaurant?.slug || role.restaurant?.slug || '',
},
};
}
}
// Extract permissions - ensure collection is loaded if needed