<file_sep>import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { MongooseModule } from '@nestjs/mongoose';
import { UserModule } from './../middleware/validation/user.module';
import { StudentTeacherModule } from './../schemas/student-teacher.module';
import { StudentModule } from './../schemas/student.module';
import { TeacherModule } from './../schemas/teacher.module';

@Module({
  imports: [
    StudentTeacherModule,
    TeacherModule,
    StudentModule,
    ConfigModule.forRoot(),
    MongooseModule.forRoot(
      `mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASS}@${process.env.DB_HOST}/${process.env.DB_NAME}?retryWrites=true&w=majority`,
    ),
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}
<file_sep>import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { User, UserSchema } from './user.schema';
import { VaildateUserService } from './vaildate-user.service';

@Module({
  providers: [VaildateUserService],
  imports: [
    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
  ],
  exports: [VaildateUserService],
})
export class UserModule {}
<file_sep>import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { StudentController } from 'src/controllers/students/student.controller';
import { UserModule } from 'src/middleware/validation/user.module';
import { ValidUserMiddleware } from 'src/middleware/validation/valid-user.middleware';
import { StudentService } from 'src/services/student.service';
import { Student, StudentSchema } from './student.schema';

@Module({
  controllers: [StudentController],
  providers: [StudentService],
  imports: [
    MongooseModule.forFeature([{ name: Student.name, schema: StudentSchema }]),
    UserModule,
  ],
  exports: [StudentService],
})
export class StudentModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(ValidUserMiddleware).forRoutes(StudentController);
  }
}
<file_sep>export class StudentDTO {
  name: string;
  teacher: string;
}

export class CreateStudentDTO extends StudentDTO {
  studentNumber: string;
}
<file_sep>import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  Param,
  Post,
  Put,
  Response,
} from '@nestjs/common';
import { StudentService } from 'src/services/student.service';
import { StudentDTO } from 'src/web/model/student.dto';
import * as bcrypt from 'bcrypt';

@Controller('students')
export class StudentController {
  constructor(private readonly studentService: StudentService) {}

  @Get()
  async getStudents() {
    return await this.studentService.getStudents();
  }

  @Get('/:id')
  async getStudentById(@Param('id') id: string, @Response() res) {
    const student = await this.studentService.getStudentById(id);

    console.log(student);

    if (student === null) {
      return res.status(404).send('Resource Not Found');
    }

    return res.json(student).end();
  }

  @Post()
  @HttpCode(201)
  async createStudent(@Body() studentDTO: StudentDTO) {
    return await this.studentService.createStudent(studentDTO);
  }

  @Put('/:id')
  async updateStudent(@Param('id') id: string, @Body() studentDTO: StudentDTO) {
    await this.studentService.updateStudent(id, studentDTO);
  }

  @Delete('/:id')
  async deleteStudent(@Param('id') id: string) {
    await this.studentService.deleteStudent(id);
  }
}
<file_sep>import { HttpException, Injectable, NestMiddleware } from '@nestjs/common';
import { NextFunction, Request, Response } from 'express';
import { VaildateUserService } from './vaildate-user.service';

@Injectable()
export class ValidUserMiddleware implements NestMiddleware {
  constructor(private readonly validateUserService: VaildateUserService) {}

  async use(req: Request, res: Response, next: NextFunction) {
    const isValidUser = await this.validateUserService.getUser(
      req.header('username'),
      req.header('password'),
    );

    if (isValidUser) {
      // console.log(user);
      next();
    } else {
      throw new HttpException('Invalid Autherization', 400);
    }
  }
}
<file_sep>import { StudentDTO } from 'src/web/model/student.dto';

export interface IStudentService<T> {
  getStudents(): Promise<T[]>;
  getStudentById(id: string): Promise<T>;
  createStudent(t: StudentDTO): Promise<T>;
  updateStudent(id: string, t: StudentDTO): Promise<void>;
  deleteStudent(id: string): Promise<void>;
}
<file_sep>import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type TeacherDocument = Teacher & Document;
@Schema({
  // timestamp: true
})
export class Teacher {
  @Prop({ required: true })
  name: string;

