ba me oi con thanh cong roi
This commit is contained in:
@@ -9,12 +9,15 @@ import type PrismaTypes from '../types/pothos.generated';
|
||||
import { getDatamodel } from '../types/pothos.generated';
|
||||
import { DateTimeResolver, JSONObjectResolver } from 'graphql-scalars';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import GraphQLUpload from 'graphql-upload/GraphQLUpload.js';
|
||||
import type { FileUpload } from 'graphql-upload/processRequest.js';
|
||||
import { PrismaCrudGenerator } from './graphql.generator';
|
||||
|
||||
import { PubSub } from 'graphql-subscriptions';
|
||||
export interface SchemaContext {
|
||||
req: Request;
|
||||
res: Response;
|
||||
generator: PrismaCrudGenerator<BuilderTypes>;
|
||||
pubSub: PubSub;
|
||||
}
|
||||
|
||||
export interface SchemaBuilderOption {
|
||||
@@ -30,6 +33,10 @@ export interface SchemaBuilderOption {
|
||||
Input: JSON;
|
||||
Output: JSON;
|
||||
};
|
||||
Upload: {
|
||||
Input: FileUpload;
|
||||
Output: FileUpload;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -51,6 +58,7 @@ export class Builder extends SchemaBuilder<SchemaBuilderOption> {
|
||||
this.generator = new PrismaCrudGenerator<BuilderTypes>(this);
|
||||
this.addScalarType('DateTime', DateTimeResolver);
|
||||
this.addScalarType('Json', JSONObjectResolver);
|
||||
this.addScalarType('Upload', GraphQLUpload);
|
||||
|
||||
this.queryType({});
|
||||
this.mutationType({});
|
||||
|
||||
@@ -13,7 +13,6 @@ import type { FilterOps } from '@pothos/plugin-prisma-utils';
|
||||
import * as Prisma from '@prisma/client';
|
||||
import { SchemaBuilderToken } from '@smatch-corp/nestjs-pothos';
|
||||
|
||||
//
|
||||
const filterOps = ['equals', 'in', 'notIn', 'not', 'is'] as const;
|
||||
const sortableFilterProps = ['lt', 'lte', 'gt', 'gte'] as const;
|
||||
const stringFilterOps = [
|
||||
|
||||
@@ -28,7 +28,7 @@ import { MilestoneModule } from '../Milestone/milestone.module';
|
||||
import { ScheduleModule } from '../Schedule/schedule.module';
|
||||
import { MessageModule } from '../Message/message.module';
|
||||
import { ServiceMeetingRoomModule } from '../ServiceMeetingRoom/servicemeetingroom.module';
|
||||
import { UploadedDocumentModule } from '../UploadedDocument/uploadeddocument.module';
|
||||
import { UploadedFileModule } from '../UploadedFile/uploadedfile.module';
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -53,7 +53,7 @@ import { UploadedDocumentModule } from '../UploadedDocument/uploadeddocument.mod
|
||||
ScheduleModule,
|
||||
MessageModule,
|
||||
ServiceMeetingRoomModule,
|
||||
UploadedDocumentModule,
|
||||
UploadedFileModule,
|
||||
PothosModule.forRoot({
|
||||
builder: {
|
||||
inject: [PrismaService],
|
||||
@@ -65,6 +65,10 @@ import { UploadedDocumentModule } from '../UploadedDocument/uploadeddocument.mod
|
||||
path: process.env.API_PATH + '/graphql',
|
||||
playground: true,
|
||||
introspection: true,
|
||||
installSubscriptionHandlers: true,
|
||||
subscriptions: {
|
||||
'graphql-ws': true,
|
||||
},
|
||||
}),
|
||||
],
|
||||
providers: [
|
||||
|
||||
@@ -59,5 +59,17 @@ export class MessageSchema extends PothosSchema {
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
// mutations
|
||||
|
||||
// subscriptions
|
||||
// this.builder.subscriptionFields((t) => ({
|
||||
// messageSent: t.field({
|
||||
// subscribe: (_parent, _args, ctx) => {
|
||||
// return ctx.pubSub.asyncIterator('MESSAGE_SENT');
|
||||
// },
|
||||
// resolve: (payload) => payload as any,
|
||||
// }),
|
||||
// }));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
import { Module, Global } from '@nestjs/common';
|
||||
|
||||
import { MinioService } from './minio.service';
|
||||
import { NestMinioModule } from 'nestjs-minio';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
@Global()
|
||||
@Module({})
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot(),
|
||||
NestMinioModule.register({
|
||||
endPoint: process.env.MINIO_ENDPOINT ?? '10.0.27.1',
|
||||
accessKey: process.env.MINIO_ACCESS_KEY ?? 'minioadmin',
|
||||
secretKey: process.env.MINIO_SECRET_KEY ?? 'minioadmin',
|
||||
useSSL: false,
|
||||
port: 9000,
|
||||
}),
|
||||
],
|
||||
providers: [MinioService],
|
||||
exports: [MinioService],
|
||||
})
|
||||
export class MinioModule {}
|
||||
|
||||
@@ -1,9 +1,45 @@
|
||||
// import { Injectable } from '@nestjs/common';
|
||||
// import { NestMinioService } from 'nestjs-minio';
|
||||
// import { ConfigService } from '@nestjs/config';
|
||||
// @Injectable()
|
||||
// export class MinioService extends NestMinioService {
|
||||
// constructor(configService: ConfigService) {
|
||||
// super(configService);
|
||||
// }
|
||||
// }
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { FileUpload } from 'graphql-upload/processRequest.js';
|
||||
import { Client } from 'Minio';
|
||||
import { MINIO_CONNECTION } from 'nestjs-minio';
|
||||
@Injectable()
|
||||
export class MinioService {
|
||||
constructor(
|
||||
private readonly configService: ConfigService,
|
||||
@Inject(MINIO_CONNECTION) private readonly minioClient: Client,
|
||||
) {}
|
||||
|
||||
async uploadFile(file: FileUpload, category: string) {
|
||||
const { filename, mimetype, createReadStream, encoding } = await file;
|
||||
const Name = `${category}/${filename}`;
|
||||
const fileBuffer = createReadStream();
|
||||
|
||||
const result = await this.minioClient.putObject(
|
||||
this.configService.get('BUCKET_NAME') ?? 'epess',
|
||||
Name,
|
||||
fileBuffer,
|
||||
undefined,
|
||||
{
|
||||
'Content-Type': mimetype,
|
||||
},
|
||||
);
|
||||
return { result, filename, mimetype };
|
||||
}
|
||||
|
||||
async getFileUrl(fileName: string, category: string) {
|
||||
return await this.minioClient.presignedUrl(
|
||||
'GET',
|
||||
this.configService.get('BUCKET_NAME') ?? 'epess',
|
||||
`${category}/${fileName}`,
|
||||
3600,
|
||||
);
|
||||
}
|
||||
|
||||
async deleteFile(fileName: string) {
|
||||
return await this.minioClient.removeObject(
|
||||
this.configService.get('BUCKET_NAME') ?? 'epess',
|
||||
fileName,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ export class ServiceAndCategorySchema extends PothosSchema {
|
||||
return this.builder.prismaObject('ServiceAndCategory', {
|
||||
fields: (t) => ({
|
||||
serviceId: t.exposeID('serviceId'),
|
||||
categoryId: t.exposeID('categoryId'),
|
||||
service: t.relation('service'),
|
||||
subCategory: t.relation('SubCategory'),
|
||||
subCategoryId: t.exposeID('subCategoryId'),
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Module, Global } from '@nestjs/common';
|
||||
import { UploadedDocumentSchema } from './uploadeddocument.schema';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [UploadedDocumentSchema],
|
||||
exports: [UploadedDocumentSchema],
|
||||
})
|
||||
export class UploadedDocumentModule {}
|
||||
@@ -1,83 +0,0 @@
|
||||
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';
|
||||
|
||||
@Injectable()
|
||||
export class UploadedDocumentSchema extends PothosSchema {
|
||||
constructor(
|
||||
@Inject(SchemaBuilderToken) private readonly builder: Builder,
|
||||
private readonly prisma: PrismaService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
@PothosRef()
|
||||
uploadedDocument() {
|
||||
return this.builder.prismaObject('UploadedDocument', {
|
||||
fields: (t) => ({
|
||||
id: t.exposeID('id'),
|
||||
userId: t.exposeID('userId'),
|
||||
documentName: t.exposeString('documentName'),
|
||||
documentType: t.exposeString('documentType'),
|
||||
status: t.exposeString('status'),
|
||||
type: t.exposeString('type'),
|
||||
documentUrl: t.exposeString('documentUrl'),
|
||||
uploadedAt: t.expose('uploadedAt', { type: 'DateTime' }),
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
@Pothos()
|
||||
init(): void {
|
||||
this.builder.queryFields((t) => ({
|
||||
uploadedDocument: t.prismaField({
|
||||
type: this.uploadedDocument(),
|
||||
args: this.builder.generator.findUniqueArgs('UploadedDocument'),
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
return await this.prisma.uploadedDocument.findUnique({
|
||||
...query,
|
||||
where: args.where,
|
||||
});
|
||||
},
|
||||
}),
|
||||
uploadedDocuments: t.prismaField({
|
||||
type: [this.uploadedDocument()],
|
||||
args: this.builder.generator.findManyArgs('UploadedDocument'),
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
return await this.prisma.uploadedDocument.findMany({
|
||||
...query,
|
||||
skip: args.skip ?? 0,
|
||||
take: args.take ?? 10,
|
||||
orderBy: args.orderBy ?? undefined,
|
||||
where: args.filter ?? undefined,
|
||||
});
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
// Mutations section
|
||||
this.builder.mutationFields((t) => ({
|
||||
createUploadedDocument: t.prismaField({
|
||||
type: this.uploadedDocument(),
|
||||
args: {
|
||||
input: t.arg({
|
||||
type: this.builder.generator.getCreateInput('UploadedDocument'),
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
return await this.prisma.uploadedDocument.create({
|
||||
...query,
|
||||
data: args.input,
|
||||
});
|
||||
},
|
||||
}),
|
||||
}));
|
||||
}
|
||||
}
|
||||
10
src/UploadedFile/uploadedfile.module.ts
Normal file
10
src/UploadedFile/uploadedfile.module.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Module, Global } from '@nestjs/common';
|
||||
import { UploadedFileSchema } from './uploadedfile.schema';
|
||||
import { MinioModule } from '../Minio/minio.module';
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [MinioModule],
|
||||
providers: [UploadedFileSchema],
|
||||
exports: [UploadedFileSchema],
|
||||
})
|
||||
export class UploadedFileModule {}
|
||||
113
src/UploadedFile/uploadedfile.schema.ts
Normal file
113
src/UploadedFile/uploadedfile.schema.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { Inject, Injectable, UploadedFiles } 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';
|
||||
|
||||
@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'),
|
||||
type: t.exposeString('type'),
|
||||
fileUrl: t.exposeString('fileUrl'),
|
||||
uploadedAt: t.expose('uploadedAt', { type: 'DateTime' }),
|
||||
user: t.relation('user'),
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
@Pothos()
|
||||
init(): void {
|
||||
this.builder.queryFields((t) => ({
|
||||
uploadedDocument: t.prismaField({
|
||||
type: this.uploadedFile(),
|
||||
args: this.builder.generator.findUniqueArgs('UploadedFile'),
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
return await this.prisma.uploadedFile.findUnique({
|
||||
...query,
|
||||
where: args.where,
|
||||
});
|
||||
},
|
||||
}),
|
||||
uploadedDocuments: t.prismaField({
|
||||
type: [this.uploadedFile()],
|
||||
args: this.builder.generator.findManyArgs('UploadedFile'),
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
return await this.prisma.uploadedFile.findMany({
|
||||
...query,
|
||||
skip: args.skip ?? 0,
|
||||
take: args.take ?? 10,
|
||||
orderBy: args.orderBy ?? undefined,
|
||||
where: args.filter ?? undefined,
|
||||
});
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
// 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,
|
||||
}),
|
||||
},
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
const user = await this.prisma.user.findUnique({
|
||||
where: {
|
||||
id: args.userId,
|
||||
},
|
||||
});
|
||||
if (!user) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
// convert graphql upload to file
|
||||
// upload file to minio
|
||||
const { filename, mimetype } = await this.minioService.uploadFile(
|
||||
args.file,
|
||||
'files',
|
||||
);
|
||||
// getFileUrl
|
||||
let fileUrl = await this.minioService.getFileUrl(filename, 'files');
|
||||
if (!fileUrl) {
|
||||
fileUrl = '';
|
||||
}
|
||||
const uploadedFile = await this.prisma.uploadedFile.create({
|
||||
data: {
|
||||
userId: user.id,
|
||||
fileName: filename,
|
||||
type: mimetype,
|
||||
fileUrl: fileUrl,
|
||||
uploadedAt: new Date(),
|
||||
},
|
||||
});
|
||||
return uploadedFile;
|
||||
},
|
||||
}),
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.js';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
@@ -40,6 +41,14 @@ async function bootstrap() {
|
||||
},
|
||||
};
|
||||
|
||||
// graphql upload
|
||||
app.use(
|
||||
graphqlUploadExpress({
|
||||
maxFileSize: 100 * 1024 * 1024, // 100 MB
|
||||
maxFiles: 10,
|
||||
}),
|
||||
);
|
||||
|
||||
const port = process.env.LISTEN_PORT ?? 3000; // Default to 3000 if LISTEN_PORT is not set
|
||||
await app.listen(port);
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user