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