  @Prop()
  surname: string;
}

export const TeacherSchema = SchemaFactory.createForClass(Teacher);
<file_sep>/*
https://docs.nestjs.com/modules
*/

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { TeacherController } from 'src/controllers/teacher/teacher.controller';
import { TeacherService } from 'src/services/teacher.service';
import { Teacher, TeacherSchema } from './teacher.schema';

@Module({
  controllers: [TeacherController],
  providers: [TeacherService],
  imports: [
    MongooseModule.forFeature([{ name: Teacher.name, schema: TeacherSchema }]),
  ],
  exports: [TeacherService],
})
export class TeacherModule {}
<file_sep>import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { v4 as uuid } from 'uuid';
import { Teacher, TeacherDocument } from 'src/schemas/teacher.schema';
import { TeacherDTO } from 'src/web/model/teacher.dto';
import { ITeacherService } from './teacher.interface';

@Injectable()
export class TeacherService implements ITeacherService<Teacher, TeacherDTO> {
  constructor(
    @InjectModel(Teacher.name) private readonly model: Model<TeacherDocument>,
  ) {}

  async getTeachers(): Promise<Teacher[]> {
    return await this.model.find().exec();
  }

  async getTeacherById(id: string): Promise<Teacher> {
    return await this.model.findById(id).exec();
  }

  async createTeacher(teacherDTO: TeacherDTO): Promise<Teacher> {
    return await new this.model({
      id: uuid(),
      ...teacherDTO,
      createdDate: new Date().getTime(),
    }).save();
  }

  async updateTeacher(id: string, teacherDTO: TeacherDTO): Promise<void> {
    await this.model.findByIdAndUpdate(id, teacherDTO).exec();
  }

  async deleteTeacher(id: string): Promise<void> {
    await this.model.findByIdAndDelete(id).exec();
  }
}
<file_sep>import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Student, StudentDocument } from 'src/schemas/student.schema';
import { CreateStudentDTO, StudentDTO } from 'src/web/model/student.dto';
import { uuid } from 'uuidv4';
import { IStudentService } from './student.interface';

@Injectable()
export class StudentService implements IStudentService<Student> {
  constructor(
    @InjectModel(Student.name) private readonly model: Model<StudentDocument>,
  ) {}
  async getStudents(): Promise<Student[]> {
    return await this.model.find().exec();
  }

  async getStudentById(id: string): Promise<Student> {
    return await this.model.findById(id).exec();
  }

  async createStudent(studentDTO: StudentDTO): Promise<Student> {
    const newStudent: CreateStudentDTO = {
      ...studentDTO,
      studentNumber: uuid().toString(),
    };

    return await new this.model({
      ...newStudent,
      createdDate: new Date().getTime(),
    }).save();
  }

  async updateStudent(id: string, studentDTO: StudentDTO): Promise<void> {
    await this.model.findByIdAndUpdate(id, studentDTO).exec();
  }
  async deleteStudent(id: string): Promise<void> {
    await this.model.findByIdAndDelete(id).exec();
  }
}
<file_sep>import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  Param,
  Post,
  Put,
} from '@nestjs/common';
import { TeacherService } from 'src/services/teacher.service';
import { TeacherDTO } from 'src/web/model/teacher.dto';

@Controller('teachers')
export class TeacherController {
  constructor(private readonly teacherService: TeacherService) {}

  @Get()
  async getTeachers() {
    return await this.teacherService.getTeachers();
  }

  @Get('/:id')
  async getTeacherById(@Param('id') id: string) {
    return await this.teacherService.getTeacherById(id);
  }

  @Post()
  @HttpCode(201)
  async createTeacher(@Body() teachertDTO: TeacherDTO) {
    return await this.teacherService.createTeacher(teachertDTO);
  }

  @Put('/:id')
  async updateTeacher(@Param('id') id: string, @Body() teacherDTO: TeacherDTO) {
    await this.teacherService.updateTeacher(id, teacherDTO);
  }

