Files
epess-web-backend/src/UploadedFile/uploadedfile.schema.ts
2024-10-28 02:56:36 +07:00

288 lines
8.7 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', {
description: 'A file uploaded by a user.',
fields: (t) => ({
id: t.exposeID('id', {
description: 'The ID of the uploaded file.',
}),
userId: t.exposeID('userId', {
description: 'The ID of the user who uploaded the file.',
}),
actualFileName: t.exposeString('actualFileName', {
description: 'The original name of the file.',
}),
fileName: t.exposeString('fileName', {
description: 'The name of the file in minio.',
}),
fileType: t.expose('fileType', {
type: UploadedFileType,
nullable: true,
description: 'The type of the file.',
}),
fileUrl: t.exposeString('fileUrl', {
description: 'The URL of the file.',
}),
uploadedAt: t.expose('uploadedAt', {
type: 'DateTime',
nullable: true,
description: 'The date and time the file was uploaded.',
}),
user: t.relation('user', {
description: 'The user who uploaded the file.',
}),
center: t.relation('center', {
description: 'The center that the file belongs to.',
}),
service: t.relation('service', {
description: 'The service that the file belongs to.',
}),
workshop: t.relation('workshop', {
description: 'The workshop that the file belongs to.',
}),
}),
});
}
@Pothos()
init(): void {
this.builder.queryFields((t) => ({
uploadedFile: t.prismaField({
description:
'Retrieve a single uploaded file by its unique identifier.',
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.id, 'files');
if (!fileUrl) {
throw new Error('Cannot retrieve file url');
}
file.fileUrl = fileUrl;
return file;
},
}),
uploadedFiles: t.prismaField({
description:
'Retrieve a list of uploaded files with optional filtering, ordering, and pagination.',
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 ?? undefined,
take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined,
});
const fileUrls = await Promise.all(
files.map((file) => this.minioService.getFileUrl(file.id, 'files')),
);
return files.map((file, index) => ({
...file,
fileUrl: fileUrls[index] ?? '',
}));
},
}),
}));
// Mutations section
this.builder.mutationFields((t) => ({
singleUpload: t.prismaField({
description: 'Upload a single file for a user.',
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, actualFileName } =
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,
actualFileName: actualFileName,
type: mimetype,
fileType: args.fileType,
fileUrl: fileUrl ?? '',
uploadedAt: new Date(),
},
});
return uploadedFile;
},
}),
multipleUpload: t.prismaField({
description: 'Upload multiple files for a user.',
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,
actualFileName: file.actualFileName,
fileUrl: fileUrls[index] ?? '',
uploadedAt: new Date(),
}));
// create files in db
const createdFiles =
await this.prisma.uploadedFile.createManyAndReturn({
data: dbFiles,
});
return createdFiles;
},
}),
deleteUploadedFile: t.prismaField({
description: 'Delete a single uploaded file by its unique identifier.',
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({
description:
'Delete multiple uploaded files by their unique identifiers.',
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;
},
}),
}));
}
}