From 2e1f6e141b618c88a5ccebcdf606db661b1d5faf Mon Sep 17 00:00:00 2001 From: MaryammAli Date: Sat, 26 Sep 2026 19:52:34 +0100 Subject: [PATCH] Revert "Feat/tutor verification workflow" --- .../src/modules/courses/courses.controller.ts | 35 -------- .../src/modules/courses/courses.service.ts | 80 ------------------- .../modules/courses/dto/create-course.dto.ts | 30 ------- .../tutors/dto/tutor-application.dto.ts | 12 --- .../src/modules/tutors/tutors.controller.ts | 30 ------- .../src/modules/tutors/tutors.service.ts | 53 ------------ .../modules/users/dto/learner-profile.dto.ts | 13 --- .../modules/users/dto/update-profile.dto.ts | 23 ------ .../src/modules/users/users.controller.ts | 25 ------ .../src/modules/users/users.service.ts | 56 ------------- 10 files changed, 357 deletions(-) delete mode 100644 app/backend/src/modules/courses/courses.controller.ts delete mode 100644 app/backend/src/modules/courses/courses.service.ts delete mode 100644 app/backend/src/modules/courses/dto/create-course.dto.ts delete mode 100644 app/backend/src/modules/tutors/dto/tutor-application.dto.ts delete mode 100644 app/backend/src/modules/tutors/tutors.controller.ts delete mode 100644 app/backend/src/modules/tutors/tutors.service.ts delete mode 100644 app/backend/src/modules/users/dto/learner-profile.dto.ts delete mode 100644 app/backend/src/modules/users/dto/update-profile.dto.ts delete mode 100644 app/backend/src/modules/users/users.controller.ts delete mode 100644 app/backend/src/modules/users/users.service.ts diff --git a/app/backend/src/modules/courses/courses.controller.ts b/app/backend/src/modules/courses/courses.controller.ts deleted file mode 100644 index b886493912..0000000000 --- a/app/backend/src/modules/courses/courses.controller.ts +++ /dev/null @@ -1,35 +0,0 @@ -// src/modules/courses/courses.controller.ts -import { Controller, Get, Post, Delete, Body, Param, Query, UseGuards, Req } from '@nestjs/common'; -import { CoursesService, CourseFilterQuery } from './courses.service'; -import { CreateCourseDto, CourseLevel } from './dto/create-course.dto'; - -@Controller('api/v1/courses') -export class CoursesController { - constructor(private readonly coursesService: CoursesService) {} - - @Post() - async create(@Req() req: any, @Body() dto: CreateCourseDto) { - const tutorId = req.user?.id || 'mock-tutor-id'; // Auth guard context - return this.coursesService.createCourse(tutorId, dto); - } - - @Get() - async getCatalog( - @Query('level') level?: CourseLevel, - @Query('tag') tag?: string, - @Query('search') search?: string, - ) { - return this.coursesService.getCatalog({ level, tag, search }); - } - - @Get(':id') - async getDetail(@Param('id') id: string) { - return this.coursesService.getCourseDetail(id); - } - - @Delete(':id') - async remove(@Req() req: any, @Param('id') id: string) { - const tutorId = req.user?.id || 'mock-tutor-id'; - return this.coursesService.deleteCourse(tutorId, id); - } -} \ No newline at end of file diff --git a/app/backend/src/modules/courses/courses.service.ts b/app/backend/src/modules/courses/courses.service.ts deleted file mode 100644 index 3a403904ae..0000000000 --- a/app/backend/src/modules/courses/courses.service.ts +++ /dev/null @@ -1,80 +0,0 @@ -// src/modules/courses/courses.service.ts -import { Injectable, NotFoundException, ForbiddenException } from '@nestjs/common'; -import { PrismaService } from '../../database/prisma.service'; -import { CreateCourseDto, CourseLevel } from './dto/create-course.dto'; - -export interface CourseFilterQuery { - level?: CourseLevel; - tag?: string; - search?: string; -} - -@Injectable() -export class CoursesService { - constructor(private readonly prisma: PrismaService) {} - - async createCourse(tutorId: string, dto: CreateCourseDto) { - return this.prisma.course.create({ - data: { - title: dto.title, - description: dto.description, - level: dto.level, - tags: dto.tags, - price: dto.price || 0, - tutorId, - }, - }); - } - - async getCatalog(query: CourseFilterQuery) { - const { level, tag, search } = query; - - return this.prisma.course.findMany({ - where: { - ...(level && { level }), - ...(tag && { tags: { has: tag } }), - ...(search && { - OR: [ - { title: { contains: search, mode: 'insensitive' } }, - { description: { contains: search, mode: 'insensitive' } }, - ], - }), - }, - include: { - tutor: { select: { id: true, username: true } }, - _count: { select: { lessons: true } }, - }, - orderBy: { createdAt: 'desc' }, - }); - } - - async getCourseDetail(courseId: string) { - const course = await this.prisma.course.findUnique({ - where: { id: courseId }, - include: { - tutor: { select: { id: true, username: true } }, - lessons: { - orderBy: { orderIndex: 'asc' }, - select: { id: true, title: true, orderIndex: true, durationMinutes: true }, - }, - }, - }); - - if (!course) { - throw new NotFoundException(`Course with ID ${courseId} not found`); - } - - return course; - } - - async deleteCourse(tutorId: string, courseId: string) { - const course = await this.prisma.course.findUnique({ where: { id: courseId } }); - if (!course) { - throw new NotFoundException(`Course not found`); - } - if (course.tutorId !== tutorId) { - throw new ForbiddenException(`Only the course owner can delete this course`); - } - return this.prisma.course.delete({ where: { id: courseId } }); - } -} \ No newline at end of file diff --git a/app/backend/src/modules/courses/dto/create-course.dto.ts b/app/backend/src/modules/courses/dto/create-course.dto.ts deleted file mode 100644 index 859a4a0919..0000000000 --- a/app/backend/src/modules/courses/dto/create-course.dto.ts +++ /dev/null @@ -1,30 +0,0 @@ -// src/modules/courses/dto/create-course.dto.ts -import { IsString, IsNotEmpty, IsEnum, IsArray, IsOptional, IsNumber, Min } from 'class-validator'; - -export enum CourseLevel { - BEGINNER = 'BEGINNER', - INTERMEDIATE = 'INTERMEDIATE', - ADVANCED = 'ADVANCED', -} - -export class CreateCourseDto { - @IsString() - @IsNotEmpty() - title: string; - - @IsString() - @IsNotEmpty() - description: string; - - @IsEnum(CourseLevel) - level: CourseLevel; - - @IsArray() - @IsString({ each: true }) - tags: string[]; - - @IsNumber() - @Min(0) - @IsOptional() - price?: number; -} \ No newline at end of file diff --git a/app/backend/src/modules/tutors/dto/tutor-application.dto.ts b/app/backend/src/modules/tutors/dto/tutor-application.dto.ts deleted file mode 100644 index 25a1e00588..0000000000 --- a/app/backend/src/modules/tutors/dto/tutor-application.dto.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { IsString, IsNotEmpty, IsUrl, MaxLength } from 'class-validator'; - -export class TutorApplicationDto { - @IsString() - @IsNotEmpty() - @MaxLength(1000) - statementOfExpertise: string; - - @IsUrl() - @IsNotEmpty() - sampleLessonUrl: string; -} \ No newline at end of file diff --git a/app/backend/src/modules/tutors/tutors.controller.ts b/app/backend/src/modules/tutors/tutors.controller.ts deleted file mode 100644 index 68604e2f4d..0000000000 --- a/app/backend/src/modules/tutors/tutors.controller.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Controller, Get, Post, Patch, Body, Param, Req, UseGuards } from '@nestjs/common'; -import { TutorsService } from './tutors.service'; -import { TutorApplicationDto } from './dto/tutor-application.dto'; - -@Controller('api/v1/tutors') -export class TutorsController { - constructor(private readonly tutorsService: TutorsService) {} - - @Post('apply') - async apply(@Req() req: any, @Body() dto: TutorApplicationDto) { - const userId = req.user?.id || 'mock-user-id'; - return this.tutorsService.applyForTutor(userId, dto); - } - - @Get('admin/pending') - async getPending(@Req() req: any) { - const adminId = req.user?.id || 'mock-admin-id'; - return this.tutorsService.getPendingApplications(adminId); - } - - @Patch('admin/review/:userId') - async review( - @Req() req: any, - @Param('userId') targetUserId: string, - @Body('approved') approved: boolean, - ) { - const adminId = req.user?.id || 'mock-admin-id'; - return this.tutorsService.reviewApplication(adminId, targetUserId, approved); - } -} \ No newline at end of file diff --git a/app/backend/src/modules/tutors/tutors.service.ts b/app/backend/src/modules/tutors/tutors.service.ts deleted file mode 100644 index 646e7f9ecd..0000000000 --- a/app/backend/src/modules/tutors/tutors.service.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Injectable, NotFoundException, BadRequestException, ForbiddenException } from '@nestjs/common'; -import { PrismaService } from '../../database/prisma.service'; -import { TutorApplicationDto } from './dto/tutor-application.dto'; - -@Injectable() -export class TutorsService { - constructor(private readonly prisma: PrismaService) {} - - async applyForTutor(userId: string, dto: TutorApplicationDto) { - const user = await this.prisma.user.findUnique({ where: { id: userId } }); - if (!user) { - throw new NotFoundException(`User not found`); - } - - if (user.isVerifiedTutor || user.tutorApplicationStatus === 'PENDING') { - throw new BadRequestException('User is already a verified tutor or has a pending application.'); - } - - return this.prisma.user.update({ - where: { id: userId }, - data: { - tutorApplicationStatus: 'PENDING', - statementOfExpertise: dto.statementOfExpertise, - sampleLessonUrl: dto.sampleLessonUrl, - }, - select: { id: true, tutorApplicationStatus: true }, - }); - } - - async getPendingApplications(adminId: string) { - // Admin authorization check omitted for brevity - return this.prisma.user.findMany({ - where: { tutorApplicationStatus: 'PENDING' }, - select: { id: true, username: true, walletAddress: true, statementOfExpertise: true, sampleLessonUrl: true, createdAt: true }, - }); - } - - async reviewApplication(adminId: string, targetUserId: string, approved: boolean) { - const targetUser = await this.prisma.user.findUnique({ where: { id: targetUserId } }); - if (!targetUser || targetUser.tutorApplicationStatus !== 'PENDING') { - throw new NotFoundException('Pending tutor application not found'); - } - - return this.prisma.user.update({ - where: { id: targetUserId }, - data: { - isVerifiedTutor: approved, - tutorApplicationStatus: approved ? 'APPROVED' : 'REJECTED', - }, - select: { id: true, isVerifiedTutor: true, tutorApplicationStatus: true }, - }); - } -} \ No newline at end of file diff --git a/app/backend/src/modules/users/dto/learner-profile.dto.ts b/app/backend/src/modules/users/dto/learner-profile.dto.ts deleted file mode 100644 index 4ffba28779..0000000000 --- a/app/backend/src/modules/users/dto/learner-profile.dto.ts +++ /dev/null @@ -1,13 +0,0 @@ -// src/modules/users/dto/learner-profile.dto.ts -export interface LearnerProfileResponseDto { - id: string; - walletAddress: string; - username: string; - xp: number; - level: number; - currentStreak: number; - longestStreak: number; - totalCompletedLessons: number; - totalCompletedQuests: number; - updatedAt: string; -} \ No newline at end of file diff --git a/app/backend/src/modules/users/dto/update-profile.dto.ts b/app/backend/src/modules/users/dto/update-profile.dto.ts deleted file mode 100644 index 35e04e4c4b..0000000000 --- a/app/backend/src/modules/users/dto/update-profile.dto.ts +++ /dev/null @@ -1,23 +0,0 @@ -// src/modules/users/dto/update-profile.dto.ts -import { IsString, IsOptional, IsUrl, IsArray, MaxLength } from 'class-validator'; - -export class UpdateProfileDto { - @IsString() - @IsOptional() - @MaxLength(50) - displayName?: string; - - @IsString() - @IsOptional() - @MaxLength(500) - bio?: string; - - @IsUrl() - @IsOptional() - avatarUrl?: string; - - @IsArray() - @IsString({ each: true }) - @IsOptional() - specialties?: string[]; -} \ No newline at end of file diff --git a/app/backend/src/modules/users/users.controller.ts b/app/backend/src/modules/users/users.controller.ts deleted file mode 100644 index c9ac1c81e9..0000000000 --- a/app/backend/src/modules/users/users.controller.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Controller, Get, Patch, Body, Param, Req, UseGuards } from '@nestjs/common'; -import { UsersService } from './users.service'; -import { UpdateProfileDto } from './dto/update-profile.dto'; - -@Controller('api/v1/users') -export class UsersController { - constructor(private readonly usersService: UsersService) {} - - @Get('me') - async getMyProfile(@Req() req: any) { - const userId = req.user?.id || 'mock-user-id'; - return this.usersService.getPublicProfile(userId); - } - - @Patch('me') - async updateMyProfile(@Req() req: any, @Body() dto: UpdateProfileDto) { - const userId = req.user?.id || 'mock-user-id'; - return this.usersService.updateProfile(userId, dto); - } - - @Get(':id/public') - async getPublicProfile(@Param('id') id: string) { - return this.usersService.getPublicProfile(id); - } -} \ No newline at end of file diff --git a/app/backend/src/modules/users/users.service.ts b/app/backend/src/modules/users/users.service.ts deleted file mode 100644 index f02c6b4073..0000000000 --- a/app/backend/src/modules/users/users.service.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Injectable, NotFoundException, ForbiddenException } from '@nestjs/common'; -import { PrismaService } from '../../database/prisma.service'; -import { UpdateProfileDto } from './dto/update-profile.dto'; - -@Injectable() -export class UsersService { - constructor(private readonly prisma: PrismaService) {} - - async getPublicProfile(userId: string) { - const user = await this.prisma.user.findUnique({ - where: { id: userId }, - select: { - id: true, - walletAddress: true, - displayName: true, - bio: true, - avatarUrl: true, - specialties: true, - createdAt: true, - }, - }); - - if (!user) { - throw new NotFoundException(`User profile with ID ${userId} not found`); - } - - return user; - } - - async updateProfile(userId: string, dto: UpdateProfileDto) { - const user = await this.prisma.user.findUnique({ where: { id: userId } }); - - if (!user) { - throw new NotFoundException(`User with ID ${userId} not found`); - } - - return this.prisma.user.update({ - where: { id: userId }, - data: { - ...(dto.displayName && { displayName: dto.displayName }), - ...(dto.bio !== undefined && { bio: dto.bio }), - ...(dto.avatarUrl !== undefined && { avatarUrl: dto.avatarUrl }), - ...(dto.specialties && { specialties: dto.specialties }), - }, - select: { - id: true, - walletAddress: true, - displayName: true, - bio: true, - avatarUrl: true, - specialties: true, - updatedAt: true, - }, - }); - } -} \ No newline at end of file