  @Delete('/:id')
  async deleteTeacher(@Param('id') id: string) {
    await this.teacherService.deleteTeacher(id);
  }
}
<file_sep>import { Injectable } from '@nestjs/common';
import * as bcrypt from 'bcrypt';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { UserDTO } from './user.dto';
import { User, UserDocument } from './user.schema';

@Injectable()
export class VaildateUserService {
  constructor(
    @InjectModel(User.name) private readonly userModel: Model<UserDocument>,
  ) {}

  //todo Convert to token authentication
  async getUser(username: string, password: string): Promise<UserDTO> {
    const user = await this.userModel
      .findOne(
        { username: username },
        {
          _id: 0,
          email: 1,
          password: 1,
          username: 1,
          firstname: 1,
        },
      )
      .exec();

    return user && (await bcrypt.compare(password, user.password));
  }
}
<file_sep>import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type StudentDocument = Student & Document;
@Schema({
  // timestamp: true
})
export class Student {
  @Prop({ required: true })
  name: string;

  @Prop()
  teacher: string;

  @Prop({ required: true })
  studentNumber: string;

  @Prop({ required: true })
  createdDate: string;
}

export const StudentSchema = SchemaFactory.createForClass(Student);
<file_sep>import { Body, Controller, Get, Param, Put } from '@nestjs/common';
import { StudentTeacherService } from 'src/services/student-teacher.service';
import { StudentDTO } from 'src/web/model/student.dto';

@Controller('teachers/:id/students')
export class StudentController {
  constructor(private readonly studentTeacherService: StudentTeacherService) {}

  @Get()
  async getStudents(@Param('id') id: string) {
    return await this.studentTeacherService.getTeacherStudents(id);
  }

  @Put('/:studentId')
  async updateStudentById(@Param() params, @Body() studentDTO: StudentDTO) {
    await this.studentTeacherService.updateStudentByTeacherAndStudentId(
      params.id,
      params.studentId,
      studentDTO,
    );
  }
}
<file_sep>export interface ITeacherService<T, TDTO> {
  getTeachers(): Promise<T[]>;
  getTeacherById(id: string): Promise<T>;
  createTeacher(tDTO: TDTO): Promise<T>;
  updateTeacher(id: string, tDTO: TDTO): Promise<void>;
  deleteTeacher(id: string): Promise<void>;
}
<file_sep>import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Student, StudentDocument } from 'src/schemas/student.schema';
import { Teacher, TeacherDocument } from 'src/schemas/teacher.schema';
import { StudentDTO } from 'src/web/model/student.dto';

@Injectable()
export class StudentTeacherService {
  constructor(
    @InjectModel(Student.name)
    private readonly studentModel: Model<StudentDocument>,

    @InjectModel(Teacher.name)
    private readonly teacherModel: Model<TeacherDocument>,
  ) {}

  async getTeacherStudents(id: string): Promise<Student[]> {
    const teacher = await this.teacherModel.findById(id).exec();

    if (teacher === null) {
      return null;
    }

    return await this.studentModel.find({ teacher: teacher.name }).exec();
  }

  async updateStudentByTeacherAndStudentId(
    teacherId: string,
    studentId: string,
    studentDTO: StudentDTO,
  ): Promise<void> {
    const teacher = await this.teacherModel.findById(teacherId).exec();

    if (teacher === null) {
      return null;
    }

    await this.studentModel.findByIdAndUpdate(studentId, studentDTO).exec();
  }
}
<file_sep>import { StudentTeacherService } from './../services/student-teacher.service';
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { StudentController } from 'src/controllers/teacher/student.controller';
import { Student, StudentSchema } from './student.schema';
import { Teacher, TeacherSchema } from './teacher.schema';

@Module({
  controllers: [StudentController],
  providers: [StudentTeacherService],
  imports: [
    MongooseModule.forFeature([{ name: Teacher.name, schema: TeacherSchema }]),
    MongooseModule.forFeature([{ name: Student.name, schema: StudentSchema }]),
  ],
  exports: [StudentTeacherService],
})
export class StudentTeacherModule {}
