From 574f92fe7b30a6ea38d9f3447ae1b3ffcf8dd1be Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Tue, 17 Sep 2024 22:59:37 +0530 Subject: [PATCH 01/14] Refactor Mentee entity to include MonthlyCheckIn relationship --- src/entities/checkin.entity.ts | 43 +++++++++++++++++++ src/entities/mentee.entity.ts | 6 ++- .../1726593082689-CreateCheckInTable.ts | 38 ++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/entities/checkin.entity.ts create mode 100644 src/migrations/1726593082689-CreateCheckInTable.ts diff --git a/src/entities/checkin.entity.ts b/src/entities/checkin.entity.ts new file mode 100644 index 00000000..b1baf8a8 --- /dev/null +++ b/src/entities/checkin.entity.ts @@ -0,0 +1,43 @@ +import { Entity, Column, ManyToOne, JoinColumn } from 'typeorm' +import BaseEntity from './baseEntity' +import Mentee from './mentee.entity' + +@Entity('monthly-check-in') +class MonthlyCheckIn extends BaseEntity { + @Column({ type: 'text' }) + generalUpdatesAndFeedback: string + + @Column({ type: 'text' }) + progressTowardsGoals: string + + @Column({ type: 'json' }) + mediaContentLinks: string[] + + @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) + checkInDate: Date + + @ManyToOne(() => Mentee, (mentee) => mentee.checkIns) + @JoinColumn({ name: 'menteeId' }) + mentee: Mentee + + constructor( + generalUpdatesAndFeedback: string, + progressTowardsGoals: string, + mediaContentLinks: string[], + checkInDate: Date, + mentee: Mentee + ) { + super() + this.generalUpdatesAndFeedback = generalUpdatesAndFeedback + this.progressTowardsGoals = progressTowardsGoals + this.mediaContentLinks = mediaContentLinks + this.checkInDate = checkInDate + this.mentee = mentee + } + + validate(): boolean { + return this.mediaContentLinks.length >= 3 + } +} + +export default MonthlyCheckIn diff --git a/src/entities/mentee.entity.ts b/src/entities/mentee.entity.ts index d2d4813d..474a80a9 100644 --- a/src/entities/mentee.entity.ts +++ b/src/entities/mentee.entity.ts @@ -1,9 +1,10 @@ -import { Column, Entity, ManyToOne } from 'typeorm' +import { Column, Entity, ManyToOne, OneToMany } from 'typeorm' import Mentor from './mentor.entity' import profileEntity from './profile.entity' import { MenteeApplicationStatus, StatusUpdatedBy } from '../enums' import BaseEntity from './baseEntity' import { UUID } from 'typeorm/driver/mongodb/bson.typings' +import MonthlyCheckIn from './checkin.entity' @Entity('mentee') class Mentee extends BaseEntity { @@ -35,6 +36,9 @@ class Mentee extends BaseEntity { @ManyToOne(() => Mentor, (mentor) => mentor.mentees) mentor: Mentor + @OneToMany(() => MonthlyCheckIn, (checkIn) => checkIn.mentee) + checkIns!: MonthlyCheckIn[] + constructor( state: MenteeApplicationStatus, application: Record, diff --git a/src/migrations/1726593082689-CreateCheckInTable.ts b/src/migrations/1726593082689-CreateCheckInTable.ts new file mode 100644 index 00000000..8d5c884b --- /dev/null +++ b/src/migrations/1726593082689-CreateCheckInTable.ts @@ -0,0 +1,38 @@ +import { type MigrationInterface, type QueryRunner } from 'typeorm' + +export class CreateCheckInTable1726593082689 implements MigrationInterface { + name = 'CreateCheckInTable1726593082689' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + CREATE TABLE "monthly_check_in" ( + "uuid" uuid PRIMARY KEY DEFAULT uuid_generate_v4(), + "generalUpdatesAndFeedback" text NOT NULL, + "progressTowardsGoals" text NOT NULL, + "mediaContentLinks" json NOT NULL, + "checkInDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "menteeId" uuid NOT NULL, + "created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "FK_monthly_check_in_mentee" FOREIGN KEY ("menteeId") REFERENCES "mentee"("uuid") ON DELETE CASCADE + ) + `) + + // Add index on menteeId for better query performance + await queryRunner.query(` + CREATE INDEX "IDX_monthly_check_in_mentee" ON "monthly_check_in" ("menteeId") + `) + } + + public async down(queryRunner: QueryRunner): Promise { + // Drop the index first + await queryRunner.query(` + DROP INDEX "IDX_monthly_check_in_mentee" + `) + + // Then drop the table + await queryRunner.query(` + DROP TABLE "monthly_check_in" + `) + } +} From a9631d30b18ccdf960aa9dec30bf9cb0cc6b8aef Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Wed, 18 Sep 2024 16:45:23 +0530 Subject: [PATCH 02/14] Refactor Mentee entity to include MonthlyCheckIn relationship --- src/controllers/mentee.controller.ts | 73 +++++++++++++- ...2-RemoveUniqueConstraintFromProfileUuid.ts | 19 +++- .../1726593082689-CreateCheckInTable.ts | 38 -------- .../1726595585135-monthly-checking.ts | 21 ++++ src/routes/mentee/mentee.route.ts | 10 ++ src/schemas/mentee-routes.schemas.ts | 12 +++ src/services/mentee.service.ts | 97 +++++++++++++++++++ 7 files changed, 227 insertions(+), 43 deletions(-) delete mode 100644 src/migrations/1726593082689-CreateCheckInTable.ts create mode 100644 src/migrations/1726595585135-monthly-checking.ts diff --git a/src/controllers/mentee.controller.ts b/src/controllers/mentee.controller.ts index 45b9faa4..b06ca6ef 100644 --- a/src/controllers/mentee.controller.ts +++ b/src/controllers/mentee.controller.ts @@ -8,7 +8,13 @@ import { updateStatus } from '../services/admin/mentee.service' import { MentorApplicationStatus, StatusUpdatedBy } from '../enums' -import { addMentee, getPublicMentee } from '../services/mentee.service' +import { + addMentee, + addMonthlyCheckIn, + fetchMonthlyCheckIns, + getPublicMentee +} from '../services/mentee.service' +import type MonthlyCheckIn from '../entities/checkin.entity' export const menteeApplicationHandler = async ( req: Request, @@ -126,3 +132,68 @@ export const getPublicMenteeDetails = async ( throw err } } + +export const submitMonthlyCheckIn = async ( + req: Request, + res: Response +): Promise => { + try { + const user = req.user as Profile + const { menteeId } = req.params + const checkInData = req.body + + if (user.uuid !== menteeId) { + res.status(403).json({ message: 'Unauthorized' }) + } + + const { statusCode, message } = await addMonthlyCheckIn( + menteeId, + checkInData + ) + res.status(statusCode).json({ message }) + } catch (err) { + if (err instanceof Error) { + console.error('Error executing query', err) + res + .status(500) + .json({ error: 'Internal server error', message: err.message }) + return + } + throw err + } +} + +export const getMonthlyCheckIns = async ( + req: Request, + res: Response +): Promise>> => { + try { + const user = req.user as Profile + const { menteeId } = req.params + + const isMentee = user.uuid === menteeId + const isMentor = user.mentor?.some( + (mentor) => + mentor.state === MentorApplicationStatus.APPROVED && + mentor.mentees?.some((mentee) => mentee.uuid === menteeId) + ) + + if (!isMentee && !isMentor) { + return res.status(403).json({ message: 'Unauthorized' }) + } + + const { statusCode, checkIns, message } = await fetchMonthlyCheckIns( + menteeId + ) + + return res.status(statusCode).json({ checkIns, message }) + } catch (err) { + if (err instanceof Error) { + console.error('Error executing query', err) + return res + .status(500) + .json({ error: 'Internal server error', message: err.message }) + } + throw err + } +} diff --git a/src/migrations/1722051742722-RemoveUniqueConstraintFromProfileUuid.ts b/src/migrations/1722051742722-RemoveUniqueConstraintFromProfileUuid.ts index 936370df..03384d7d 100644 --- a/src/migrations/1722051742722-RemoveUniqueConstraintFromProfileUuid.ts +++ b/src/migrations/1722051742722-RemoveUniqueConstraintFromProfileUuid.ts @@ -6,14 +6,25 @@ export class RemoveUniqueConstraintFromProfileUuid1722051742722 name = 'RemoveUniqueConstraintFromProfileUuid1722051742722' public async up(queryRunner: QueryRunner): Promise { + // Check if the constraint exists before attempting to drop it + const constraintExists = await queryRunner.query(` + SELECT 1 + FROM information_schema.table_constraints + WHERE constraint_name = 'REL_f671cf2220d1bd0621a1a5e92e' + AND table_name = 'mentee' + `) + + if (constraintExists.length > 0) { + await queryRunner.query( + `ALTER TABLE "mentee" DROP CONSTRAINT "REL_f671cf2220d1bd0621a1a5e92e"` + ) + } + await queryRunner.query( `ALTER TABLE "mentee" DROP CONSTRAINT "FK_f671cf2220d1bd0621a1a5e92e7"` ) await queryRunner.query( - `ALTER TABLE "mentee" DROP CONSTRAINT "REL_f671cf2220d1bd0621a1a5e92e"` - ) - await queryRunner.query( - `ALTER TABLE "mentee" ADD CONSTRAINT "FK_f671cf2220d1bd0621a1a5e92e7" FOREIGN KEY ("profileUuid") REFERENCES "profile"("uuid") ON DELETE NO ACTION ON UPDATE NO ACTION` + `ALTER TABLE "mentee" ADD CONSTRAINT "FK_f671cf2220d1bd0621a1a5e92e7" FOREIGN KEY ("profileUuid") REFERENCES "profile"("uuid") ON DELETE CASCADE ON UPDATE NO ACTION` ) } diff --git a/src/migrations/1726593082689-CreateCheckInTable.ts b/src/migrations/1726593082689-CreateCheckInTable.ts deleted file mode 100644 index 8d5c884b..00000000 --- a/src/migrations/1726593082689-CreateCheckInTable.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { type MigrationInterface, type QueryRunner } from 'typeorm' - -export class CreateCheckInTable1726593082689 implements MigrationInterface { - name = 'CreateCheckInTable1726593082689' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - CREATE TABLE "monthly_check_in" ( - "uuid" uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - "generalUpdatesAndFeedback" text NOT NULL, - "progressTowardsGoals" text NOT NULL, - "mediaContentLinks" json NOT NULL, - "checkInDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - "menteeId" uuid NOT NULL, - "created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updated_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT "FK_monthly_check_in_mentee" FOREIGN KEY ("menteeId") REFERENCES "mentee"("uuid") ON DELETE CASCADE - ) - `) - - // Add index on menteeId for better query performance - await queryRunner.query(` - CREATE INDEX "IDX_monthly_check_in_mentee" ON "monthly_check_in" ("menteeId") - `) - } - - public async down(queryRunner: QueryRunner): Promise { - // Drop the index first - await queryRunner.query(` - DROP INDEX "IDX_monthly_check_in_mentee" - `) - - // Then drop the table - await queryRunner.query(` - DROP TABLE "monthly_check_in" - `) - } -} diff --git a/src/migrations/1726595585135-monthly-checking.ts b/src/migrations/1726595585135-monthly-checking.ts new file mode 100644 index 00000000..434efcbf --- /dev/null +++ b/src/migrations/1726595585135-monthly-checking.ts @@ -0,0 +1,21 @@ +import { type MigrationInterface, type QueryRunner } from 'typeorm' + +export class MonthlyChecking1726595585135 implements MigrationInterface { + name = 'MonthlyChecking1726595585135' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "monthly-check-in" ("uuid" uuid NOT NULL DEFAULT uuid_generate_v4(), "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), "generalUpdatesAndFeedback" text NOT NULL, "progressTowardsGoals" text NOT NULL, "mediaContentLinks" json NOT NULL, "checkInDate" TIMESTAMP NOT NULL DEFAULT now(), "menteeId" uuid, CONSTRAINT "PK_44f1414b858e3eb6b8aacee7fbe" PRIMARY KEY ("uuid"))` + ) + await queryRunner.query( + `ALTER TABLE "monthly-check-in" ADD CONSTRAINT "FK_6de642444085d9599d3f260d566" FOREIGN KEY ("menteeId") REFERENCES "mentee"("uuid") ON DELETE NO ACTION ON UPDATE NO ACTION` + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "monthly-check-in" DROP CONSTRAINT "FK_6de642444085d9599d3f260d566"` + ) + await queryRunner.query(`DROP TABLE "monthly-check-in"`) + } +} diff --git a/src/routes/mentee/mentee.route.ts b/src/routes/mentee/mentee.route.ts index 24d255b0..f4e3e074 100644 --- a/src/routes/mentee/mentee.route.ts +++ b/src/routes/mentee/mentee.route.ts @@ -2,14 +2,17 @@ import express from 'express' import { requireAuth } from '../../controllers/auth.controller' import { getMenteeDetails, + getMonthlyCheckIns, getPublicMenteeDetails, menteeApplicationHandler, revokeApplication, + submitMonthlyCheckIn, updateMenteeStatus } from '../../controllers/mentee.controller' import { requestBodyValidator } from '../../middlewares/requestValidator' import { menteeApplicationSchema, + submitMonthlyCheckInSchema, updateMenteeStatusSchema } from '../../schemas/mentee-routes.schemas' @@ -29,4 +32,11 @@ menteeRouter.put( ) menteeRouter.put('/revoke-application', requireAuth, revokeApplication) +menteeRouter.post( + '/checkin', + [requireAuth, requestBodyValidator(submitMonthlyCheckInSchema)], + submitMonthlyCheckIn +) + +menteeRouter.get('/:menteeId/checkin', requireAuth, getMonthlyCheckIns) export default menteeRouter diff --git a/src/schemas/mentee-routes.schemas.ts b/src/schemas/mentee-routes.schemas.ts index 0f6d2878..ab5dfc55 100644 --- a/src/schemas/mentee-routes.schemas.ts +++ b/src/schemas/mentee-routes.schemas.ts @@ -9,3 +9,15 @@ export const menteeApplicationSchema = z.object({ export const updateMenteeStatusSchema = z.object({ state: z.nativeEnum(MenteeApplicationStatus) }) + +export const submitMonthlyCheckInSchema = z.object({ + generalUpdatesAndFeedback: z + .string() + .min(1, 'Please provide a valid feedback'), + progressTowardsGoals: z + .string() + .min(1, 'Please provide a valid progress report'), + mediaContentLinks: z + .array(z.string()) + .min(1, 'Please provide at least 3 media content links') +}) diff --git a/src/services/mentee.service.ts b/src/services/mentee.service.ts index d16c8541..5315ac55 100644 --- a/src/services/mentee.service.ts +++ b/src/services/mentee.service.ts @@ -1,4 +1,5 @@ import { dataSource } from '../configs/dbConfig' +import MonthlyCheckIn from '../entities/checkin.entity' import Mentee from '../entities/mentee.entity' import Mentor from '../entities/mentor.entity' import type Profile from '../entities/profile.entity' @@ -161,3 +162,99 @@ export const getPublicMentee = async ( throw new Error('Error getting mentees') } } + +export const addMonthlyCheckIn = async ( + menteeId: string, + checkInData: { + generalUpdatedsAndFeedback: string + progressTowardsGoals: string + mediaContentLinks: string[] + } +): Promise<{ + statusCode: number + checkIn?: MonthlyCheckIn + message: string +}> => { + try { + const menteeRepository = dataSource.getRepository(Mentee) + const checkInRepository = dataSource.getRepository(MonthlyCheckIn) + + const mentee = await menteeRepository.findOne({ + where: { uuid: menteeId } + }) + + if (!mentee) { + return { + statusCode: 404, + message: 'Mentee not found' + } + } + + const newCheckIn = new MonthlyCheckIn( + checkInData.generalUpdatedsAndFeedback, + checkInData.progressTowardsGoals, + checkInData.mediaContentLinks, + new Date(), + mentee + ) + + await checkInRepository.save(newCheckIn) + + const mentor = await dataSource + .getRepository(Mentor) + .findOne({ where: { uuid: mentee.mentor.uuid }, relations: ['profile'] }) + + if (mentor) { + const mentorNotificationContent = { + subject: 'New Monthly Check-In Submitted', + message: `A new monthly check-in has been submitted by ${mentee.application.firstName} ${mentee.application.lastName}` + } + + await sendEmail( + mentor.profile.primary_email, + mentorNotificationContent.subject, + mentorNotificationContent.message + ) + } + return { + statusCode: 200, + checkIn: newCheckIn, + message: 'New check-in created' + } + } catch (err) { + throw new Error('Error adding check-in') + } +} + +export const fetchMonthlyCheckIns = async ( + menteeId: string +): Promise<{ + statusCode: number + checkIns: MonthlyCheckIn[] + message: string +}> => { + try { + const checkInRepository = dataSource.getRepository(MonthlyCheckIn) + + const checkIns = await checkInRepository.find({ + where: { mentee: { uuid: menteeId } }, + order: { checkInDate: 'DESC' } + }) + + if (checkIns.length === 0) { + return { + statusCode: 404, + checkIns: [], + message: 'No check-ins found' + } + } + + return { + statusCode: 200, + checkIns, + message: 'Check-ins found' + } + } catch (err) { + throw new Error('Error getting check-ins') + } +} From dc1f12685115c1980219098ba2971805a2e96416 Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Wed, 18 Sep 2024 18:44:54 +0530 Subject: [PATCH 03/14] Refactor Mentee entity to include MonthlyCheckIn relationship --- package.json | 1 + src/controllers/mentee.controller.ts | 31 ++++--- src/entities/mentee.entity.ts | 6 +- .../1726595585135-monthly-checking.ts | 21 ----- src/migrations/1726662706578-monthlycheck.ts | 40 +++++++++ src/services/mentee.service.ts | 87 ++++++++++--------- 6 files changed, 108 insertions(+), 78 deletions(-) delete mode 100644 src/migrations/1726595585135-monthly-checking.ts create mode 100644 src/migrations/1726662706578-monthlycheck.ts diff --git a/package.json b/package.json index 0713614e..92dfade8 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "typeorm:db": "npm run build && npx typeorm -d dist/src/configs/dbConfig.js", "migration:generate": "npm run typeorm:db -- migration:generate", "migration:run": "npm run typeorm:db -- migration:run", + "migration:revert": "npm run typeorm:db -- migration:revert", "sync:db": "npm run typeorm:db schema:sync", "seed": "npm run build && node dist/src/scripts/seed-db.js" }, diff --git a/src/controllers/mentee.controller.ts b/src/controllers/mentee.controller.ts index b06ca6ef..cf10f77f 100644 --- a/src/controllers/mentee.controller.ts +++ b/src/controllers/mentee.controller.ts @@ -10,9 +10,9 @@ import { import { MentorApplicationStatus, StatusUpdatedBy } from '../enums' import { addMentee, - addMonthlyCheckIn, fetchMonthlyCheckIns, - getPublicMentee + getPublicMentee, + addMonthlyCheckIn } from '../services/mentee.service' import type MonthlyCheckIn from '../entities/checkin.entity' @@ -138,26 +138,29 @@ export const submitMonthlyCheckIn = async ( res: Response ): Promise => { try { - const user = req.user as Profile - const { menteeId } = req.params - const checkInData = req.body - - if (user.uuid !== menteeId) { - res.status(403).json({ message: 'Unauthorized' }) - } - - const { statusCode, message } = await addMonthlyCheckIn( + const menteeId = '342c9387-4505-4c44-bacc-a80ad6850df3' + const { + generalUpdatesAndFeedback, + progressTowardsGoals, + mediaContentLinks + } = req.body + + const newCheckIn = await addMonthlyCheckIn( menteeId, - checkInData + generalUpdatesAndFeedback, + progressTowardsGoals, + mediaContentLinks ) - res.status(statusCode).json({ message }) + + res + .status(201) + .json({ checkIn: newCheckIn, message: 'Check-in added successfully' }) } catch (err) { if (err instanceof Error) { console.error('Error executing query', err) res .status(500) .json({ error: 'Internal server error', message: err.message }) - return } throw err } diff --git a/src/entities/mentee.entity.ts b/src/entities/mentee.entity.ts index 474a80a9..dbfbf5b0 100644 --- a/src/entities/mentee.entity.ts +++ b/src/entities/mentee.entity.ts @@ -37,19 +37,21 @@ class Mentee extends BaseEntity { mentor: Mentor @OneToMany(() => MonthlyCheckIn, (checkIn) => checkIn.mentee) - checkIns!: MonthlyCheckIn[] + checkIns?: MonthlyCheckIn[] constructor( state: MenteeApplicationStatus, application: Record, profile: profileEntity, - mentor: Mentor + mentor: Mentor, + checkIns?: MonthlyCheckIn[] ) { super() this.state = state || MenteeApplicationStatus.PENDING this.application = application this.profile = profile this.mentor = mentor + this.checkIns = checkIns } } diff --git a/src/migrations/1726595585135-monthly-checking.ts b/src/migrations/1726595585135-monthly-checking.ts deleted file mode 100644 index 434efcbf..00000000 --- a/src/migrations/1726595585135-monthly-checking.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { type MigrationInterface, type QueryRunner } from 'typeorm' - -export class MonthlyChecking1726595585135 implements MigrationInterface { - name = 'MonthlyChecking1726595585135' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE TABLE "monthly-check-in" ("uuid" uuid NOT NULL DEFAULT uuid_generate_v4(), "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), "generalUpdatesAndFeedback" text NOT NULL, "progressTowardsGoals" text NOT NULL, "mediaContentLinks" json NOT NULL, "checkInDate" TIMESTAMP NOT NULL DEFAULT now(), "menteeId" uuid, CONSTRAINT "PK_44f1414b858e3eb6b8aacee7fbe" PRIMARY KEY ("uuid"))` - ) - await queryRunner.query( - `ALTER TABLE "monthly-check-in" ADD CONSTRAINT "FK_6de642444085d9599d3f260d566" FOREIGN KEY ("menteeId") REFERENCES "mentee"("uuid") ON DELETE NO ACTION ON UPDATE NO ACTION` - ) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "monthly-check-in" DROP CONSTRAINT "FK_6de642444085d9599d3f260d566"` - ) - await queryRunner.query(`DROP TABLE "monthly-check-in"`) - } -} diff --git a/src/migrations/1726662706578-monthlycheck.ts b/src/migrations/1726662706578-monthlycheck.ts new file mode 100644 index 00000000..77c8726d --- /dev/null +++ b/src/migrations/1726662706578-monthlycheck.ts @@ -0,0 +1,40 @@ +import { type MigrationInterface, type QueryRunner } from 'typeorm' + +export class Monthlycheck1726662706578 implements MigrationInterface { + name = 'Monthlycheck1726662706578' + + public async up(queryRunner: QueryRunner): Promise { + // Check if the table already exists + const tableExists = await queryRunner.hasTable('monthly-check-in') + if (!tableExists) { + await queryRunner.query(` + CREATE TABLE "monthly-check-in" ( + "uuid" uuid NOT NULL DEFAULT uuid_generate_v4(), + "created_at" TIMESTAMP NOT NULL DEFAULT now(), + "updated_at" TIMESTAMP NOT NULL DEFAULT now(), + "generalUpdatesAndFeedback" text NOT NULL, + "progressTowardsGoals" text NOT NULL, + "mediaContentLinks" json NOT NULL, + "checkInDate" TIMESTAMP NOT NULL DEFAULT now(), + "menteeId" uuid, + CONSTRAINT "PK_44f1414b858e3eb6b8aacee7fbe" PRIMARY KEY ("uuid") + ) + `) + await queryRunner.query(` + ALTER TABLE "monthly-check-in" + ADD CONSTRAINT "FK_6de642444085d9599d3f260d566" + FOREIGN KEY ("menteeId") REFERENCES "mentee"("uuid") + ON DELETE NO ACTION ON UPDATE NO ACTION + `) + } + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + ALTER TABLE "monthly-check-in" DROP CONSTRAINT "FK_6de642444085d9599d3f260d566" + `) + await queryRunner.query(` + DROP TABLE IF EXISTS "monthly-check-in" + `) + } +} diff --git a/src/services/mentee.service.ts b/src/services/mentee.service.ts index 5315ac55..83e2c44f 100644 --- a/src/services/mentee.service.ts +++ b/src/services/mentee.service.ts @@ -4,6 +4,7 @@ import Mentee from '../entities/mentee.entity' import Mentor from '../entities/mentor.entity' import type Profile from '../entities/profile.entity' import { MenteeApplicationStatus } from '../enums' +import { type ApiResponse } from '../types' import { getEmailContent, getMentorNotifyEmailContent, @@ -165,64 +166,68 @@ export const getPublicMentee = async ( export const addMonthlyCheckIn = async ( menteeId: string, - checkInData: { - generalUpdatedsAndFeedback: string - progressTowardsGoals: string - mediaContentLinks: string[] - } -): Promise<{ - statusCode: number - checkIn?: MonthlyCheckIn - message: string -}> => { + generalUpdatesAndFeedback: string, + progressTowardsGoals: string, + mediaContentLinks: string[] +): Promise> => { try { const menteeRepository = dataSource.getRepository(Mentee) const checkInRepository = dataSource.getRepository(MonthlyCheckIn) + console.log(checkInRepository) + const mentee = await menteeRepository.findOne({ - where: { uuid: menteeId } + where: { + uuid: menteeId + } }) + console.log(mentee) + if (!mentee) { - return { - statusCode: 404, - message: 'Mentee not found' - } + return { statusCode: 404, message: 'Mentee not found' } } - const newCheckIn = new MonthlyCheckIn( - checkInData.generalUpdatedsAndFeedback, - checkInData.progressTowardsGoals, - checkInData.mediaContentLinks, - new Date(), + const newCheckIn = checkInRepository.create({ + generalUpdatesAndFeedback, + progressTowardsGoals, + mediaContentLinks, + checkInDate: new Date(), mentee - ) + }) - await checkInRepository.save(newCheckIn) + console.log(newCheckIn) + try { + await checkInRepository.save(newCheckIn) - const mentor = await dataSource - .getRepository(Mentor) - .findOne({ where: { uuid: mentee.mentor.uuid }, relations: ['profile'] }) + const mentor = await dataSource.getRepository(Mentor).findOne({ + where: { uuid: mentee.mentor.uuid }, + relations: ['profile'] + }) - if (mentor) { - const mentorNotificationContent = { - subject: 'New Monthly Check-In Submitted', - message: `A new monthly check-in has been submitted by ${mentee.application.firstName} ${mentee.application.lastName}` - } + if (mentor) { + const mentorNotificationContent = { + subject: 'New Monthly Check-In Submitted', + message: `A new monthly check-in has been submitted by ${mentee.uuid}` + } - await sendEmail( - mentor.profile.primary_email, - mentorNotificationContent.subject, - mentorNotificationContent.message - ) - } - return { - statusCode: 200, - checkIn: newCheckIn, - message: 'New check-in created' + await sendEmail( + mentor.profile.primary_email, + mentorNotificationContent.subject, + mentorNotificationContent.message + ) + } + return { + statusCode: 200, + data: newCheckIn, + message: 'New check-in created' + } + } catch (err) { + throw new Error('Error adding check-in') } } catch (err) { - throw new Error('Error adding check-in') + console.error('Error in addMonthlyCheckIn', err) + throw new Error('Error in addMonthlyCheckIn') } } From cab216efba39e9297c4403cdedeae5badc82369c Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Wed, 18 Sep 2024 20:50:22 +0530 Subject: [PATCH 04/14] Refactor Mentee service to include MonthlyCheckIn relationship --- src/services/mentee.service.ts | 35 ++++++---------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/src/services/mentee.service.ts b/src/services/mentee.service.ts index 83e2c44f..265faa68 100644 --- a/src/services/mentee.service.ts +++ b/src/services/mentee.service.ts @@ -4,7 +4,6 @@ import Mentee from '../entities/mentee.entity' import Mentor from '../entities/mentor.entity' import type Profile from '../entities/profile.entity' import { MenteeApplicationStatus } from '../enums' -import { type ApiResponse } from '../types' import { getEmailContent, getMentorNotifyEmailContent, @@ -169,7 +168,10 @@ export const addMonthlyCheckIn = async ( generalUpdatesAndFeedback: string, progressTowardsGoals: string, mediaContentLinks: string[] -): Promise> => { +): Promise<{ + statusCode: number + message: string +}> => { try { const menteeRepository = dataSource.getRepository(Mentee) const checkInRepository = dataSource.getRepository(MonthlyCheckIn) @@ -197,34 +199,9 @@ export const addMonthlyCheckIn = async ( }) console.log(newCheckIn) - try { - await checkInRepository.save(newCheckIn) - - const mentor = await dataSource.getRepository(Mentor).findOne({ - where: { uuid: mentee.mentor.uuid }, - relations: ['profile'] - }) - - if (mentor) { - const mentorNotificationContent = { - subject: 'New Monthly Check-In Submitted', - message: `A new monthly check-in has been submitted by ${mentee.uuid}` - } + await checkInRepository.save(newCheckIn) - await sendEmail( - mentor.profile.primary_email, - mentorNotificationContent.subject, - mentorNotificationContent.message - ) - } - return { - statusCode: 200, - data: newCheckIn, - message: 'New check-in created' - } - } catch (err) { - throw new Error('Error adding check-in') - } + return { statusCode: 200, message: 'monthly checking inserted' } } catch (err) { console.error('Error in addMonthlyCheckIn', err) throw new Error('Error in addMonthlyCheckIn') From 5c8383f3481d440537ee17db6b5bfd27bc4c4fdd Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Fri, 20 Sep 2024 14:06:37 +0530 Subject: [PATCH 05/14] Refactor Mentee service to include MonthlyCheckIn relationship --- src/controllers/mentee.controller.ts | 19 +++------ src/entities/checkin.entity.ts | 20 ++++++++++ src/migrations/1726662706578-monthlycheck.ts | 40 ------------------- .../1726811876231-monthly-checking.ts | 21 ++++++++++ src/routes/mentee/mentee.route.ts | 2 +- src/services/mentee.service.ts | 13 +++++- sudo | 0 7 files changed, 60 insertions(+), 55 deletions(-) delete mode 100644 src/migrations/1726662706578-monthlycheck.ts create mode 100644 src/migrations/1726811876231-monthly-checking.ts create mode 100644 sudo diff --git a/src/controllers/mentee.controller.ts b/src/controllers/mentee.controller.ts index cf10f77f..af350244 100644 --- a/src/controllers/mentee.controller.ts +++ b/src/controllers/mentee.controller.ts @@ -138,15 +138,19 @@ export const submitMonthlyCheckIn = async ( res: Response ): Promise => { try { - const menteeId = '342c9387-4505-4c44-bacc-a80ad6850df3' const { + menteeId, + title, generalUpdatesAndFeedback, progressTowardsGoals, mediaContentLinks } = req.body + console.log(menteeId) + const newCheckIn = await addMonthlyCheckIn( menteeId, + title, generalUpdatesAndFeedback, progressTowardsGoals, mediaContentLinks @@ -171,20 +175,9 @@ export const getMonthlyCheckIns = async ( res: Response ): Promise>> => { try { - const user = req.user as Profile const { menteeId } = req.params - const isMentee = user.uuid === menteeId - const isMentor = user.mentor?.some( - (mentor) => - mentor.state === MentorApplicationStatus.APPROVED && - mentor.mentees?.some((mentee) => mentee.uuid === menteeId) - ) - - if (!isMentee && !isMentor) { - return res.status(403).json({ message: 'Unauthorized' }) - } - + console.log('menteeId', menteeId) const { statusCode, checkIns, message } = await fetchMonthlyCheckIns( menteeId ) diff --git a/src/entities/checkin.entity.ts b/src/entities/checkin.entity.ts index b1baf8a8..31693ad9 100644 --- a/src/entities/checkin.entity.ts +++ b/src/entities/checkin.entity.ts @@ -4,6 +4,9 @@ import Mentee from './mentee.entity' @Entity('monthly-check-in') class MonthlyCheckIn extends BaseEntity { + @Column({ type: 'text' }) + title: string + @Column({ type: 'text' }) generalUpdatesAndFeedback: string @@ -13,6 +16,15 @@ class MonthlyCheckIn extends BaseEntity { @Column({ type: 'json' }) mediaContentLinks: string[] + @Column({ type: 'text', nullable: true }) + mentorFeedback: string + + @Column({ type: 'boolean', default: false }) + isCheckedByMentor: boolean + + @Column({ type: 'timestamp', nullable: true }) + mentorCheckedDate: Date + @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) checkInDate: Date @@ -21,16 +33,24 @@ class MonthlyCheckIn extends BaseEntity { mentee: Mentee constructor( + title: string, generalUpdatesAndFeedback: string, progressTowardsGoals: string, mediaContentLinks: string[], + mentorFeedback: string, + isCheckedByMentor: boolean, + mentorCheckedDate: Date, checkInDate: Date, mentee: Mentee ) { super() + this.title = title this.generalUpdatesAndFeedback = generalUpdatesAndFeedback this.progressTowardsGoals = progressTowardsGoals this.mediaContentLinks = mediaContentLinks + this.mentorFeedback = mentorFeedback + this.isCheckedByMentor = isCheckedByMentor + this.mentorCheckedDate = mentorCheckedDate this.checkInDate = checkInDate this.mentee = mentee } diff --git a/src/migrations/1726662706578-monthlycheck.ts b/src/migrations/1726662706578-monthlycheck.ts deleted file mode 100644 index 77c8726d..00000000 --- a/src/migrations/1726662706578-monthlycheck.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { type MigrationInterface, type QueryRunner } from 'typeorm' - -export class Monthlycheck1726662706578 implements MigrationInterface { - name = 'Monthlycheck1726662706578' - - public async up(queryRunner: QueryRunner): Promise { - // Check if the table already exists - const tableExists = await queryRunner.hasTable('monthly-check-in') - if (!tableExists) { - await queryRunner.query(` - CREATE TABLE "monthly-check-in" ( - "uuid" uuid NOT NULL DEFAULT uuid_generate_v4(), - "created_at" TIMESTAMP NOT NULL DEFAULT now(), - "updated_at" TIMESTAMP NOT NULL DEFAULT now(), - "generalUpdatesAndFeedback" text NOT NULL, - "progressTowardsGoals" text NOT NULL, - "mediaContentLinks" json NOT NULL, - "checkInDate" TIMESTAMP NOT NULL DEFAULT now(), - "menteeId" uuid, - CONSTRAINT "PK_44f1414b858e3eb6b8aacee7fbe" PRIMARY KEY ("uuid") - ) - `) - await queryRunner.query(` - ALTER TABLE "monthly-check-in" - ADD CONSTRAINT "FK_6de642444085d9599d3f260d566" - FOREIGN KEY ("menteeId") REFERENCES "mentee"("uuid") - ON DELETE NO ACTION ON UPDATE NO ACTION - `) - } - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(` - ALTER TABLE "monthly-check-in" DROP CONSTRAINT "FK_6de642444085d9599d3f260d566" - `) - await queryRunner.query(` - DROP TABLE IF EXISTS "monthly-check-in" - `) - } -} diff --git a/src/migrations/1726811876231-monthly-checking.ts b/src/migrations/1726811876231-monthly-checking.ts new file mode 100644 index 00000000..29fec671 --- /dev/null +++ b/src/migrations/1726811876231-monthly-checking.ts @@ -0,0 +1,21 @@ +import { type MigrationInterface, type QueryRunner } from 'typeorm' + +export class MonthlyChecking1726811876231 implements MigrationInterface { + name = 'MonthlyChecking1726811876231' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "monthly-check-in" ("uuid" uuid NOT NULL DEFAULT uuid_generate_v4(), "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), "title" text NOT NULL, "generalUpdatesAndFeedback" text NOT NULL, "progressTowardsGoals" text NOT NULL, "mediaContentLinks" json NOT NULL, "mentorFeedback" text, "isCheckedByMentor" boolean NOT NULL DEFAULT false, "mentorCheckedDate" TIMESTAMP, "checkInDate" TIMESTAMP NOT NULL DEFAULT now(), "menteeId" uuid, CONSTRAINT "PK_44f1414b858e3eb6b8aacee7fbe" PRIMARY KEY ("uuid"))` + ) + await queryRunner.query( + `ALTER TABLE "monthly-check-in" ADD CONSTRAINT "FK_6de642444085d9599d3f260d566" FOREIGN KEY ("menteeId") REFERENCES "mentee"("uuid") ON DELETE NO ACTION ON UPDATE NO ACTION` + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "monthly-check-in" DROP CONSTRAINT "FK_6de642444085d9599d3f260d566"` + ) + await queryRunner.query(`DROP TABLE "monthly-check-in"`) + } +} diff --git a/src/routes/mentee/mentee.route.ts b/src/routes/mentee/mentee.route.ts index f4e3e074..6128837a 100644 --- a/src/routes/mentee/mentee.route.ts +++ b/src/routes/mentee/mentee.route.ts @@ -38,5 +38,5 @@ menteeRouter.post( submitMonthlyCheckIn ) -menteeRouter.get('/:menteeId/checkin', requireAuth, getMonthlyCheckIns) +menteeRouter.get('/checkin/:menteeId', requireAuth, getMonthlyCheckIns) export default menteeRouter diff --git a/src/services/mentee.service.ts b/src/services/mentee.service.ts index 265faa68..5b340723 100644 --- a/src/services/mentee.service.ts +++ b/src/services/mentee.service.ts @@ -165,6 +165,7 @@ export const getPublicMentee = async ( export const addMonthlyCheckIn = async ( menteeId: string, + title: string, generalUpdatesAndFeedback: string, progressTowardsGoals: string, mediaContentLinks: string[] @@ -176,7 +177,7 @@ export const addMonthlyCheckIn = async ( const menteeRepository = dataSource.getRepository(Mentee) const checkInRepository = dataSource.getRepository(MonthlyCheckIn) - console.log(checkInRepository) + console.log(menteeId) const mentee = await menteeRepository.findOne({ where: { @@ -191,6 +192,7 @@ export const addMonthlyCheckIn = async ( } const newCheckIn = checkInRepository.create({ + title, generalUpdatesAndFeedback, progressTowardsGoals, mediaContentLinks, @@ -218,8 +220,17 @@ export const fetchMonthlyCheckIns = async ( try { const checkInRepository = dataSource.getRepository(MonthlyCheckIn) + const mentee = await dataSource.getRepository(Mentee).findOne({ + where: { uuid: menteeId } + }) + + if (!mentee) { + return { statusCode: 404, checkIns: [], message: 'Mentee not found' } + } + const checkIns = await checkInRepository.find({ where: { mentee: { uuid: menteeId } }, + relations: ['mentee'], order: { checkInDate: 'DESC' } }) diff --git a/sudo b/sudo new file mode 100644 index 00000000..e69de29b From 7681a50ed9db527f9e52b8f076d39abad5fc7d94 Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Wed, 25 Sep 2024 02:18:43 +0530 Subject: [PATCH 06/14] Added tags column into monthly-checking-in table --- src/controllers/mentee.controller.ts | 69 +----------------- src/controllers/monthlyChecking.controller.ts | 70 +++++++++++++++++++ src/entities/checkin.entity.ts | 5 ++ .../1726811876231-monthly-checking.ts | 21 ------ .../1727197270336-monthly-checking-tags.ts | 14 ++++ src/routes/mentee/mentee.route.ts | 12 ++-- src/schemas/mentee-routes.schemas.ts | 19 ++++- src/services/mentee.service.ts | 4 +- 8 files changed, 117 insertions(+), 97 deletions(-) create mode 100644 src/controllers/monthlyChecking.controller.ts delete mode 100644 src/migrations/1726811876231-monthly-checking.ts create mode 100644 src/migrations/1727197270336-monthly-checking-tags.ts diff --git a/src/controllers/mentee.controller.ts b/src/controllers/mentee.controller.ts index af350244..45b9faa4 100644 --- a/src/controllers/mentee.controller.ts +++ b/src/controllers/mentee.controller.ts @@ -8,13 +8,7 @@ import { updateStatus } from '../services/admin/mentee.service' import { MentorApplicationStatus, StatusUpdatedBy } from '../enums' -import { - addMentee, - fetchMonthlyCheckIns, - getPublicMentee, - addMonthlyCheckIn -} from '../services/mentee.service' -import type MonthlyCheckIn from '../entities/checkin.entity' +import { addMentee, getPublicMentee } from '../services/mentee.service' export const menteeApplicationHandler = async ( req: Request, @@ -132,64 +126,3 @@ export const getPublicMenteeDetails = async ( throw err } } - -export const submitMonthlyCheckIn = async ( - req: Request, - res: Response -): Promise => { - try { - const { - menteeId, - title, - generalUpdatesAndFeedback, - progressTowardsGoals, - mediaContentLinks - } = req.body - - console.log(menteeId) - - const newCheckIn = await addMonthlyCheckIn( - menteeId, - title, - generalUpdatesAndFeedback, - progressTowardsGoals, - mediaContentLinks - ) - - res - .status(201) - .json({ checkIn: newCheckIn, message: 'Check-in added successfully' }) - } catch (err) { - if (err instanceof Error) { - console.error('Error executing query', err) - res - .status(500) - .json({ error: 'Internal server error', message: err.message }) - } - throw err - } -} - -export const getMonthlyCheckIns = async ( - req: Request, - res: Response -): Promise>> => { - try { - const { menteeId } = req.params - - console.log('menteeId', menteeId) - const { statusCode, checkIns, message } = await fetchMonthlyCheckIns( - menteeId - ) - - return res.status(statusCode).json({ checkIns, message }) - } catch (err) { - if (err instanceof Error) { - console.error('Error executing query', err) - return res - .status(500) - .json({ error: 'Internal server error', message: err.message }) - } - throw err - } -} diff --git a/src/controllers/monthlyChecking.controller.ts b/src/controllers/monthlyChecking.controller.ts new file mode 100644 index 00000000..af6ed0eb --- /dev/null +++ b/src/controllers/monthlyChecking.controller.ts @@ -0,0 +1,70 @@ +import type { Request, Response } from 'express' +import { type ApiResponse } from '../types' +import { + fetchMonthlyCheckIns, + addMonthlyCheckIn +} from '../services/mentee.service' +import type MonthlyCheckIn from '../entities/checkin.entity' + +export const postMonthlyCheckIn = async ( + req: Request, + res: Response +): Promise => { + try { + const { + menteeId, + title, + generalUpdatesAndFeedback, + progressTowardsGoals, + mediaContentLinks, + tags + } = req.body + + console.log(menteeId) + + const newCheckIn = await addMonthlyCheckIn( + menteeId, + title, + generalUpdatesAndFeedback, + progressTowardsGoals, + mediaContentLinks, + tags + ) + + res + .status(201) + .json({ checkIn: newCheckIn, message: 'Check-in added successfully' }) + } catch (err) { + if (err instanceof Error) { + console.error('Error executing query', err) + res + .status(500) + .json({ error: 'Internal server error', message: err.message }) + } + throw err + } +} + +export const getMonthlyCheckIns = async ( + req: Request, + res: Response +): Promise>> => { + try { + const { menteeId } = req.params + + console.log('menteeId', menteeId) + const { statusCode, checkIns, message } = await fetchMonthlyCheckIns( + menteeId + ) + + return res.status(statusCode).json({ checkIns, message }) + } catch (err) { + if (err instanceof Error) { + console.error('Error executing query', err) + return res + .status(500) + .json({ error: 'Internal server error', message: err.message }) + } + throw err + } +} diff --git a/src/entities/checkin.entity.ts b/src/entities/checkin.entity.ts index 31693ad9..0f70044b 100644 --- a/src/entities/checkin.entity.ts +++ b/src/entities/checkin.entity.ts @@ -16,6 +16,9 @@ class MonthlyCheckIn extends BaseEntity { @Column({ type: 'json' }) mediaContentLinks: string[] + @Column({ type: 'json', nullable: true }) + tags: string[] + @Column({ type: 'text', nullable: true }) mentorFeedback: string @@ -38,6 +41,7 @@ class MonthlyCheckIn extends BaseEntity { progressTowardsGoals: string, mediaContentLinks: string[], mentorFeedback: string, + tags: string[], isCheckedByMentor: boolean, mentorCheckedDate: Date, checkInDate: Date, @@ -48,6 +52,7 @@ class MonthlyCheckIn extends BaseEntity { this.generalUpdatesAndFeedback = generalUpdatesAndFeedback this.progressTowardsGoals = progressTowardsGoals this.mediaContentLinks = mediaContentLinks + this.tags = tags this.mentorFeedback = mentorFeedback this.isCheckedByMentor = isCheckedByMentor this.mentorCheckedDate = mentorCheckedDate diff --git a/src/migrations/1726811876231-monthly-checking.ts b/src/migrations/1726811876231-monthly-checking.ts deleted file mode 100644 index 29fec671..00000000 --- a/src/migrations/1726811876231-monthly-checking.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { type MigrationInterface, type QueryRunner } from 'typeorm' - -export class MonthlyChecking1726811876231 implements MigrationInterface { - name = 'MonthlyChecking1726811876231' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE TABLE "monthly-check-in" ("uuid" uuid NOT NULL DEFAULT uuid_generate_v4(), "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), "title" text NOT NULL, "generalUpdatesAndFeedback" text NOT NULL, "progressTowardsGoals" text NOT NULL, "mediaContentLinks" json NOT NULL, "mentorFeedback" text, "isCheckedByMentor" boolean NOT NULL DEFAULT false, "mentorCheckedDate" TIMESTAMP, "checkInDate" TIMESTAMP NOT NULL DEFAULT now(), "menteeId" uuid, CONSTRAINT "PK_44f1414b858e3eb6b8aacee7fbe" PRIMARY KEY ("uuid"))` - ) - await queryRunner.query( - `ALTER TABLE "monthly-check-in" ADD CONSTRAINT "FK_6de642444085d9599d3f260d566" FOREIGN KEY ("menteeId") REFERENCES "mentee"("uuid") ON DELETE NO ACTION ON UPDATE NO ACTION` - ) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "monthly-check-in" DROP CONSTRAINT "FK_6de642444085d9599d3f260d566"` - ) - await queryRunner.query(`DROP TABLE "monthly-check-in"`) - } -} diff --git a/src/migrations/1727197270336-monthly-checking-tags.ts b/src/migrations/1727197270336-monthly-checking-tags.ts new file mode 100644 index 00000000..2a1009e3 --- /dev/null +++ b/src/migrations/1727197270336-monthly-checking-tags.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class MonthlyCheckingTags1727197270336 implements MigrationInterface { + name = 'MonthlyCheckingTags1727197270336' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "monthly-check-in" ADD "tags" json`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "monthly-check-in" DROP COLUMN "tags"`); + } + +} diff --git a/src/routes/mentee/mentee.route.ts b/src/routes/mentee/mentee.route.ts index 6128837a..b58efa72 100644 --- a/src/routes/mentee/mentee.route.ts +++ b/src/routes/mentee/mentee.route.ts @@ -2,19 +2,21 @@ import express from 'express' import { requireAuth } from '../../controllers/auth.controller' import { getMenteeDetails, - getMonthlyCheckIns, getPublicMenteeDetails, menteeApplicationHandler, revokeApplication, - submitMonthlyCheckIn, updateMenteeStatus } from '../../controllers/mentee.controller' import { requestBodyValidator } from '../../middlewares/requestValidator' import { menteeApplicationSchema, - submitMonthlyCheckInSchema, + postMonthlyCheckInSchema, updateMenteeStatusSchema } from '../../schemas/mentee-routes.schemas' +import { + getMonthlyCheckIns, + postMonthlyCheckIn +} from '../../controllers/monthlyChecking.controller' const menteeRouter = express.Router() @@ -34,8 +36,8 @@ menteeRouter.put('/revoke-application', requireAuth, revokeApplication) menteeRouter.post( '/checkin', - [requireAuth, requestBodyValidator(submitMonthlyCheckInSchema)], - submitMonthlyCheckIn + [requireAuth, requestBodyValidator(postMonthlyCheckInSchema)], + postMonthlyCheckIn ) menteeRouter.get('/checkin/:menteeId', requireAuth, getMonthlyCheckIns) diff --git a/src/schemas/mentee-routes.schemas.ts b/src/schemas/mentee-routes.schemas.ts index ab5dfc55..49f7325d 100644 --- a/src/schemas/mentee-routes.schemas.ts +++ b/src/schemas/mentee-routes.schemas.ts @@ -10,7 +10,21 @@ export const updateMenteeStatusSchema = z.object({ state: z.nativeEnum(MenteeApplicationStatus) }) -export const submitMonthlyCheckInSchema = z.object({ +export const postMonthlyCheckInSchema = z.object({ + title: z.enum([ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' + ]), generalUpdatesAndFeedback: z .string() .min(1, 'Please provide a valid feedback'), @@ -19,5 +33,6 @@ export const submitMonthlyCheckInSchema = z.object({ .min(1, 'Please provide a valid progress report'), mediaContentLinks: z .array(z.string()) - .min(1, 'Please provide at least 3 media content links') + .min(3, 'Please provide at least 3 media content links'), + tags: z.array(z.string()).min(1, 'Please provide at least 1 tag') }) diff --git a/src/services/mentee.service.ts b/src/services/mentee.service.ts index 5b340723..5c665bdd 100644 --- a/src/services/mentee.service.ts +++ b/src/services/mentee.service.ts @@ -168,7 +168,8 @@ export const addMonthlyCheckIn = async ( title: string, generalUpdatesAndFeedback: string, progressTowardsGoals: string, - mediaContentLinks: string[] + mediaContentLinks: string[], + tags: string[] ): Promise<{ statusCode: number message: string @@ -196,6 +197,7 @@ export const addMonthlyCheckIn = async ( generalUpdatesAndFeedback, progressTowardsGoals, mediaContentLinks, + tags, checkInDate: new Date(), mentee }) From 37e63cb84698658b2302605aaffc65765a41b395 Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Wed, 25 Sep 2024 02:51:36 +0530 Subject: [PATCH 07/14] Refactor Mentee service to include MonthlyCheckIn feedback functionality --- src/controllers/monthlyChecking.controller.ts | 32 ++++++++++++ src/routes/mentee/mentee.route.ts | 4 ++ src/services/monthlyChecking.service.ts | 49 +++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 src/services/monthlyChecking.service.ts diff --git a/src/controllers/monthlyChecking.controller.ts b/src/controllers/monthlyChecking.controller.ts index af6ed0eb..0207a028 100644 --- a/src/controllers/monthlyChecking.controller.ts +++ b/src/controllers/monthlyChecking.controller.ts @@ -5,6 +5,7 @@ import { addMonthlyCheckIn } from '../services/mentee.service' import type MonthlyCheckIn from '../entities/checkin.entity' +import { addMentorFeedbackMonthlyCheckIn } from '../services/monthlyChecking.service' export const postMonthlyCheckIn = async ( req: Request, @@ -68,3 +69,34 @@ export const getMonthlyCheckIns = async ( throw err } } + +export const addFeedbackMonthlyCheckIn = async ( + req: Request, + res: Response +): Promise => { + try { + const { checkInId, menteeId, mentorFeedback, isCheckedByMentor } = req.body + + console.log(menteeId, checkInId) + + const newMentorFeedbackCheckIn = await addMentorFeedbackMonthlyCheckIn( + checkInId, + menteeId, + mentorFeedback, + isCheckedByMentor + ) + + res.status(201).json({ + feedbackCheckIn: newMentorFeedbackCheckIn, + message: 'Mentor Feedback added successfully' + }) + } catch (err) { + if (err instanceof Error) { + console.error('Error executing query', err) + res + .status(500) + .json({ error: 'Internal server error', message: err.message }) + } + throw err + } +} diff --git a/src/routes/mentee/mentee.route.ts b/src/routes/mentee/mentee.route.ts index b58efa72..b63a22f9 100644 --- a/src/routes/mentee/mentee.route.ts +++ b/src/routes/mentee/mentee.route.ts @@ -14,6 +14,7 @@ import { updateMenteeStatusSchema } from '../../schemas/mentee-routes.schemas' import { + addFeedbackMonthlyCheckIn, getMonthlyCheckIns, postMonthlyCheckIn } from '../../controllers/monthlyChecking.controller' @@ -41,4 +42,7 @@ menteeRouter.post( ) menteeRouter.get('/checkin/:menteeId', requireAuth, getMonthlyCheckIns) + +menteeRouter.put('/checking/feedback', requireAuth, addFeedbackMonthlyCheckIn) + export default menteeRouter diff --git a/src/services/monthlyChecking.service.ts b/src/services/monthlyChecking.service.ts new file mode 100644 index 00000000..c1174a13 --- /dev/null +++ b/src/services/monthlyChecking.service.ts @@ -0,0 +1,49 @@ +import { dataSource } from '../configs/dbConfig' +import MonthlyCheckIn from '../entities/checkin.entity' +import Mentee from '../entities/mentee.entity' + +export const addMentorFeedbackMonthlyCheckIn = async ( + menteeId: string, + checkInId: string, + mentorfeedback: string, + isCheckedByMentor: boolean +): Promise<{ + statusCode: number + message: string +}> => { + try { + const menteeRepository = dataSource.getRepository(Mentee) + const checkInRepository = dataSource.getRepository(MonthlyCheckIn) + + const mentee = await menteeRepository.findOne({ + where: { uuid: menteeId } + }) + console.log(menteeId) + + if (!mentee) { + return { statusCode: 404, message: 'Mentee not found' } + } + console.log(mentee) + + const checkIn = await checkInRepository.findOne({ + where: { uuid: checkInId, mentee: { uuid: menteeId } } + }) + + if (!checkIn) { + return { statusCode: 404, message: 'Check-in not found' } + } + + console.log(checkIn) + + checkIn.mentorFeedback = mentorfeedback + checkIn.isCheckedByMentor = isCheckedByMentor + checkIn.mentorCheckedDate = new Date() + + await checkInRepository.save(checkIn) + + return { statusCode: 200, message: 'feedback added' } + } catch (err) { + console.error('Error in addFeedbackToMonthlyCheckIn', err) + return { statusCode: 500, message: 'Internal server error' } + } +} From b878909aad4613300719b986eb15d54a36fc3a7d Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Fri, 27 Sep 2024 23:20:28 +0530 Subject: [PATCH 08/14] Refactor Mentee service to include MonthlyCheckIn feedback functionality --- src/controllers/monthlyChecking.controller.ts | 22 ++++-------- src/entities/checkin.entity.ts | 5 --- src/routes/mentee/mentee.route.ts | 7 +++- src/schemas/mentee-routes.schemas.ts | 11 ++++-- src/services/mentee.service.ts | 35 +++++++++++++++---- src/services/monthlyChecking.service.ts | 4 --- 6 files changed, 51 insertions(+), 33 deletions(-) diff --git a/src/controllers/monthlyChecking.controller.ts b/src/controllers/monthlyChecking.controller.ts index 0207a028..e9cec1c3 100644 --- a/src/controllers/monthlyChecking.controller.ts +++ b/src/controllers/monthlyChecking.controller.ts @@ -10,35 +10,31 @@ import { addMentorFeedbackMonthlyCheckIn } from '../services/monthlyChecking.ser export const postMonthlyCheckIn = async ( req: Request, res: Response -): Promise => { +): Promise>> => { try { const { menteeId, title, generalUpdatesAndFeedback, progressTowardsGoals, - mediaContentLinks, - tags + mediaContentLinks } = req.body - console.log(menteeId) - const newCheckIn = await addMonthlyCheckIn( menteeId, title, generalUpdatesAndFeedback, progressTowardsGoals, - mediaContentLinks, - tags + mediaContentLinks ) - res + return res .status(201) .json({ checkIn: newCheckIn, message: 'Check-in added successfully' }) } catch (err) { if (err instanceof Error) { console.error('Error executing query', err) - res + return res .status(500) .json({ error: 'Internal server error', message: err.message }) } @@ -53,7 +49,6 @@ export const getMonthlyCheckIns = async ( try { const { menteeId } = req.params - console.log('menteeId', menteeId) const { statusCode, checkIns, message } = await fetchMonthlyCheckIns( menteeId ) @@ -77,18 +72,15 @@ export const addFeedbackMonthlyCheckIn = async ( try { const { checkInId, menteeId, mentorFeedback, isCheckedByMentor } = req.body - console.log(menteeId, checkInId) - const newMentorFeedbackCheckIn = await addMentorFeedbackMonthlyCheckIn( - checkInId, menteeId, + checkInId, mentorFeedback, isCheckedByMentor ) res.status(201).json({ - feedbackCheckIn: newMentorFeedbackCheckIn, - message: 'Mentor Feedback added successfully' + feedbackCheckIn: newMentorFeedbackCheckIn }) } catch (err) { if (err instanceof Error) { diff --git a/src/entities/checkin.entity.ts b/src/entities/checkin.entity.ts index 0f70044b..31693ad9 100644 --- a/src/entities/checkin.entity.ts +++ b/src/entities/checkin.entity.ts @@ -16,9 +16,6 @@ class MonthlyCheckIn extends BaseEntity { @Column({ type: 'json' }) mediaContentLinks: string[] - @Column({ type: 'json', nullable: true }) - tags: string[] - @Column({ type: 'text', nullable: true }) mentorFeedback: string @@ -41,7 +38,6 @@ class MonthlyCheckIn extends BaseEntity { progressTowardsGoals: string, mediaContentLinks: string[], mentorFeedback: string, - tags: string[], isCheckedByMentor: boolean, mentorCheckedDate: Date, checkInDate: Date, @@ -52,7 +48,6 @@ class MonthlyCheckIn extends BaseEntity { this.generalUpdatesAndFeedback = generalUpdatesAndFeedback this.progressTowardsGoals = progressTowardsGoals this.mediaContentLinks = mediaContentLinks - this.tags = tags this.mentorFeedback = mentorFeedback this.isCheckedByMentor = isCheckedByMentor this.mentorCheckedDate = mentorCheckedDate diff --git a/src/routes/mentee/mentee.route.ts b/src/routes/mentee/mentee.route.ts index b63a22f9..bf6e731f 100644 --- a/src/routes/mentee/mentee.route.ts +++ b/src/routes/mentee/mentee.route.ts @@ -9,6 +9,7 @@ import { } from '../../controllers/mentee.controller' import { requestBodyValidator } from '../../middlewares/requestValidator' import { + addFeedbackMonthlyCheckInSchema, menteeApplicationSchema, postMonthlyCheckInSchema, updateMenteeStatusSchema @@ -43,6 +44,10 @@ menteeRouter.post( menteeRouter.get('/checkin/:menteeId', requireAuth, getMonthlyCheckIns) -menteeRouter.put('/checking/feedback', requireAuth, addFeedbackMonthlyCheckIn) +menteeRouter.put( + '/checking/feedback', + [requireAuth, requestBodyValidator(addFeedbackMonthlyCheckInSchema)], + addFeedbackMonthlyCheckIn +) export default menteeRouter diff --git a/src/schemas/mentee-routes.schemas.ts b/src/schemas/mentee-routes.schemas.ts index 49f7325d..6cf53ccd 100644 --- a/src/schemas/mentee-routes.schemas.ts +++ b/src/schemas/mentee-routes.schemas.ts @@ -11,6 +11,7 @@ export const updateMenteeStatusSchema = z.object({ }) export const postMonthlyCheckInSchema = z.object({ + menteeId: z.string(), title: z.enum([ 'January', 'February', @@ -33,6 +34,12 @@ export const postMonthlyCheckInSchema = z.object({ .min(1, 'Please provide a valid progress report'), mediaContentLinks: z .array(z.string()) - .min(3, 'Please provide at least 3 media content links'), - tags: z.array(z.string()).min(1, 'Please provide at least 1 tag') + .min(3, 'Please provide at least 3 media content links') +}) + +export const addFeedbackMonthlyCheckInSchema = z.object({ + menteeId: z.string(), + checkInId: z.string(), + mentorFeedback: z.string().min(1, 'Please provide a valid feedback'), + isCheckedByMentor: z.boolean() }) diff --git a/src/services/mentee.service.ts b/src/services/mentee.service.ts index 5c665bdd..b34ed553 100644 --- a/src/services/mentee.service.ts +++ b/src/services/mentee.service.ts @@ -168,8 +168,7 @@ export const addMonthlyCheckIn = async ( title: string, generalUpdatesAndFeedback: string, progressTowardsGoals: string, - mediaContentLinks: string[], - tags: string[] + mediaContentLinks: string[] ): Promise<{ statusCode: number message: string @@ -197,7 +196,6 @@ export const addMonthlyCheckIn = async ( generalUpdatesAndFeedback, progressTowardsGoals, mediaContentLinks, - tags, checkInDate: new Date(), mentee }) @@ -216,7 +214,18 @@ export const fetchMonthlyCheckIns = async ( menteeId: string ): Promise<{ statusCode: number - checkIns: MonthlyCheckIn[] + checkIns: Array<{ + uuid: string + title: string + generalUpdatesAndFeedback: string + progressTowardsGoals: string + mediaContentLinks: string[] + mentorFeedback: string | null + isCheckedByMentor: boolean + mentorCheckedDate: Date | null + checkInDate: Date + mentee: Mentee + }> message: string }> => { try { @@ -244,12 +253,26 @@ export const fetchMonthlyCheckIns = async ( } } + const checkInsWithUuid = checkIns.map((checkIn) => ({ + uuid: checkIn.uuid, + title: checkIn.title, + generalUpdatesAndFeedback: checkIn.generalUpdatesAndFeedback, + progressTowardsGoals: checkIn.progressTowardsGoals, + mediaContentLinks: checkIn.mediaContentLinks, + mentorFeedback: checkIn.mentorFeedback, + isCheckedByMentor: checkIn.isCheckedByMentor, + mentorCheckedDate: checkIn.mentorCheckedDate, + checkInDate: checkIn.checkInDate, + mentee: checkIn.mentee + })) + return { statusCode: 200, - checkIns, + checkIns: checkInsWithUuid, message: 'Check-ins found' } } catch (err) { - throw new Error('Error getting check-ins') + console.error('Error in fetchMonthlyCheckIns', err) + return { statusCode: 500, checkIns: [], message: 'Internal server error' } } } diff --git a/src/services/monthlyChecking.service.ts b/src/services/monthlyChecking.service.ts index c1174a13..2881c158 100644 --- a/src/services/monthlyChecking.service.ts +++ b/src/services/monthlyChecking.service.ts @@ -18,12 +18,10 @@ export const addMentorFeedbackMonthlyCheckIn = async ( const mentee = await menteeRepository.findOne({ where: { uuid: menteeId } }) - console.log(menteeId) if (!mentee) { return { statusCode: 404, message: 'Mentee not found' } } - console.log(mentee) const checkIn = await checkInRepository.findOne({ where: { uuid: checkInId, mentee: { uuid: menteeId } } @@ -33,8 +31,6 @@ export const addMentorFeedbackMonthlyCheckIn = async ( return { statusCode: 404, message: 'Check-in not found' } } - console.log(checkIn) - checkIn.mentorFeedback = mentorfeedback checkIn.isCheckedByMentor = isCheckedByMentor checkIn.mentorCheckedDate = new Date() From d31bb0e3a7aded0c9dd494779ad1698287445721 Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Fri, 27 Sep 2024 23:27:22 +0530 Subject: [PATCH 09/14] Refactor Mentee service to include MonthlyCheckIn feedback functionality --- src/controllers/monthlyChecking.controller.ts | 15 +-- src/services/mentee.service.ts | 117 +----------------- src/services/monthlyChecking.service.ts | 116 ++++++++++++++++- 3 files changed, 124 insertions(+), 124 deletions(-) diff --git a/src/controllers/monthlyChecking.controller.ts b/src/controllers/monthlyChecking.controller.ts index e9cec1c3..bb6ed6ef 100644 --- a/src/controllers/monthlyChecking.controller.ts +++ b/src/controllers/monthlyChecking.controller.ts @@ -1,11 +1,12 @@ import type { Request, Response } from 'express' import { type ApiResponse } from '../types' -import { - fetchMonthlyCheckIns, - addMonthlyCheckIn -} from '../services/mentee.service' import type MonthlyCheckIn from '../entities/checkin.entity' -import { addMentorFeedbackMonthlyCheckIn } from '../services/monthlyChecking.service' + +import { + addFeedbackByMentor, + addMonthlyCheckInByMentee, + fetchMonthlyCheckIns +} from '../services/monthlyChecking.service' export const postMonthlyCheckIn = async ( req: Request, @@ -20,7 +21,7 @@ export const postMonthlyCheckIn = async ( mediaContentLinks } = req.body - const newCheckIn = await addMonthlyCheckIn( + const newCheckIn = await addMonthlyCheckInByMentee( menteeId, title, generalUpdatesAndFeedback, @@ -72,7 +73,7 @@ export const addFeedbackMonthlyCheckIn = async ( try { const { checkInId, menteeId, mentorFeedback, isCheckedByMentor } = req.body - const newMentorFeedbackCheckIn = await addMentorFeedbackMonthlyCheckIn( + const newMentorFeedbackCheckIn = await addFeedbackByMentor( menteeId, checkInId, mentorFeedback, diff --git a/src/services/mentee.service.ts b/src/services/mentee.service.ts index b34ed553..7f4ca1bf 100644 --- a/src/services/mentee.service.ts +++ b/src/services/mentee.service.ts @@ -1,5 +1,4 @@ import { dataSource } from '../configs/dbConfig' -import MonthlyCheckIn from '../entities/checkin.entity' import Mentee from '../entities/mentee.entity' import Mentor from '../entities/mentor.entity' import type Profile from '../entities/profile.entity' @@ -158,121 +157,7 @@ export const getPublicMentee = async ( mentee: publicMentee, message: 'Mentees found' } - } catch (err) { + } catch (err) {MonthlyCheckIn throw new Error('Error getting mentees') } } - -export const addMonthlyCheckIn = async ( - menteeId: string, - title: string, - generalUpdatesAndFeedback: string, - progressTowardsGoals: string, - mediaContentLinks: string[] -): Promise<{ - statusCode: number - message: string -}> => { - try { - const menteeRepository = dataSource.getRepository(Mentee) - const checkInRepository = dataSource.getRepository(MonthlyCheckIn) - - console.log(menteeId) - - const mentee = await menteeRepository.findOne({ - where: { - uuid: menteeId - } - }) - - console.log(mentee) - - if (!mentee) { - return { statusCode: 404, message: 'Mentee not found' } - } - - const newCheckIn = checkInRepository.create({ - title, - generalUpdatesAndFeedback, - progressTowardsGoals, - mediaContentLinks, - checkInDate: new Date(), - mentee - }) - - console.log(newCheckIn) - await checkInRepository.save(newCheckIn) - - return { statusCode: 200, message: 'monthly checking inserted' } - } catch (err) { - console.error('Error in addMonthlyCheckIn', err) - throw new Error('Error in addMonthlyCheckIn') - } -} - -export const fetchMonthlyCheckIns = async ( - menteeId: string -): Promise<{ - statusCode: number - checkIns: Array<{ - uuid: string - title: string - generalUpdatesAndFeedback: string - progressTowardsGoals: string - mediaContentLinks: string[] - mentorFeedback: string | null - isCheckedByMentor: boolean - mentorCheckedDate: Date | null - checkInDate: Date - mentee: Mentee - }> - message: string -}> => { - try { - const checkInRepository = dataSource.getRepository(MonthlyCheckIn) - - const mentee = await dataSource.getRepository(Mentee).findOne({ - where: { uuid: menteeId } - }) - - if (!mentee) { - return { statusCode: 404, checkIns: [], message: 'Mentee not found' } - } - - const checkIns = await checkInRepository.find({ - where: { mentee: { uuid: menteeId } }, - relations: ['mentee'], - order: { checkInDate: 'DESC' } - }) - - if (checkIns.length === 0) { - return { - statusCode: 404, - checkIns: [], - message: 'No check-ins found' - } - } - - const checkInsWithUuid = checkIns.map((checkIn) => ({ - uuid: checkIn.uuid, - title: checkIn.title, - generalUpdatesAndFeedback: checkIn.generalUpdatesAndFeedback, - progressTowardsGoals: checkIn.progressTowardsGoals, - mediaContentLinks: checkIn.mediaContentLinks, - mentorFeedback: checkIn.mentorFeedback, - isCheckedByMentor: checkIn.isCheckedByMentor, - mentorCheckedDate: checkIn.mentorCheckedDate, - checkInDate: checkIn.checkInDate, - mentee: checkIn.mentee - })) - - return { - statusCode: 200, - checkIns: checkInsWithUuid, - message: 'Check-ins found' - } - } catch (err) { - console.error('Error in fetchMonthlyCheckIns', err) - return { statusCode: 500, checkIns: [], message: 'Internal server error' } - } -} diff --git a/src/services/monthlyChecking.service.ts b/src/services/monthlyChecking.service.ts index 2881c158..b7d9ab3c 100644 --- a/src/services/monthlyChecking.service.ts +++ b/src/services/monthlyChecking.service.ts @@ -2,7 +2,7 @@ import { dataSource } from '../configs/dbConfig' import MonthlyCheckIn from '../entities/checkin.entity' import Mentee from '../entities/mentee.entity' -export const addMentorFeedbackMonthlyCheckIn = async ( +export const addFeedbackByMentor = async ( menteeId: string, checkInId: string, mentorfeedback: string, @@ -43,3 +43,117 @@ export const addMentorFeedbackMonthlyCheckIn = async ( return { statusCode: 500, message: 'Internal server error' } } } + +export const addMonthlyCheckInByMentee = async ( + menteeId: string, + title: string, + generalUpdatesAndFeedback: string, + progressTowardsGoals: string, + mediaContentLinks: string[] +): Promise<{ + statusCode: number + message: string +}> => { + try { + const menteeRepository = dataSource.getRepository(Mentee) + const checkInRepository = dataSource.getRepository(MonthlyCheckIn) + + console.log(menteeId) + + const mentee = await menteeRepository.findOne({ + where: { + uuid: menteeId + } + }) + + console.log(mentee) + + if (!mentee) { + return { statusCode: 404, message: 'Mentee not found' } + } + + const newCheckIn = checkInRepository.create({ + title, + generalUpdatesAndFeedback, + progressTowardsGoals, + mediaContentLinks, + checkInDate: new Date(), + mentee + }) + + console.log(newCheckIn) + await checkInRepository.save(newCheckIn) + + return { statusCode: 200, message: 'monthly checking inserted' } + } catch (err) { + console.error('Error in addMonthlyCheckIn', err) + throw new Error('Error in addMonthlyCheckIn') + } +} + +export const fetchMonthlyCheckIns = async ( + menteeId: string +): Promise<{ + statusCode: number + checkIns: Array<{ + uuid: string + title: string + generalUpdatesAndFeedback: string + progressTowardsGoals: string + mediaContentLinks: string[] + mentorFeedback: string | null + isCheckedByMentor: boolean + mentorCheckedDate: Date | null + checkInDate: Date + mentee: Mentee + }> + message: string +}> => { + try { + const checkInRepository = dataSource.getRepository(MonthlyCheckIn) + + const mentee = await dataSource.getRepository(Mentee).findOne({ + where: { uuid: menteeId } + }) + + if (!mentee) { + return { statusCode: 404, checkIns: [], message: 'Mentee not found' } + } + + const checkIns = await checkInRepository.find({ + where: { mentee: { uuid: menteeId } }, + relations: ['mentee'], + order: { checkInDate: 'DESC' } + }) + + if (checkIns.length === 0) { + return { + statusCode: 404, + checkIns: [], + message: 'No check-ins found' + } + } + + const checkInsWithUuid = checkIns.map((checkIn) => ({ + uuid: checkIn.uuid, + title: checkIn.title, + generalUpdatesAndFeedback: checkIn.generalUpdatesAndFeedback, + progressTowardsGoals: checkIn.progressTowardsGoals, + mediaContentLinks: checkIn.mediaContentLinks, + mentorFeedback: checkIn.mentorFeedback, + isCheckedByMentor: checkIn.isCheckedByMentor, + mentorCheckedDate: checkIn.mentorCheckedDate, + checkInDate: checkIn.checkInDate, + mentee: checkIn.mentee + })) + + return { + statusCode: 200, + checkIns: checkInsWithUuid, + message: 'Check-ins found' + } + } catch (err) { + console.error('Error in fetchMonthlyCheckIns', err) + return { statusCode: 500, checkIns: [], message: 'Internal server error' } + } +} From d738745beb943f26bcaab15d3e8205c4259b50f8 Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Fri, 27 Sep 2024 23:28:00 +0530 Subject: [PATCH 10/14] Refactor Mentee service to remove unnecessary code --- src/services/mentee.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/mentee.service.ts b/src/services/mentee.service.ts index 7f4ca1bf..d16c8541 100644 --- a/src/services/mentee.service.ts +++ b/src/services/mentee.service.ts @@ -157,7 +157,7 @@ export const getPublicMentee = async ( mentee: publicMentee, message: 'Mentees found' } - } catch (err) {MonthlyCheckIn + } catch (err) { throw new Error('Error getting mentees') } } From 368a7f9f6a59dc61e6f2f1a19c926ec248f684e0 Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Sun, 29 Sep 2024 15:34:02 +0530 Subject: [PATCH 11/14] Refactor: Separate Monthly Checking Services and Controllers - Moved monthly checking service functions to a dedicated service file (monthlyChecking.service.ts). - Moved monthly checking controller functions to a dedicated controller file (monthlyChecking.controller.ts). - Updated import paths and references to reflect the new file structure. - Improved code organization and maintainability by separating concerns. --- src/schemas/mentee-routes.schemas.ts | 4 ++-- src/services/monthlyChecking.service.ts | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/schemas/mentee-routes.schemas.ts b/src/schemas/mentee-routes.schemas.ts index 6cf53ccd..072e7a18 100644 --- a/src/schemas/mentee-routes.schemas.ts +++ b/src/schemas/mentee-routes.schemas.ts @@ -34,12 +34,12 @@ export const postMonthlyCheckInSchema = z.object({ .min(1, 'Please provide a valid progress report'), mediaContentLinks: z .array(z.string()) - .min(3, 'Please provide at least 3 media content links') + .min(1, 'Please provide at least 1 media content links') }) export const addFeedbackMonthlyCheckInSchema = z.object({ menteeId: z.string(), checkInId: z.string(), - mentorFeedback: z.string().min(1, 'Please provide a valid feedback'), + mentorFeedback: z.string().min(5, 'Please provide a valid feedback'), isCheckedByMentor: z.boolean() }) diff --git a/src/services/monthlyChecking.service.ts b/src/services/monthlyChecking.service.ts index b7d9ab3c..2ae67a18 100644 --- a/src/services/monthlyChecking.service.ts +++ b/src/services/monthlyChecking.service.ts @@ -58,16 +58,12 @@ export const addMonthlyCheckInByMentee = async ( const menteeRepository = dataSource.getRepository(Mentee) const checkInRepository = dataSource.getRepository(MonthlyCheckIn) - console.log(menteeId) - const mentee = await menteeRepository.findOne({ where: { uuid: menteeId } }) - console.log(mentee) - if (!mentee) { return { statusCode: 404, message: 'Mentee not found' } } @@ -81,7 +77,6 @@ export const addMonthlyCheckInByMentee = async ( mentee }) - console.log(newCheckIn) await checkInRepository.save(newCheckIn) return { statusCode: 200, message: 'monthly checking inserted' } @@ -126,7 +121,7 @@ export const fetchMonthlyCheckIns = async ( order: { checkInDate: 'DESC' } }) - if (checkIns.length === 0) { + if (checkIns.length === 0 || !checkIns) { return { statusCode: 404, checkIns: [], From cedd5cdf02296141f7069ac3696135b4f5b97de2 Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Sun, 29 Sep 2024 21:55:55 +0530 Subject: [PATCH 12/14] removed sudo file --- sudo | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 sudo diff --git a/sudo b/sudo deleted file mode 100644 index e69de29b..00000000 From 87a7e02ca167940a86e69deaddc58ac5f5ec5451 Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Mon, 30 Sep 2024 00:33:57 +0530 Subject: [PATCH 13/14] Refactor: Make mentor feedback optional in addFeedbackMonthlyCheckInSchema --- src/schemas/mentee-routes.schemas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/schemas/mentee-routes.schemas.ts b/src/schemas/mentee-routes.schemas.ts index 072e7a18..4069319f 100644 --- a/src/schemas/mentee-routes.schemas.ts +++ b/src/schemas/mentee-routes.schemas.ts @@ -40,6 +40,6 @@ export const postMonthlyCheckInSchema = z.object({ export const addFeedbackMonthlyCheckInSchema = z.object({ menteeId: z.string(), checkInId: z.string(), - mentorFeedback: z.string().min(5, 'Please provide a valid feedback'), + mentorFeedback: z.string().optional(), isCheckedByMentor: z.boolean() }) From 7d6395c49b068689bd2f5aeaf53e4ef4dea30d12 Mon Sep 17 00:00:00 2001 From: mayura-andrew Date: Sun, 6 Oct 2024 22:43:56 +0530 Subject: [PATCH 14/14] Refactor MonthlyChecking service to include MonthlyCheckInResponse type --- .../1727636762101-monthlychecking.ts | 13 +++++++++ src/services/monthlyChecking.service.ts | 29 ++----------------- src/types.ts | 15 ++++++++++ 3 files changed, 31 insertions(+), 26 deletions(-) create mode 100644 src/migrations/1727636762101-monthlychecking.ts diff --git a/src/migrations/1727636762101-monthlychecking.ts b/src/migrations/1727636762101-monthlychecking.ts new file mode 100644 index 00000000..030e5fbc --- /dev/null +++ b/src/migrations/1727636762101-monthlychecking.ts @@ -0,0 +1,13 @@ +import { type MigrationInterface, type QueryRunner } from 'typeorm' + +export class Monthlychecking1727636762101 implements MigrationInterface { + name = 'Monthlychecking1727636762101' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "monthly-check-in" DROP COLUMN "tags"`) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "monthly-check-in" ADD "tags" json`) + } +} diff --git a/src/services/monthlyChecking.service.ts b/src/services/monthlyChecking.service.ts index 2ae67a18..6fe1fc8e 100644 --- a/src/services/monthlyChecking.service.ts +++ b/src/services/monthlyChecking.service.ts @@ -1,6 +1,7 @@ import { dataSource } from '../configs/dbConfig' import MonthlyCheckIn from '../entities/checkin.entity' import Mentee from '../entities/mentee.entity' +import { type MonthlyCheckInResponse } from '../types' export const addFeedbackByMentor = async ( menteeId: string, @@ -90,18 +91,7 @@ export const fetchMonthlyCheckIns = async ( menteeId: string ): Promise<{ statusCode: number - checkIns: Array<{ - uuid: string - title: string - generalUpdatesAndFeedback: string - progressTowardsGoals: string - mediaContentLinks: string[] - mentorFeedback: string | null - isCheckedByMentor: boolean - mentorCheckedDate: Date | null - checkInDate: Date - mentee: Mentee - }> + checkIns: MonthlyCheckInResponse[] message: string }> => { try { @@ -129,22 +119,9 @@ export const fetchMonthlyCheckIns = async ( } } - const checkInsWithUuid = checkIns.map((checkIn) => ({ - uuid: checkIn.uuid, - title: checkIn.title, - generalUpdatesAndFeedback: checkIn.generalUpdatesAndFeedback, - progressTowardsGoals: checkIn.progressTowardsGoals, - mediaContentLinks: checkIn.mediaContentLinks, - mentorFeedback: checkIn.mentorFeedback, - isCheckedByMentor: checkIn.isCheckedByMentor, - mentorCheckedDate: checkIn.mentorCheckedDate, - checkInDate: checkIn.checkInDate, - mentee: checkIn.mentee - })) - return { statusCode: 200, - checkIns: checkInsWithUuid, + checkIns, message: 'Check-ins found' } } catch (err) { diff --git a/src/types.ts b/src/types.ts index b5e27a78..8c39f185 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,5 @@ +import type Mentee from './entities/mentee.entity' + export interface ApiResponse { statusCode: number message?: string @@ -32,3 +34,16 @@ export interface LinkedInProfile { picture: string email: string } + +export interface MonthlyCheckInResponse { + uuid: string + title: string + generalUpdatesAndFeedback: string + progressTowardsGoals: string + mediaContentLinks: string[] + mentorFeedback: string | null + isCheckedByMentor: boolean + mentorCheckedDate: Date | null + checkInDate: Date + mentee: Mentee +}