AI da dat ten cho dong song
This commit is contained in:
@@ -16,10 +16,12 @@ import { OrderModule } from '../Order/order.module';
|
||||
import { PaymentModule } from '../Payment/payment.module';
|
||||
import { PothosApolloDriver } from '@smatch-corp/nestjs-pothos-apollo-driver';
|
||||
import { PothosModule } from '@smatch-corp/nestjs-pothos';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { PrismaCrudGenerator } from './graphql.generator';
|
||||
import { PrismaModule } from '../Prisma/prisma.module';
|
||||
import { PrismaService } from '../Prisma/prisma.service';
|
||||
import { RefundTicketModule } from '../RefundTicket/refundticket.module';
|
||||
import { Request } from 'express';
|
||||
import { ResumeModule } from '../Resume/resume.module';
|
||||
import { ScheduleModule } from '../Schedule/schedule.module';
|
||||
import { ServiceAndCategoryModule } from '../ServiceAndCategory/serviceandcategory.module';
|
||||
@@ -32,6 +34,7 @@ import { WorkshopMeetingRoomModule } from '../WorkshopMeetingRoom/workshopmeetin
|
||||
import { WorkshopModule } from '../Workshop/workshop.module';
|
||||
import { WorkshopOrganizationModule } from '../WorkshopOrganization/workshoporganization.module';
|
||||
import { WorkshopSubscriptionModule } from '../WorkshopSubscription/workshopsubscription.module';
|
||||
import { initContextCache } from '@pothos/core';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
@@ -76,6 +79,9 @@ import { WorkshopSubscriptionModule } from '../WorkshopSubscription/workshopsubs
|
||||
subscriptions: {
|
||||
'graphql-ws': true,
|
||||
},
|
||||
context: async () => ({
|
||||
...initContextCache(),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
providers: [
|
||||
|
||||
45
src/Mail/mail.module.ts
Normal file
45
src/Mail/mail.module.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import * as path from 'path';
|
||||
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
|
||||
import { MailService } from './mail.service';
|
||||
import { MailerModule } from '@nestjs-modules/mailer';
|
||||
import { OpenaiModule } from '../OpenAI/openai.module';
|
||||
import { PugAdapter } from '@nestjs-modules/mailer/dist/adapters/pug.adapter';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [
|
||||
MailerModule.forRootAsync({
|
||||
useFactory: () => ({
|
||||
transport: {
|
||||
host: process.env.MAILU_HOST,
|
||||
port: parseInt(process.env.MAILU_PORT || '587'),
|
||||
secure: false,
|
||||
pool: true,
|
||||
authMethod: 'login',
|
||||
path: '/',
|
||||
auth: {
|
||||
user: process.env.MAILU_USER,
|
||||
pass: process.env.MAILU_PASSWORD,
|
||||
},
|
||||
verify: true,
|
||||
},
|
||||
defaults: {
|
||||
from: process.env.MAILU_FROM,
|
||||
},
|
||||
// template: {
|
||||
// dir: path.join(__dirname, 'templates'),
|
||||
// adapter: new PugAdapter(),
|
||||
// options: {
|
||||
// strict: true,
|
||||
// },
|
||||
// },
|
||||
}),
|
||||
}),
|
||||
OpenaiModule,
|
||||
],
|
||||
providers: [MailService],
|
||||
exports: [MailService],
|
||||
})
|
||||
export class MailModule {}
|
||||
51
src/Mail/mail.service.ts
Normal file
51
src/Mail/mail.service.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import { MailerService } from '@nestjs-modules/mailer';
|
||||
import { OpenaiService } from '../OpenAI/openai.service';
|
||||
|
||||
@Injectable()
|
||||
export class MailService {
|
||||
constructor(
|
||||
private readonly mailerService: MailerService,
|
||||
private readonly openaiService: OpenaiService,
|
||||
) {}
|
||||
|
||||
async sendEmail(to: string, subject: string, text: string) {
|
||||
try {
|
||||
const mailContent =
|
||||
await this.openaiService.generateInvitationMailContent(
|
||||
to,
|
||||
'John Doe',
|
||||
'https://epess.org',
|
||||
);
|
||||
|
||||
const result = await this.mailerService.sendMail({
|
||||
to,
|
||||
subject,
|
||||
text: mailContent ?? text,
|
||||
});
|
||||
Logger.log(result, 'MailService');
|
||||
} catch (error) {
|
||||
Logger.error(error, 'MailService');
|
||||
}
|
||||
}
|
||||
|
||||
async sendTemplateEmail(
|
||||
to: string,
|
||||
subject: string,
|
||||
template: string,
|
||||
context: any,
|
||||
) {
|
||||
try {
|
||||
const result = await this.mailerService.sendMail({
|
||||
to,
|
||||
subject,
|
||||
template,
|
||||
context,
|
||||
});
|
||||
Logger.log(result, 'MailService');
|
||||
} catch (error) {
|
||||
Logger.error(error, 'MailService');
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/OpenAI/openai.module.ts
Normal file
23
src/OpenAI/openai.module.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ClientOptions, OpenAI } from 'openai';
|
||||
|
||||
import { Module } from '@nestjs/common';
|
||||
import { OpenaiService } from './openai.service';
|
||||
|
||||
const openaiOptions: ClientOptions = {
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
baseURL: process.env.OPENAI_BASE_URL,
|
||||
maxRetries: parseInt(process.env.OPENAI_MAX_RETRIES as string) ?? 3,
|
||||
};
|
||||
|
||||
@Module({
|
||||
imports: [OpenAI],
|
||||
providers: [
|
||||
{
|
||||
provide: OpenAI,
|
||||
useFactory: () => new OpenAI(openaiOptions),
|
||||
},
|
||||
OpenaiService,
|
||||
],
|
||||
exports: [OpenaiService],
|
||||
})
|
||||
export class OpenaiModule {}
|
||||
24
src/OpenAI/openai.service.ts
Normal file
24
src/OpenAI/openai.service.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { OpenAI } from 'openai';
|
||||
|
||||
@Injectable()
|
||||
export class OpenaiService {
|
||||
constructor(private openai: OpenAI) {}
|
||||
|
||||
async generateInvitationMailContent(
|
||||
mail: string,
|
||||
username: string,
|
||||
url: string,
|
||||
) {
|
||||
const prompt = `
|
||||
give me mail content for invitation to a workshop to EPESS and replace {{ mail }} with ${mail}, {{ username }} with ${username} and {{ url }} with ${url}
|
||||
`;
|
||||
|
||||
const response = await this.openai.chat.completions.create({
|
||||
model: 'gpt-4o',
|
||||
messages: [{ role: 'user', content: prompt }],
|
||||
});
|
||||
|
||||
return response.choices[0].message.content;
|
||||
}
|
||||
}
|
||||
@@ -42,11 +42,11 @@ export class PrismaService extends PrismaClient implements OnModuleInit {
|
||||
await this.$connect();
|
||||
break; // Exit loop if connection is successful
|
||||
} catch (error) {
|
||||
if (attempt < 3) {
|
||||
if (attempt < (parseInt(process.env.PRISMA_MAX_RETRY as string) ?? 3)) {
|
||||
this.logger.warn(
|
||||
`Connection attempt ${attempt} failed. Retrying in 5000ms...`,
|
||||
`Connection attempt ${attempt} failed. Retrying in 10000ms...`,
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
await new Promise((resolve) => setTimeout(resolve, 10000));
|
||||
} else {
|
||||
this.logger.error(
|
||||
'Failed to connect to the database after 3 attempts.',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Inject, Injectable, Logger } from '@nestjs/common';
|
||||
import {
|
||||
Pothos,
|
||||
PothosRef,
|
||||
@@ -97,6 +97,31 @@ export class ResumeSchema extends PothosSchema {
|
||||
@Pothos()
|
||||
init(): void {
|
||||
this.builder.queryFields((t) => ({
|
||||
myResumes: t.prismaField({
|
||||
description: 'Retrieve a list of resumes for the current user.',
|
||||
type: [this.resume()],
|
||||
args: {
|
||||
status: t.arg({
|
||||
type: ResumeStatus,
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
try {
|
||||
const resumes = await this.prisma.resume.findMany({
|
||||
...query,
|
||||
where: {
|
||||
userId: ctx.me.id,
|
||||
status: args.status ?? undefined,
|
||||
},
|
||||
});
|
||||
return resumes;
|
||||
} catch (error) {
|
||||
Logger.error(error, 'myResumes');
|
||||
return [];
|
||||
}
|
||||
},
|
||||
}),
|
||||
resumes: t.prismaField({
|
||||
description:
|
||||
'Retrieve a list of resumes with optional filtering, ordering, and pagination.',
|
||||
|
||||
@@ -9,12 +9,13 @@ import { Builder } from '../Graphql/graphql.builder';
|
||||
import { PrismaService } from '../Prisma/prisma.service';
|
||||
import { clerkClient } from '@clerk/express';
|
||||
import { UnauthorizedException } from '@nestjs/common';
|
||||
|
||||
import { MailService } from '../Mail/mail.service';
|
||||
@Injectable()
|
||||
export class UserSchema extends PothosSchema {
|
||||
constructor(
|
||||
@Inject(SchemaBuilderToken) private readonly builder: Builder,
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly mailService: MailService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -123,22 +124,26 @@ export class UserSchema extends PothosSchema {
|
||||
},
|
||||
}),
|
||||
me: t.prismaField({
|
||||
description: 'Retrieve the current user.',
|
||||
description: 'Retrieve the current user by token.',
|
||||
type: this.user(),
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
const sessionCookie = ctx.req.headers.cookie
|
||||
?.split('; ')
|
||||
.find((row) => row.startsWith('__session='))
|
||||
?.split('=')[1];
|
||||
if (!sessionCookie)
|
||||
// get session id from X-Session-Id
|
||||
const sessionId = ctx.req.headers['x-session-id'];
|
||||
if (!sessionId)
|
||||
throw new UnauthorizedException({
|
||||
message: 'No session cookie found',
|
||||
message: 'No session ID found',
|
||||
});
|
||||
const session = await clerkClient.sessions.getSession(sessionCookie);
|
||||
// verify the token
|
||||
const session = await clerkClient.sessions.getSession(
|
||||
sessionId as string,
|
||||
);
|
||||
if (!session) throw new UnauthorizedException();
|
||||
return await this.prisma.user.findUnique({
|
||||
const user = await this.prisma.user.findUnique({
|
||||
where: { id: session.userId },
|
||||
});
|
||||
if (!user) throw new UnauthorizedException();
|
||||
ctx.me = user;
|
||||
return user;
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -227,6 +232,17 @@ export class UserSchema extends PothosSchema {
|
||||
// });
|
||||
// },
|
||||
// }),
|
||||
|
||||
sendEmailTest: t.field({
|
||||
type: 'String',
|
||||
args: {
|
||||
to: t.arg({ type: 'String', required: true }),
|
||||
},
|
||||
resolve: async (_parent, args, _context, _info) => {
|
||||
await this.mailService.sendEmail(args.to, 'Test', 'Test');
|
||||
return 'Email sent';
|
||||
},
|
||||
}),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ClerkModule } from './Clerk/clerk.module';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { GraphqlModule } from './Graphql/graphql.module';
|
||||
import { ClerkModule } from './Clerk/clerk.module';
|
||||
import { MailModule } from './Mail/mail.module';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { RestfulModule } from './Restful/restful.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
}),
|
||||
ClerkModule,
|
||||
MailModule,
|
||||
GraphqlModule,
|
||||
RestfulModule,
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user