enabled context and fix some api
This commit is contained in:
@@ -28,7 +28,7 @@ export class AdminNoteSchema extends PothosSchema {
|
||||
content: t.exposeString('content', {
|
||||
description: 'The content of the admin note.',
|
||||
}),
|
||||
notedByUserId: t.exposeID('notedByUserId', {
|
||||
notedByUserId: t.exposeString('notedByUserId', {
|
||||
description: 'The ID of the user who created the admin note.',
|
||||
}),
|
||||
notedBy: t.relation('notedBy', {
|
||||
|
||||
@@ -9,7 +9,6 @@ import { Builder } from '../Graphql/graphql.builder';
|
||||
import { PrismaService } from '../Prisma/prisma.service';
|
||||
import { MailService } from '../Mail/mail.service';
|
||||
import { JwtUtils } from '../common/utils/jwt.utils';
|
||||
import { UserSchema } from 'src/User/user.schema';
|
||||
@Injectable()
|
||||
export class CenterMentorSchema extends PothosSchema {
|
||||
constructor(
|
||||
@@ -17,7 +16,6 @@ export class CenterMentorSchema extends PothosSchema {
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly mailService: MailService,
|
||||
private readonly jwtUtils: JwtUtils,
|
||||
private readonly userSchema: UserSchema,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -48,7 +46,7 @@ export class CenterMentorSchema extends PothosSchema {
|
||||
managedService: t.relation('managedService', {
|
||||
description: 'The managed services of the center mentor.',
|
||||
}),
|
||||
adminNote: t.relation('AdminNote', {
|
||||
adminNote: t.relation('adminNote', {
|
||||
description: 'The admin note of the center mentor.',
|
||||
}),
|
||||
}),
|
||||
@@ -138,7 +136,7 @@ export class CenterMentorSchema extends PothosSchema {
|
||||
args: {
|
||||
email: t.arg({ type: 'String', required: true }),
|
||||
},
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
resolve: async (query, root, args, ctx) => {
|
||||
return this.prisma.$transaction(async (prisma) => {
|
||||
// get centerId by user id from context
|
||||
const userId = ctx.me.id;
|
||||
@@ -180,8 +178,8 @@ export class CenterMentorSchema extends PothosSchema {
|
||||
centerId: t.arg({ type: 'String', required: true }),
|
||||
},
|
||||
description: 'Test invite center mentor.',
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
return this.prisma.$transaction(async (prisma) => {
|
||||
resolve: async (query, root, args) => {
|
||||
return this.prisma.$transaction(async () => {
|
||||
// sign token
|
||||
const token = this.jwtUtils.signTokenRS256(
|
||||
{ centerId: args.centerId, email: args.email },
|
||||
@@ -204,7 +202,7 @@ export class CenterMentorSchema extends PothosSchema {
|
||||
},
|
||||
}),
|
||||
approveOrRejectCenterMentor: t.prismaField({
|
||||
type: this.userSchema.user(),
|
||||
type: this.centerMentor(),
|
||||
description: 'Approve or reject a center mentor.',
|
||||
args: {
|
||||
where: t.arg({
|
||||
@@ -216,27 +214,104 @@ export class CenterMentorSchema extends PothosSchema {
|
||||
},
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
return this.prisma.$transaction(async (prisma) => {
|
||||
// validate input
|
||||
if (args.approved && !args.adminNote) {
|
||||
throw new Error('Admin note is required');
|
||||
}
|
||||
// get mentor info
|
||||
const mentor = await prisma.user.findUnique({
|
||||
where: args.where,
|
||||
});
|
||||
if (!mentor) {
|
||||
throw new Error('Mentor not found');
|
||||
}
|
||||
// get centerMentor
|
||||
const centerMentor = await prisma.centerMentor.findUnique({
|
||||
where: { mentorId: mentor.id },
|
||||
});
|
||||
if (!centerMentor) {
|
||||
throw new Error('Center mentor not found');
|
||||
}
|
||||
// get center
|
||||
const center = await prisma.center.findUnique({
|
||||
where: { id: centerMentor.centerId },
|
||||
});
|
||||
if (!center) {
|
||||
throw new Error('Center not found');
|
||||
}
|
||||
// get email
|
||||
const email = await prisma.user.findUnique({
|
||||
where: args.where,
|
||||
select: { email: true },
|
||||
});
|
||||
if (!email) {
|
||||
throw new Error('Email is required');
|
||||
}
|
||||
// if approved, update role to mentor
|
||||
if (args.approved) {
|
||||
return await prisma.user.update({
|
||||
// send mail to user
|
||||
await this.mailService.sendTemplateEmail(
|
||||
email.email,
|
||||
'Thông báo về việc được chấp nhận làm mentor',
|
||||
'MentorApproved',
|
||||
{
|
||||
CENTER_NAME: center.name,
|
||||
USER_NAME: mentor.name,
|
||||
},
|
||||
);
|
||||
// create adminNote
|
||||
const adminNote = await prisma.adminNote.create({
|
||||
data: {
|
||||
content: args.adminNote ?? '',
|
||||
mentorId: mentor.id,
|
||||
notedByUserId: ctx.me.id,
|
||||
},
|
||||
});
|
||||
const updatedUser = await prisma.user.update({
|
||||
where: args.where,
|
||||
data: {
|
||||
role: 'CENTER_MENTOR',
|
||||
updatedAt: new Date(),
|
||||
adminNote: {
|
||||
create: {
|
||||
content: args.adminNote ?? '',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
// update centerMentor
|
||||
const updatedCenterMentor = await prisma.centerMentor.update({
|
||||
where: {
|
||||
mentorId_centerId: {
|
||||
mentorId: mentor.id,
|
||||
centerId: centerMentor.centerId,
|
||||
},
|
||||
},
|
||||
data: {
|
||||
adminNote: { connect: { id: adminNote.id } },
|
||||
},
|
||||
});
|
||||
return updatedCenterMentor;
|
||||
}
|
||||
// if rejected, update adminNote
|
||||
return await prisma.user.update({
|
||||
where: args.where,
|
||||
await this.mailService.sendTemplateEmail(
|
||||
email.email,
|
||||
'Thông báo về việc không được chấp nhận làm mentor',
|
||||
'MentorRejected',
|
||||
{
|
||||
CENTER_NAME: center.name,
|
||||
USER_NAME: mentor.name,
|
||||
},
|
||||
);
|
||||
return await prisma.centerMentor.update({
|
||||
where: {
|
||||
mentorId_centerId: {
|
||||
mentorId: mentor.id,
|
||||
centerId: centerMentor.centerId,
|
||||
},
|
||||
},
|
||||
data: {
|
||||
adminNote: {
|
||||
create: { content: args.adminNote ?? '' },
|
||||
create: {
|
||||
content: args.adminNote ?? '',
|
||||
notedByUserId: ctx.me.id,
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Global, Logger, MiddlewareConsumer, Module } from '@nestjs/common';
|
||||
import { Global, MiddlewareConsumer, Module } from '@nestjs/common';
|
||||
|
||||
import { AdminNoteModule } from '../AdminNote/adminnote.module';
|
||||
import { ApolloDriverConfig } from '@nestjs/apollo';
|
||||
@@ -71,19 +71,22 @@ import { initContextCache } from '@pothos/core';
|
||||
useFactory: (prisma: PrismaService) => new Builder(prisma),
|
||||
},
|
||||
}),
|
||||
GraphQLModule.forRoot<ApolloDriverConfig>({
|
||||
GraphQLModule.forRootAsync<ApolloDriverConfig>({
|
||||
driver: PothosApolloDriver,
|
||||
path: process.env.API_PATH + '/graphql',
|
||||
debug: process.env.NODE_ENV === 'development' || false,
|
||||
playground: process.env.NODE_ENV === 'development' || false,
|
||||
introspection: process.env.NODE_ENV === 'development' || false,
|
||||
installSubscriptionHandlers: true,
|
||||
subscriptions: {
|
||||
'graphql-ws': true,
|
||||
},
|
||||
context: async ({ req }: { req: Request }) => ({
|
||||
...initContextCache(),
|
||||
me: await new GraphqlService(new PrismaService()).acquireContext(req),
|
||||
inject: [GraphqlService],
|
||||
useFactory: async (graphqlService: GraphqlService) => ({
|
||||
path: process.env.API_PATH + '/graphql',
|
||||
debug: process.env.NODE_ENV === 'development' || false,
|
||||
playground: process.env.NODE_ENV === 'development' || false,
|
||||
introspection: process.env.NODE_ENV === 'development' || false,
|
||||
installSubscriptionHandlers: true,
|
||||
subscriptions: {
|
||||
'graphql-ws': true,
|
||||
},
|
||||
context: async ({ req }: { req: Request }) => ({
|
||||
...initContextCache(),
|
||||
me: await graphqlService.acquireContext(req),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
@@ -104,7 +107,7 @@ import { initContextCache } from '@pothos/core';
|
||||
inject: [Builder],
|
||||
},
|
||||
],
|
||||
exports: [Builder, PrismaCrudGenerator],
|
||||
exports: [Builder, PrismaCrudGenerator, GraphqlService],
|
||||
})
|
||||
export class GraphqlModule {
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
|
||||
@@ -14,8 +14,8 @@ export class GraphqlService {
|
||||
const disableAuth = process.env.DISABLE_AUTH === 'true';
|
||||
try {
|
||||
sessionId = req.headers['x-session-id'] as string;
|
||||
//eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (error) {
|
||||
Logger.error('Error acquiring context', error);
|
||||
if (disableAuth) {
|
||||
return null;
|
||||
}
|
||||
@@ -35,6 +35,7 @@ export class GraphqlService {
|
||||
if (!user) {
|
||||
throw new UnauthorizedException('User not found');
|
||||
}
|
||||
Logger.log(`User ${user.name} with id ${user.id} acquired context`);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
72
src/Mail/templates/MentorApproved.pug
Normal file
72
src/Mail/templates/MentorApproved.pug
Normal file
@@ -0,0 +1,72 @@
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
meta(charset="UTF-8")
|
||||
title Thông báo phê duyệt Mentor tại Trung tâm #{CENTER_NAME}
|
||||
style.
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f0f8ff;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
background-color: #457D84; /* Medium teal */
|
||||
color: #ffffff;
|
||||
padding: 15px;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
}
|
||||
.content {
|
||||
padding: 20px;
|
||||
color: #333;
|
||||
}
|
||||
.content p {
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 12px 20px;
|
||||
background-color: #2BD4E2; /* Bright aqua */
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
padding: 10px;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
}
|
||||
body
|
||||
.container
|
||||
.header
|
||||
h1 Chúc mừng #{USER_NAME} đã trở thành Mentor tại #{CENTER_NAME}
|
||||
.content
|
||||
p Chào #{USER_NAME},
|
||||
p Chúng tôi vui mừng thông báo rằng bạn đã được phê duyệt trở thành Mentor tại trung tâm #{CENTER_NAME}.
|
||||
p Vui lòng nhấn vào nút dưới đây để truy cập vào trung tâm:
|
||||
a.button(href="https://center.epess.org") Truy cập Trung tâm
|
||||
p Nếu bạn có bất kỳ thắc mắc nào, đừng ngần ngại liên hệ với chúng tôi.
|
||||
.footer
|
||||
p Trân trọng,
|
||||
p EPESS
|
||||
p Nền tảng hỗ trợ viết luận
|
||||
73
src/Mail/templates/MentorRejected.pug
Normal file
73
src/Mail/templates/MentorRejected.pug
Normal file
@@ -0,0 +1,73 @@
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
meta(charset="UTF-8")
|
||||
title Thông báo kết quả ứng tuyển tại Trung tâm #{CENTER_NAME}
|
||||
style.
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f0f8ff;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
background-color: #d9534f; /* Red color for rejection */
|
||||
color: #ffffff;
|
||||
padding: 15px;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
}
|
||||
.content {
|
||||
padding: 20px;
|
||||
color: #333;
|
||||
}
|
||||
.content p {
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 12px 20px;
|
||||
background-color: #2BD4E2; /* Bright aqua */
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
padding: 10px;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
}
|
||||
body
|
||||
.container
|
||||
.header
|
||||
h1 Thông báo kết quả ứng tuyển của #{USER_NAME} tại #{CENTER_NAME}
|
||||
.content
|
||||
p Chào #{USER_NAME},
|
||||
p Chúng tôi rất tiếc thông báo rằng bạn chưa được phê duyệt trở thành Mentor tại trung tâm #{CENTER_NAME} lần này.
|
||||
p Chúng tôi khuyến khích bạn tiếp tục nâng cao kỹ năng và kinh nghiệm, và mong đợi đơn ứng tuyển của bạn trong tương lai.
|
||||
p Bạn có thể truy cập trang web của chúng tôi để biết thêm thông tin:
|
||||
a.button(href="https://center.epess.org") Truy cập Trung tâm
|
||||
p Nếu bạn có bất kỳ thắc mắc nào, đừng ngần ngại liên hệ với chúng tôi.
|
||||
.footer
|
||||
p Trân trọng,
|
||||
p EPESS
|
||||
p Nền tảng hỗ trợ viết luận
|
||||
@@ -14,7 +14,7 @@ export class PrismaService extends PrismaClient implements OnModuleInit {
|
||||
super({
|
||||
log: [
|
||||
{
|
||||
emit: 'stdout',
|
||||
emit: 'event',
|
||||
level: 'query',
|
||||
},
|
||||
{
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user