push code ne

This commit is contained in:
2024-10-28 01:08:13 +07:00
parent 571bb93e28
commit eec9fcfeff
20 changed files with 296 additions and 118 deletions

View File

@@ -0,0 +1,8 @@
import { AdminNoteSchema } from './adminnote.schema';
import { Module } from '@nestjs/common';
@Module({
providers: [AdminNoteSchema],
exports: [AdminNoteSchema],
})
export class AdminNoteModule {}

View File

@@ -0,0 +1,89 @@
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 AdminNoteSchema extends PothosSchema {
constructor(
@Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService,
) {
super();
}
@PothosRef()
adminNote() {
return this.builder.prismaObject('AdminNote', {
description: 'An admin note.',
fields: (t) => ({
id: t.exposeID('id', {
description: 'The ID of the admin note.',
}),
content: t.exposeString('content', {
description: 'The content of the admin note.',
}),
notedByUserId: t.exposeString('notedByUserId', {
description: 'The ID of the user who created the admin note.',
}),
notedBy: t.relation('notedBy', {
description: 'The user who created the admin note.',
}),
createdAt: t.expose('createdAt', {
type: 'DateTime',
description: 'The date and time the admin note was created.',
}),
updatedAt: t.expose('updatedAt', {
type: 'DateTime',
description: 'The date and time the admin note was last updated.',
}),
center: t.relation('center', {
description: 'The center the admin note is associated with.',
}),
service: t.relation('service', {
description: 'The service the admin note is associated with.',
}),
serviceId: t.exposeString('serviceId', {
description:
'The ID of the service the admin note is associated with.',
}),
}),
});
}
@Pothos()
init(): void {
this.builder.queryFields((t) => ({
adminNote: t.prismaField({
type: this.adminNote(),
args: this.builder.generator.findUniqueArgs('AdminNote'),
description: 'Retrieve a single admin note by its unique identifier.',
resolve: async (query, root, args, ctx, info) => {
return await this.prisma.adminNote.findUnique({
...query,
where: args.where,
});
},
}),
adminNotes: t.prismaField({
type: [this.adminNote()],
args: this.builder.generator.findManyArgs('AdminNote'),
description: 'Retrieve a list of admin notes.',
resolve: async (query, root, args, ctx, info) => {
return await this.prisma.adminNote.findMany({
...query,
where: args.filter ?? undefined,
orderBy: args.orderBy ?? undefined,
skip: args.skip ?? undefined,
take: args.take ?? undefined,
});
},
}),
}));
}
}

View File

View File

View File

View File

