Picsur/backend/src/routes/image/image.controller.ts

115 lines
3.5 KiB
TypeScript
Raw Normal View History

2022-02-21 21:17:44 +00:00
import {
2022-04-04 08:36:59 +00:00
Controller,
Get,
2022-04-16 14:35:28 +00:00
Head,
2022-04-04 08:36:59 +00:00
InternalServerErrorException,
Logger,
2022-06-05 10:16:31 +00:00
NotFoundException,
Query,
2022-06-27 14:46:11 +00:00
Res
2022-02-21 21:17:44 +00:00
} from '@nestjs/common';
2022-06-05 10:16:31 +00:00
import type { FastifyReply } from 'fastify';
2022-04-25 16:07:36 +00:00
import {
ImageMetaResponse,
2022-06-27 14:46:11 +00:00
ImageRequestParams
2022-04-25 16:07:36 +00:00
} from 'picsur-shared/dist/dto/api/image.dto';
2022-02-27 19:27:22 +00:00
import { HasFailed } from 'picsur-shared/dist/types';
2022-05-02 13:03:01 +00:00
import { UsersService } from '../../collections/user-db/user-db.service';
import { ImageFullIdParam } from '../../decorators/image-id/image-full-id.decorator';
2022-04-18 12:34:53 +00:00
import { ImageIdParam } from '../../decorators/image-id/image-id.decorator';
2022-03-12 14:10:22 +00:00
import { RequiredPermissions } from '../../decorators/permissions.decorator';
2022-04-04 08:36:59 +00:00
import { Returns } from '../../decorators/returns.decorator';
2022-04-18 12:34:53 +00:00
import { ImageManagerService } from '../../managers/image/image.service';
2022-06-05 10:16:31 +00:00
import type { ImageFullId } from '../../models/constants/image-full-id.const';
2022-04-18 12:34:53 +00:00
import { Permission } from '../../models/constants/permissions.const';
2022-05-02 13:03:01 +00:00
import { EUserBackend2EUser } from '../../models/transformers/user.transformer';
2022-03-08 09:59:22 +00:00
2022-03-31 20:40:11 +00:00
// This is the only controller with CORS enabled
2022-02-23 10:50:25 +00:00
@Controller('i')
2022-03-12 22:09:46 +00:00
@RequiredPermissions(Permission.ImageView)
2022-02-21 21:36:47 +00:00
export class ImageController {
2022-03-12 14:10:22 +00:00
private readonly logger = new Logger('ImageController');
2022-05-02 13:03:01 +00:00
constructor(
private readonly imagesService: ImageManagerService,
private readonly userService: UsersService,
) {}
2022-02-21 21:17:44 +00:00
2022-08-26 10:38:05 +00:00
@Head(':id')
async headImage(
@Res({ passthrough: true }) res: FastifyReply,
@ImageFullIdParam() fullid: ImageFullId,
) {
if (fullid.type === 'original') {
const fullmime = await this.imagesService.getOriginalMime(fullid.id);
if (HasFailed(fullmime)) {
this.logger.warn(fullmime.getReason());
throw new NotFoundException('Could not find image');
}
res.type(fullmime.mime);
return;
}
res.type(fullid.mime);
}
@Get(':id')
2022-02-21 21:17:44 +00:00
async getImage(
2022-03-28 13:43:52 +00:00
// Usually passthrough is for manually sending the response,
// But we need it here to set the mime type
2022-02-21 21:17:44 +00:00
@Res({ passthrough: true }) res: FastifyReply,
@ImageFullIdParam() fullid: ImageFullId,
2022-05-01 21:29:56 +00:00
@Query() params: ImageRequestParams,
2022-03-12 19:15:48 +00:00
): Promise<Buffer> {
if (fullid.type === 'original') {
const image = await this.imagesService.getOriginal(fullid.id);
if (HasFailed(image)) {
this.logger.warn(image.getReason());
throw new NotFoundException('Could not find image');
}
res.type(image.mime);
return image.data;
}
2022-05-01 21:29:56 +00:00
const image = await this.imagesService.getConverted(
fullid.id,
fullid.mime,
params,
);
2022-03-04 14:28:56 +00:00
if (HasFailed(image)) {
2022-03-12 14:10:22 +00:00
this.logger.warn(image.getReason());
2022-05-01 21:29:56 +00:00
throw new NotFoundException('Failed to get image');
2022-03-04 14:28:56 +00:00
}
2022-02-21 21:17:44 +00:00
res.type(image.mime);
return image.data;
}
@Get('meta/:id')
2022-04-04 08:36:59 +00:00
@Returns(ImageMetaResponse)
2022-04-18 15:28:45 +00:00
async getImageMeta(@ImageIdParam() id: string): Promise<ImageMetaResponse> {
2022-05-03 19:37:20 +00:00
const image = await this.imagesService.findOne(id);
2022-03-04 14:28:56 +00:00
if (HasFailed(image)) {
2022-03-12 14:10:22 +00:00
this.logger.warn(image.getReason());
2022-03-04 14:28:56 +00:00
throw new NotFoundException('Could not find image');
}
2022-05-02 13:03:01 +00:00
const [fileMimes, imageUser] = await Promise.all([
2022-06-27 14:46:11 +00:00
this.imagesService.getFileMimes(id),
2022-05-02 13:03:01 +00:00
this.userService.findOne(image.user_id),
]);
2022-04-25 16:07:36 +00:00
if (HasFailed(fileMimes)) {
this.logger.warn(fileMimes.getReason());
throw new InternalServerErrorException('Could not get image mime');
}
2022-05-02 13:03:01 +00:00
if (HasFailed(imageUser)) {
this.logger.warn(imageUser.getReason());
throw new InternalServerErrorException('Could not get image user');
}
2022-04-25 16:07:36 +00:00
2022-05-02 13:03:01 +00:00
return { image, user: EUserBackend2EUser(imageUser), fileMimes };
}
2022-02-21 21:17:44 +00:00
}