edit image business
This commit is contained in:
@@ -92,6 +92,19 @@ export class BusinessImagesService {
|
||||
return saved;
|
||||
}
|
||||
|
||||
async setCover(businessId: string, imageId: string): Promise<BusinessImageEntity> {
|
||||
const image = await this.imageRepo.findOne({
|
||||
where: { id: imageId, businessId },
|
||||
});
|
||||
if (!image) {
|
||||
throw new NotFoundException('Image not found');
|
||||
}
|
||||
|
||||
await this.imageRepo.update({ businessId }, { isCover: false });
|
||||
image.isCover = true;
|
||||
return this.imageRepo.save(image);
|
||||
}
|
||||
|
||||
async remove(businessId: string, imageId: string): Promise<void> {
|
||||
const image = await this.imageRepo.findOne({
|
||||
where: { id: imageId, businessId },
|
||||
|
||||
@@ -22,7 +22,6 @@ import { CurrentUser } from '../auth/decorators/current-user.decorator';
|
||||
import { Roles } from '../auth/decorators/roles.decorator';
|
||||
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
|
||||
import { RolesGuard } from '../auth/guards/roles.guard';
|
||||
import { BusinessImagesService } from './business-images.service';
|
||||
import { BusinessesService } from './businesses.service';
|
||||
import { AssignBusinessOwnerDto } from './dto/assign-business-owner.dto';
|
||||
import { CreateBusinessDto } from './dto/create-business.dto';
|
||||
@@ -31,10 +30,7 @@ import { UpdateBusinessDto } from './dto/update-business.dto';
|
||||
|
||||
@Controller('businesses')
|
||||
export class BusinessesController {
|
||||
constructor(
|
||||
private readonly service: BusinessesService,
|
||||
private readonly images: BusinessImagesService,
|
||||
) {}
|
||||
constructor(private readonly service: BusinessesService) {}
|
||||
|
||||
@Get()
|
||||
findAll(
|
||||
@@ -57,6 +53,43 @@ export class BusinessesController {
|
||||
return this.service.findMine(user.id);
|
||||
}
|
||||
|
||||
@Post('mine/images')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles(UserRole.BUSINESS_OWNER)
|
||||
@UseInterceptors(
|
||||
FilesInterceptor('files', 10, {
|
||||
storage: memoryStorage(),
|
||||
limits: { fileSize: 5 * 1024 * 1024 },
|
||||
}),
|
||||
)
|
||||
uploadMyImages(
|
||||
@UploadedFiles() files: Express.Multer.File[],
|
||||
@CurrentUser() user: AuthUser,
|
||||
): Promise<BusinessImageEntity[]> {
|
||||
return this.service.uploadMyImages(files, user);
|
||||
}
|
||||
|
||||
@Delete('mine/images/:imageId')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles(UserRole.BUSINESS_OWNER)
|
||||
async removeMyImage(
|
||||
@Param('imageId') imageId: string,
|
||||
@CurrentUser() user: AuthUser,
|
||||
): Promise<{ success: true }> {
|
||||
await this.service.removeMyImage(imageId, user);
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
@Patch('mine/images/:imageId/cover')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles(UserRole.BUSINESS_OWNER)
|
||||
setMyCoverImage(
|
||||
@Param('imageId') imageId: string,
|
||||
@CurrentUser() user: AuthUser,
|
||||
): Promise<BusinessImageEntity> {
|
||||
return this.service.setMyCoverImage(imageId, user);
|
||||
}
|
||||
|
||||
@Get(':id/availability')
|
||||
getAvailability(@Param('id') id: string) {
|
||||
return this.service.getAvailability(id);
|
||||
@@ -87,7 +120,7 @@ export class BusinessesController {
|
||||
|
||||
@Post(':id/images')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles(UserRole.ADMIN)
|
||||
@Roles(UserRole.ADMIN, UserRole.BUSINESS_OWNER)
|
||||
@UseInterceptors(
|
||||
FilesInterceptor('files', 10, {
|
||||
storage: memoryStorage(),
|
||||
@@ -97,18 +130,20 @@ export class BusinessesController {
|
||||
uploadImages(
|
||||
@Param('id') id: string,
|
||||
@UploadedFiles() files: Express.Multer.File[],
|
||||
@CurrentUser() user: AuthUser,
|
||||
): Promise<BusinessImageEntity[]> {
|
||||
return this.images.upload(id, files);
|
||||
return this.service.uploadImages(id, files, user);
|
||||
}
|
||||
|
||||
@Delete(':id/images/:imageId')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles(UserRole.ADMIN)
|
||||
@Roles(UserRole.ADMIN, UserRole.BUSINESS_OWNER)
|
||||
async removeImage(
|
||||
@Param('id') id: string,
|
||||
@Param('imageId') imageId: string,
|
||||
@CurrentUser() user: AuthUser,
|
||||
): Promise<{ success: true }> {
|
||||
await this.images.remove(id, imageId);
|
||||
await this.service.removeImage(id, imageId, user);
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
|
||||
@@ -70,10 +70,12 @@ export class BusinessesService {
|
||||
async findMine(ownerId: string): Promise<BusinessEntity[]> {
|
||||
const businesses = await this.repo.find({
|
||||
where: { ownerId },
|
||||
relations: { category: true },
|
||||
relations: { category: true, images: true },
|
||||
order: { createdAt: 'DESC' },
|
||||
});
|
||||
await this.attachCoverImages(businesses);
|
||||
for (const business of businesses) {
|
||||
business.images = this.sortImages(business.images ?? []);
|
||||
}
|
||||
return businesses;
|
||||
}
|
||||
|
||||
@@ -85,6 +87,7 @@ export class BusinessesService {
|
||||
if (!business) {
|
||||
throw new NotFoundException('Business not found');
|
||||
}
|
||||
business.images = this.sortImages(business.images ?? []);
|
||||
return business;
|
||||
}
|
||||
|
||||
@@ -282,6 +285,89 @@ export class BusinessesService {
|
||||
return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
async uploadImages(
|
||||
id: string,
|
||||
files: Express.Multer.File[],
|
||||
actor: AuthUser,
|
||||
): Promise<BusinessImageEntity[]> {
|
||||
const business = await this.findOne(id);
|
||||
this.assertCanManageBusiness(business, actor);
|
||||
return this.images.upload(id, files);
|
||||
}
|
||||
|
||||
async uploadMyImages(
|
||||
files: Express.Multer.File[],
|
||||
actor: AuthUser,
|
||||
): Promise<BusinessImageEntity[]> {
|
||||
const business = await this.requireOwnedBusiness(actor);
|
||||
return this.images.upload(business.id, files);
|
||||
}
|
||||
|
||||
async removeImage(
|
||||
id: string,
|
||||
imageId: string,
|
||||
actor: AuthUser,
|
||||
): Promise<void> {
|
||||
const business = await this.findOne(id);
|
||||
this.assertCanManageBusiness(business, actor);
|
||||
await this.images.remove(id, imageId);
|
||||
}
|
||||
|
||||
async removeMyImage(imageId: string, actor: AuthUser): Promise<void> {
|
||||
const business = await this.requireOwnedBusiness(actor);
|
||||
await this.images.remove(business.id, imageId);
|
||||
}
|
||||
|
||||
async setMyCoverImage(
|
||||
imageId: string,
|
||||
actor: AuthUser,
|
||||
): Promise<BusinessImageEntity> {
|
||||
const business = await this.requireOwnedBusiness(actor);
|
||||
return this.images.setCover(business.id, imageId);
|
||||
}
|
||||
|
||||
private async requireOwnedBusiness(actor: AuthUser): Promise<BusinessEntity> {
|
||||
if (actor.role === UserRole.ADMIN) {
|
||||
throw new ForbiddenException('Use admin image endpoints for this account');
|
||||
}
|
||||
if (actor.role !== UserRole.BUSINESS_OWNER) {
|
||||
throw new ForbiddenException('Insufficient role');
|
||||
}
|
||||
|
||||
const business = await this.repo.findOne({
|
||||
where: { ownerId: actor.id },
|
||||
order: { createdAt: 'DESC' },
|
||||
});
|
||||
if (!business) {
|
||||
throw new NotFoundException('No business linked to your account');
|
||||
}
|
||||
return business;
|
||||
}
|
||||
|
||||
private sortImages(images: BusinessImageEntity[]): BusinessImageEntity[] {
|
||||
return [...images].sort((a, b) => {
|
||||
if (a.isCover !== b.isCover) {
|
||||
return a.isCover ? -1 : 1;
|
||||
}
|
||||
return a.sortOrder - b.sortOrder;
|
||||
});
|
||||
}
|
||||
|
||||
private assertCanManageBusiness(
|
||||
business: BusinessEntity,
|
||||
actor?: AuthUser,
|
||||
): void {
|
||||
if (!actor || actor.role === UserRole.ADMIN) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
actor.role !== UserRole.BUSINESS_OWNER ||
|
||||
business.ownerId !== actor.id
|
||||
) {
|
||||
throw new ForbiddenException('You can only manage your own business');
|
||||
}
|
||||
}
|
||||
|
||||
private assertCanManageAvailability(
|
||||
business: BusinessEntity,
|
||||
actor?: AuthUser,
|
||||
|
||||
Reference in New Issue
Block a user