@@ -44,6 +44,9 @@ export class CenterSchema extends PothosSchema {
description: t.exposeString('description', { description: t.exposeString('description', {
description: 'The description of the center.', description: 'The description of the center.',
}), }),
adminNote: t.relation('adminNote', {
description: 'The admin note of the center.',
}),
logoUrl: t.exposeString('logoUrl', { logoUrl: t.exposeString('logoUrl', {
description: 'The URL of the center logo.', description: 'The URL of the center logo.',
}), }),
@@ -68,8 +71,8 @@ export class CenterSchema extends PothosSchema {
chatRoom: t.relation('chatRoom', { chatRoom: t.relation('chatRoom', {
description: 'The chat room associated with the center.', description: 'The chat room associated with the center.',
}), }),
centerStaff: t.relation('centerStaff', { centerMentor: t.relation('centerMentors', {
description: 'The staff members of the center.', description: 'The mentors of the center.',
}), }),
resume: t.relation('resume', { resume: t.relation('resume', {
description: 'The resume of the center.', description: 'The resume of the center.',
@@ -114,8 +117,8 @@ export class CenterSchema extends PothosSchema {
}); });
}, },
}), }),
// get current center of centerstaff by providing userId // get current center of centermentor by providing userId
centerByCenterStaff: t.prismaField({ centerByCenterMentor: t.prismaField({
type: this.center(), type: this.center(),
description: 'Retrieve a single center by its unique identifier.', description: 'Retrieve a single center by its unique identifier.',
args: { args: {
@@ -124,9 +127,9 @@ export class CenterSchema extends PothosSchema {
resolve: async (query, root, args, ctx, info) => { resolve: async (query, root, args, ctx, info) => {
return await this.prisma.center.findFirst({ return await this.prisma.center.findFirst({
where: { where: {
centerStaff: { centerMentors: {
some: { some: {
staffId: args.userId, mentorId: args.userId,
}, },
}, },
}, },
@@ -192,7 +195,7 @@ export class CenterSchema extends PothosSchema {
}), }),
approveOrRejectCenter: t.prismaField({ approveOrRejectCenter: t.prismaField({
type: this.center(), type: this.center(),
description: 'Approve a center and promote centerstaff to staff', description: 'Approve a center and promote centermentor to mentor',
args: { args: {
centerId: t.arg({ centerId: t.arg({
type: 'String', type: 'String',
@@ -218,10 +221,10 @@ export class CenterSchema extends PothosSchema {
if (center.centerStatus !== CenterStatus.PENDING) { if (center.centerStatus !== CenterStatus.PENDING) {
throw new Error('Center is already approved or rejected'); throw new Error('Center is already approved or rejected');
} }
// find center owner and promote to staff // find user and promote to center owner
const centerOwnerId = center.centerOwnerId; const centerOwnerId = center.centerOwnerId;
if (!centerOwnerId) { if (!centerOwnerId) {
throw new Error('Center owner not found'); throw new Error('User not found');
} }
const centerOwner = await prisma.user.findUnique({ const centerOwner = await prisma.user.findUnique({
where: { where: {
@@ -229,7 +232,7 @@ export class CenterSchema extends PothosSchema {
}, },
}); });
if (!centerOwner) { if (!centerOwner) {
throw new Error('Center owner not found'); throw new Error('User not found');
} }
await prisma.user.update({ await prisma.user.update({
where: { where: {

View File

@@ -0,0 +1,8 @@
import { CenterMentorSchema } from './centermentor.schema';
import { Module } from '@nestjs/common';
@Module({
providers: [CenterMentorSchema],
exports: [CenterMentorSchema],
})
export class CenterMentorModule {}

View File

@@ -10,7 +10,7 @@ import { PrismaService } from '../Prisma/prisma.service';
import { MailService } from '../Mail/mail.service'; import { MailService } from '../Mail/mail.service';
import { JwtUtils } from '../common/utils/jwt.utils'; import { JwtUtils } from '../common/utils/jwt.utils';
@Injectable() @Injectable()
export class CenterStaffSchema extends PothosSchema { export class CenterMentorSchema extends PothosSchema {
constructor( constructor(
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
@@ -21,27 +21,30 @@ export class CenterStaffSchema extends PothosSchema {
} }
@PothosRef() @PothosRef()
centerStaff() { centerMentor() {
return this.builder.prismaObject('CenterStaff', { return this.builder.prismaObject('CenterMentor', {
description: 'A staff member of a center.', description: 'A mentor of a center.',
fields: (t) => ({ fields: (t) => ({
staffId: t.exposeID('staffId', { mentorId: t.exposeID('mentorId', {
description: 'The ID of the staff member.', description: 'The ID of the mentor.',
}), }),
centerId: t.exposeID('centerId', { centerId: t.exposeID('centerId', {
description: 'The ID of the center.', description: 'The ID of the center.',
}), }),
staff: t.relation('staff', { isCenterOwner: t.exposeBoolean('isCenterOwner', {
description: 'The staff member.', description: 'Whether the mentor is the center owner.',
}),
mentor: t.relation('mentor', {
description: 'The mentor.',
}), }),
center: t.relation('center', { center: t.relation('center', {
description: 'The center.', description: 'The center.',
}), }),
createdWorkshop: t.relation('createdWorkshop', { createdWorkshop: t.relation('createdWorkshop', {
description: 'The workshops created by the center staff.', description: 'The workshops created by the center mentor.',
}), }),
managedService: t.relation('managedService', { managedService: t.relation('managedService', {
description: 'The managed services of the center staff.', description: 'The managed services of the center mentor.',
}), }),
}), }),
}); });
@@ -50,13 +53,13 @@ export class CenterStaffSchema extends PothosSchema {
@Pothos() @Pothos()
init(): void { init(): void {
this.builder.queryFields((t) => ({ this.builder.queryFields((t) => ({
centerStaff: t.prismaField({ centerMentor: t.prismaField({
description: description:
'Retrieve a list of center staff members with optional filtering, ordering, and pagination.', 'Retrieve a list of center mentors with optional filtering, ordering, and pagination.',
type: [this.centerStaff()], type: [this.centerMentor()],
args: this.builder.generator.findManyArgs('CenterStaff'), args: this.builder.generator.findManyArgs('CenterMentor'),
resolve: async (query, root, args) => { resolve: async (query, root, args) => {
return await this.prisma.centerStaff.findMany({ return await this.prisma.centerMentor.findMany({
...query, ...query,
skip: args.skip ?? undefined, skip: args.skip ?? undefined,
take: args.take ?? 10, take: args.take ?? 10,
@@ -69,38 +72,38 @@ export class CenterStaffSchema extends PothosSchema {
// mutations // mutations
this.builder.mutationFields((t) => ({ this.builder.mutationFields((t) => ({
createCenterStaff: t.prismaField({ createCenterMentor: t.prismaField({
type: this.centerStaff(), type: this.centerMentor(),
description: 'Create a new center staff member.', description: 'Create a new center mentor.',
args: { args: {
data: t.arg({ data: t.arg({
type: this.builder.generator.getCreateInput('CenterStaff'), type: this.builder.generator.getCreateInput('CenterMentor'),
required: true, required: true,
}), }),
}, },
resolve: async (query, root, args) => { resolve: async (query, root, args) => {
return await this.prisma.centerStaff.create({ return await this.prisma.centerMentor.create({
...query, ...query,
data: args.data, data: args.data,
}); });
}, },
}), }),
updateCenterStaff: t.prismaField({ updateCenterMentor: t.prismaField({
type: this.centerStaff(), type: this.centerMentor(),
description: 'Update an existing center staff member.', description: 'Update an existing center mentor.',
args: { args: {
where: t.arg({ where: t.arg({
type: this.builder.generator.getWhereUnique('CenterStaff'), type: this.builder.generator.getWhereUnique('CenterMentor'),
required: true, required: true,
}), }),
data: t.arg({ data: t.arg({
type: this.builder.generator.getUpdateInput('CenterStaff'), type: this.builder.generator.getUpdateInput('CenterMentor'),
required: true, required: true,
}), }),
}, },
resolve: async (query, root, args) => { resolve: async (query, root, args) => {
return await this.prisma.centerStaff.update({ return await this.prisma.centerMentor.update({
...query, ...query,
where: args.where, where: args.where,
data: args.data, data: args.data,
@@ -108,25 +111,25 @@ export class CenterStaffSchema extends PothosSchema {
}, },
}), }),
deleteCenterStaff: t.prismaField({ deleteCenterMentor: t.prismaField({
type: this.centerStaff(), type: this.centerMentor(),
description: 'Delete an existing center staff member.', description: 'Delete an existing center mentor.',
args: { args: {
where: t.arg({ where: t.arg({
type: this.builder.generator.getWhereUnique('CenterStaff'), type: this.builder.generator.getWhereUnique('CenterMentor'),
required: true, required: true,
}), }),
}, },
resolve: async (query, root, args) => { resolve: async (query, root, args) => {
return await this.prisma.centerStaff.delete({ return await this.prisma.centerMentor.delete({
...query, ...query,
where: args.where, where: args.where,
}); });
}, },
}), }),
inviteCenterStaff: t.prismaField({ inviteCenterMentor: t.prismaField({
type: this.centerStaff(), type: this.centerMentor(),
description: 'Invite a new center staff member.', description: 'Invite a new center mentor.',
args: { args: {
email: t.arg({ type: 'String', required: true }), email: t.arg({ type: 'String', required: true }),
}, },
@@ -155,7 +158,7 @@ export class CenterStaffSchema extends PothosSchema {
await this.mailService.sendTemplateEmail( await this.mailService.sendTemplateEmail(
args.email, args.email,
'Invite to center', 'Invite to center',
'StaffInvitation', 'MentorInvitation',
{ {
center_name: center.name, center_name: center.name,
invite_url: inviteUrl, invite_url: inviteUrl,

View File

@@ -1,8 +0,0 @@
import { Module } from '@nestjs/common';
import { CenterStaffSchema } from './centerstaff.schema';
@Module({
providers: [CenterStaffSchema],
exports: [CenterStaffSchema],
})
export class CenterStaffModule {}

View File

@@ -36,8 +36,8 @@ export class ChatroomSchema extends PothosSchema {
centerId: t.exposeID('centerId', { centerId: t.exposeID('centerId', {
description: 'The ID of the center.', description: 'The ID of the center.',
}), }),
centerStaffId: t.exposeID('centerStaffId', { mentorId: t.exposeID('mentorId', {
description: 'The ID of the center staff member.', description: 'The ID of the mentor.',
}), }),
createdAt: t.expose('createdAt', { createdAt: t.expose('createdAt', {
type: 'DateTime', type: 'DateTime',
@@ -52,8 +52,8 @@ export class ChatroomSchema extends PothosSchema {
center: t.relation('center', { center: t.relation('center', {
description: 'The center.', description: 'The center.',
}), }),
centerStaff: t.relation('centerStaff', { mentor: t.relation('mentor', {
description: 'The center staff member.', description: 'The mentor.',
}), }),
meetingRoom: t.relation('meetingRoom', { meetingRoom: t.relation('meetingRoom', {
description: 'The meeting room.', description: 'The meeting room.',

View File

@@ -55,6 +55,10 @@ export interface SchemaBuilderOption {
Input: FileUpload; Input: FileUpload;
Output: FileUpload; Output: FileUpload;
}; };
Int: {
Input: number;
Output: number | bigint | string;
};
}; };
} }

View File

@@ -1,4 +1,5 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Int } from '@nestjs/graphql';
import { import {
type BaseEnum, type BaseEnum,
@@ -33,7 +34,6 @@ const scalarListOps = [
] as const; ] as const;
const JsonFilterOps = ['equals', 'in', 'notIn', 'not'] as const; const JsonFilterOps = ['equals', 'in', 'notIn', 'not'] as const;
const EnumFilterOps = ['equals', 'not'] as const; const EnumFilterOps = ['equals', 'not'] as const;
@Injectable() @Injectable()
export class PrismaCrudGenerator<Types extends SchemaTypes> { export class PrismaCrudGenerator<Types extends SchemaTypes> {
private refCache = new Map< private refCache = new Map<
@@ -67,6 +67,8 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
take: t.field({ take: t.field({
type: 'Int', type: 'Int',
required: false, required: false,
// @ts-expect-error: Int is not a valid default value
defaultValue: 10,
}), }),
skip: t.field({ skip: t.field({
type: 'Int', type: 'Int',

View File

@@ -1,10 +1,11 @@
import { Global, Logger, MiddlewareConsumer, Module } from '@nestjs/common'; import { Global, Logger, MiddlewareConsumer, Module } from '@nestjs/common';
import { AdminNoteModule } from '../AdminNote/adminnote.module';
import { ApolloDriverConfig } from '@nestjs/apollo'; import { ApolloDriverConfig } from '@nestjs/apollo';
import { Builder } from './graphql.builder'; import { Builder } from './graphql.builder';
import { CategoryModule } from '../Category/category.module'; import { CategoryModule } from '../Category/category.module';
import { CenterMentorModule } from '../CenterMentor/centermentor.module';
import { CenterModule } from '../Center/center.module'; import { CenterModule } from '../Center/center.module';
import { CenterStaffModule } from '../CenterStaff/centerstaff.module';
import { ChatroomModule } from '../ChatRoom/chatroom.module'; import { ChatroomModule } from '../ChatRoom/chatroom.module';
import { CommonModule } from '../common/common.module'; import { CommonModule } from '../common/common.module';
import { GraphQLModule } from '@nestjs/graphql'; import { GraphQLModule } from '@nestjs/graphql';
@@ -45,7 +46,7 @@ import { initContextCache } from '@pothos/core';
CenterModule, CenterModule,
ServiceModule, ServiceModule,
ChatroomModule, ChatroomModule,
CenterStaffModule, CenterMentorModule,
ResumeModule, ResumeModule,
WorkshopModule, WorkshopModule,
WorkshopOrganizationModule, WorkshopOrganizationModule,
@@ -63,6 +64,7 @@ import { initContextCache } from '@pothos/core';
UploadedFileModule, UploadedFileModule,
ManagedServiceModule, ManagedServiceModule,
WorkshopMeetingRoomModule, WorkshopMeetingRoomModule,
AdminNoteModule,
PothosModule.forRoot({ PothosModule.forRoot({
builder: { builder: {
inject: [PrismaService], inject: [PrismaService],

View File

@@ -25,14 +25,17 @@ export class ManagedServiceSchema extends PothosSchema {
id: t.exposeID('id', { id: t.exposeID('id', {
description: 'The ID of the managed service.', description: 'The ID of the managed service.',
}), }),
staffId: t.exposeID('staffId', { mentorId: t.exposeID('mentorId', {
description: 'The ID of the staff member.', description: 'The ID of the mentor.',
}), }),
serviceId: t.exposeID('serviceId', { serviceId: t.exposeID('serviceId', {
description: 'The ID of the service.', description: 'The ID of the service.',
}), }),
staff: t.relation('staff', { schedule: t.relation('schedule', {
description: 'The staff member.', description: 'The schedule of the service.',
}),
mentor: t.relation('mentor', {
description: 'The mentor.',
}), }),
service: t.relation('service', { service: t.relation('service', {
description: 'The service.', description: 'The service.',

View File

@@ -44,6 +44,9 @@ export class ServiceSchema extends PothosSchema {
userId: t.exposeID('userId', { userId: t.exposeID('userId', {
description: 'The ID of the user who requested the service.', description: 'The ID of the user who requested the service.',
}), }),
adminNote: t.relation('adminNote', {
description: 'The admin note of the service.',
}),
price: t.exposeFloat('price', { price: t.exposeFloat('price', {
description: 'The price of the service.', description: 'The price of the service.',
}), }),
@@ -257,7 +260,7 @@ export class ServiceSchema extends PothosSchema {
: ServiceStatus.REJECTED, : ServiceStatus.REJECTED,
}, },
}); });
// mail to center owner and staff who requested the service // mail to center owner and mentor who requested the service
const center = await prisma.center.findUnique({ const center = await prisma.center.findUnique({
where: { id: service.centerId }, where: { id: service.centerId },
}); });
@@ -270,11 +273,11 @@ export class ServiceSchema extends PothosSchema {
if (!centerOwner) { if (!centerOwner) {
throw new Error('Center owner not found'); throw new Error('Center owner not found');
} }
const centerStaff = await prisma.centerStaff.findMany({ const centerMentor = await prisma.centerMentor.findMany({
where: { centerId: service.centerId }, where: { centerId: service.centerId },
}); });
const staffEmails = centerStaff.map((staff) => staff.staffId); const mentorEmails = centerMentor.map((mentor) => mentor.mentorId);
const emails = [centerOwner.email, ...staffEmails]; const emails = [centerOwner.email, ...mentorEmails];
for (const email of emails) { for (const email of emails) {
await this.mailService.sendEmail( await this.mailService.sendEmail(
email, email,

View File

@@ -80,15 +80,18 @@ export class UserSchema extends PothosSchema {
customerChatRoom: t.relation('customerChatRoom', { customerChatRoom: t.relation('customerChatRoom', {
description: 'The customer chat room of the user.', description: 'The customer chat room of the user.',
}), }),
centerStaffChatRoom: t.relation('centerStaffChatRoom', { mentorChatRoom: t.relation('mentorChatRoom', {
description: 'The center staff chat room of the user.', description: 'The mentor chat room of the user.',
}), }),
centerStaff: t.relation('centerStaff', { mentor: t.relation('mentor', {
description: 'The center staff of the user.', description: 'The mentor of the user.',
}), }),
workshopSubscription: t.relation('workshopSubscription', { workshopSubscription: t.relation('workshopSubscription', {
description: 'The workshop subscription of the user.', description: 'The workshop subscription of the user.',
}), }),
adminNote: t.relation('adminNote', {
description: 'The admin note of the user.',
}),
}), }),
}); });
} }
@@ -242,7 +245,7 @@ export class UserSchema extends PothosSchema {
await this.mailService.sendTemplateEmail( await this.mailService.sendTemplateEmail(
args.to, args.to,
'Bạn đã được mời làm việc tại Trung tâm băng đĩa lậu hải ngoại', 'Bạn đã được mời làm việc tại Trung tâm băng đĩa lậu hải ngoại',
'StaffInvitation', 'MentorInvitation',
{ {
center_name: 'băng đĩa lậu hải ngoại', center_name: 'băng đĩa lậu hải ngoại',
invite_url: 'https://epess.org', invite_url: 'https://epess.org',

View File

@@ -33,9 +33,8 @@ export class WorkshopSchema extends PothosSchema {
description: t.exposeString('description', { description: t.exposeString('description', {
description: 'The description of the workshop.', description: 'The description of the workshop.',
}), }),
staffId: t.exposeID('staffId', { mentorId: t.exposeID('mentorId', {
description: description: 'The ID of the mentor who is leading the workshop.',
'The ID of the staff member who is leading the workshop.',
}), }),
serviceId: t.exposeID('serviceId', { serviceId: t.exposeID('serviceId', {
description: 'The ID of the service that the workshop is for.', description: 'The ID of the service that the workshop is for.',
@@ -73,8 +72,8 @@ export class WorkshopSchema extends PothosSchema {
subscription: t.relation('subscription', { subscription: t.relation('subscription', {
description: 'The subscription that the workshop is for.', description: 'The subscription that the workshop is for.',
}), }),
staff: t.relation('staff', { mentor: t.relation('mentor', {
description: 'The staff member who is leading the workshop.', description: 'The mentor who is leading the workshop.',
}), }),
meetingRoom: t.relation('workshopMeetingRoom', { meetingRoom: t.relation('workshopMeetingRoom', {
nullable: true, nullable: true,

File diff suppressed because one or more lines are too long