Files
epess-web-backend/src/UploadedFile/uploadedfile.schema.ts
2024-10-17 00:57:33 +07:00

257 lines
7.2 KiB
TypeScript

import { Inject, Injectable } from '@nestjs/common';
import {
Pothos,
PothosRef,
PothosSchema,
SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos';
import { Builder } from '../Graphql/graphql.builder';
import { PrismaService } from '../Prisma/prisma.service';
import { MinioService } from 'src/Minio/minio.service';
import { UploadedFileType } from '@prisma/client';
@Injectable()
export class UploadedFileSchema extends PothosSchema {
constructor(
@Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService,
private readonly minioService: MinioService,
) {
super();
}
@PothosRef()
uploadedFile() {
return this.builder.prismaObject('UploadedFile', {
fields: (t) => ({
id: t.exposeID('id'),
userId: t.exposeID('userId'),
fileName: t.exposeString('fileName'),
// expose enum
fileType: t.expose('fileType', {
type: UploadedFileType,
nullable: false,
}),
fileUrl: t.exposeString('fileUrl'),
uploadedAt: t.expose('uploadedAt', { type: 'DateTime' }),
user: t.relation('user'),
}),
});
}
@Pothos()
init(): void {
this.builder.queryFields((t) => ({
uploadedFile: t.prismaField({
type: this.uploadedFile(),
args: this.builder.generator.findUniqueArgs('UploadedFile'),
resolve: async (query, root, args) => {
const file = await this.prisma.uploadedFile.findUnique({
...query,
where: args.where,
});
if (!file) {
throw new Error('File not found');
}
const fileUrl = await this.minioService.getFileUrl(
file.fileName,
'files',
);
if (!fileUrl) {
throw new Error('Cannot retrieve file url');
}
file.fileUrl = fileUrl;
return file;
},
}),
uploadedFiles: t.prismaField({
type: [this.uploadedFile()],
args: this.builder.generator.findManyArgs('UploadedFile'),
resolve: async (query, root, args) => {
const files = await this.prisma.uploadedFile.findMany({
...query,
skip: args.skip ?? 0,
take: args.take ?? 10,
orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined,
});
const fileUrls = await Promise.all(
files.map((file) =>
this.minioService.getFileUrl(file.fileName, 'files'),
),
);
return files.map((file, index) => ({
...file,
fileUrl: fileUrls[index],
}));
},
}),
}));
// Mutations section
this.builder.mutationFields((t) => ({
singleUpload: t.prismaField({
type: this.uploadedFile(),
args: {
userId: t.arg({
type: 'String',
required: true,
}),
file: t.arg({
type: 'Upload',
required: true,
}),
fileType: t.arg({
type: UploadedFileType,
required: true,
}),
},
resolve: async (query, root, args) => {
const user = await this.prisma.user.findUnique({
where: {
id: args.userId,
},
});
if (!user) {
throw new Error('User not found');
}
const { filename, mimetype } = await this.minioService.uploadFile(
args.file,
'files',
);
if (!mimetype) {
throw new Error('File type not supported');
}
const fileUrl = await this.minioService.getFileUrl(filename, 'files');
if (!fileUrl) {
throw new Error('Cannot retrieve file url, please try again later');
}
const uploadedFile = await this.prisma.uploadedFile.create({
data: {
userId: user.id,
fileName: filename,
type: mimetype,
fileType: args.fileType,
fileUrl: fileUrl,
uploadedAt: new Date(),
},
});
return uploadedFile;
},
}),
multipleUpload: t.prismaField({
type: [this.uploadedFile()],
args: {
userId: t.arg({
type: 'String',
required: true,
}),
files: t.arg({
type: ['Upload'],
required: true,
}),
fileType: t.arg({
type: UploadedFileType,
required: true,
}),
},
resolve: async (query, root, args) => {
const user = await this.prisma.user.findUnique({
where: {
id: args.userId,
},
});
if (!user) {
throw new Error('User not found');
}
const uploadedFiles = await Promise.all(
args.files.map((file) =>
this.minioService.uploadFile(file, 'files'),
),
);
// get file urls
const fileUrls = await Promise.all(
uploadedFiles.map((file) =>
this.minioService.getFileUrl(file.filename, 'files'),
),
);
// map uploadedFiles to db
const dbFiles = uploadedFiles.map((file, index) => ({
userId: user.id,
fileName: file.filename,
type: file.mimetype,
fileType: args.fileType,
fileUrl: fileUrls[index],
uploadedAt: new Date(),
}));
// create files in db
const createdFiles =
await this.prisma.uploadedFile.createManyAndReturn({
data: dbFiles,
});
return createdFiles;
},
}),
deleteUploadedFile: t.prismaField({
type: this.uploadedFile(),
args: {
id: t.arg({
type: 'String',
required: true,
}),
},
resolve: async (query, root, args) => {
const file = await this.prisma.uploadedFile.findUnique({
where: {
id: args.id,
},
});
if (!file) {
throw new Error('File not found');
}
await this.minioService.deleteFile(file.fileName, 'files');
await this.prisma.uploadedFile.delete({
where: {
id: file.id,
},
});
return file;
},
}),
deleteUploadedFiles: t.prismaField({
type: [this.uploadedFile()],
args: {
ids: t.arg({
type: ['String'],
required: true,
}),
},
resolve: async (query, root, args) => {
const files = await this.prisma.uploadedFile.findMany({
where: {
id: {
in: args.ids,
},
},
});
await this.prisma.uploadedFile.deleteMany({
where: {
id: {
in: args.ids,
},
},
});
await Promise.all(
files.map((file) =>
this.minioService.deleteFile(file.fileName, 'files'),
),
);
return files;
},
}),
}));
}
}