Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: ci.yml
on:
pull_request:
branches: [ master ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Node.js
uses: actions/setup-node@v1
with:
node-version: '18.x'

- name: Install dependencies
run: npm install

- name: Run build
run: npm run build

- name: Run tests
run: npm run test

- name: Check Format
run : npm run format:check

- name: Check Lint
run : npm run lint:check
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
"scripts": {
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"backend:run": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"lint:check": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
Expand Down
50 changes: 29 additions & 21 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,34 @@ import { ResponseAssignment } from './response_assignment/entities/response_assi
dotenv.config();

@Module({
imports: [
ClassroomModule,
CourseModule,
PracticeModule,
UserModule,
TaskModule,
TeacherModule,
ResponseTaskModule,
ResponseAssignmentModule,
TypeOrmModule.forRoot({
type: 'postgres', // Set the database type to PostgreSQL
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT),
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
autoLoadEntities: true,
// synchronize: true, // You can enable synchronization for development, but disable it in production
entities: [Teacher, Student, Course, Classroom, Practice, ResponseTask, ResponseAssignment],
}),
],
imports: [
ClassroomModule,
CourseModule,
PracticeModule,
UserModule,
TaskModule,
TeacherModule,
ResponseTaskModule,
ResponseAssignmentModule,
TypeOrmModule.forRoot({
type: 'postgres', // Set the database type to PostgreSQL
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT),
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
autoLoadEntities: true,
// synchronize: true, // You can enable synchronization for development, but disable it in production
entities: [
Teacher,
Student,
Course,
Classroom,
Practice,
ResponseTask,
ResponseAssignment,
],
}),
],
})
export class AppModule {}
18 changes: 9 additions & 9 deletions src/authentification/dto/sign-in.dto.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {IsDefined, IsEmail, IsString, MinLength} from "class-validator";
import { IsDefined, IsEmail, IsString, MinLength } from 'class-validator';

export class SignInDto {
@IsDefined()
@IsString()
@IsEmail()
email: string;
@IsDefined()
@IsString()
@MinLength(6)
password: string;
@IsDefined()
@IsString()
@IsEmail()
email: string;
@IsDefined()
@IsString()
@MinLength(6)
password: string;
}
18 changes: 9 additions & 9 deletions src/authentification/dto/sign-up.dto.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {IsBoolean, IsDefined, IsString, Length} from "class-validator";
import {SignInDto} from "./sign-in.dto";
import { IsBoolean, IsDefined, IsString, Length } from 'class-validator';
import { SignInDto } from './sign-in.dto';

export class SignUpDto extends SignInDto {
@IsDefined()
@IsString()
@Length(4, 16)
name: string;
@IsDefined()
@IsBoolean()
user: Boolean;
@IsDefined()
@IsString()
@Length(4, 16)
name: string;
@IsDefined()
@IsBoolean()
user: boolean;
}
4 changes: 2 additions & 2 deletions src/authentification/get-user.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {createParamDecorator, ExecutionContext} from '@nestjs/common';
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const GetUser = createParamDecorator((data, ctx: ExecutionContext) => {
const req = ctx.switchToHttp().getRequest();
return req.user;
});
});
2 changes: 1 addition & 1 deletion src/authentification/role.enum.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export enum Role {
Teacher = 'teacher',
Student = 'student',
}
}
27 changes: 16 additions & 11 deletions src/authentification/role.guard.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
import { CanActivate, ExecutionContext, Injectable, mixin } from "@nestjs/common";
import { TokenService } from "./token.service";
import { Role } from "./role.enum";
import {
CanActivate,
ExecutionContext,
Injectable,
mixin,
} from '@nestjs/common';
import { TokenService } from './token.service';
import { Role } from './role.enum';

export const RoleGuard = (roles?: Role [] | Role) => {
export const RoleGuard = (roles?: Role[] | Role) => {
@Injectable()
class RoleGuardMixin implements CanActivate {
constructor( public TokenService : TokenService) {}
constructor(public TokenService: TokenService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = request.headers.authorization?.split(" ")[1];
const token = request.headers.authorization?.split(' ')[1];
if (!token) {
throw new Error("Token not found");
throw new Error('Token not found');
}
const user = await this.TokenService.decode(token);
if (!user.role) {
throw new Error("User has no role");
throw new Error('User has no role');
}
if (!roles || roles.includes(user.role)) {
request.user = user;
return true;
}
throw new Error("User have no permission");
};
throw new Error('User have no permission');
}
}
return mixin(RoleGuardMixin);
}
};
14 changes: 6 additions & 8 deletions src/authentification/token.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { Injectable, UnauthorizedException } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class TokenService {

constructor(private readonly jwtService: JwtService) { }
constructor(private readonly jwtService: JwtService) {}
async encode(payload: any) {
try {
return await this.jwtService.signAsync(payload);
Expand All @@ -18,14 +16,14 @@ export class TokenService {
try {
const user = await this.jwtService.verifyAsync(token);
if (!user) {
throw new Error("Token invalid");
throw new Error('Token invalid');
}
if (user.exp < Date.now() / 1000) {
throw new Error("Token expired");
throw new Error('Token expired');
}
return user;
} catch (e) {
throw new UnauthorizedException(e.message);
}
}
}
}
28 changes: 13 additions & 15 deletions src/authentification/user.controller.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
import { Body, Controller, Get, Param, Post, Res, UseGuards } from "@nestjs/common";
import { SignInDto } from "./dto/sign-in.dto";
import { SignUpDto } from "./dto/sign-up.dto";
import { TokenUser, UserService } from "./user.service";
import { RoleGuard } from "./role.guard";
import { GetUser } from "./get-user.decorator";
import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common';
import { SignInDto } from './dto/sign-in.dto';
import { SignUpDto } from './dto/sign-up.dto';
import { TokenUser, UserService } from './user.service';
import { RoleGuard } from './role.guard';
import { GetUser } from './get-user.decorator';

@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}

constructor(private readonly userService: UserService) {
}

@Post("signin",)
@Post('signin')
async signin(@Body() SignInDto: SignInDto) {
return this.userService.signIn(SignInDto);
}

@Post("signup")
@Post('signup')
async signup(@Body() SignUpDto: SignUpDto) {
return this.userService.signup(SignUpDto);
}

@Get("/current")
@Get('/current')
@UseGuards(RoleGuard())
current(@GetUser() user: TokenUser ) {
current(@GetUser() user: TokenUser) {
return this.userService.getUser(user);
}

@Get("/all")
@Get('/all')
@UseGuards(RoleGuard())
all(@GetUser() user: TokenUser) {
return this.userService.getAll(user)
return this.userService.getAll(user);
}
}
35 changes: 18 additions & 17 deletions src/authentification/user.module.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import {Module} from '@nestjs/common';
import {UserController} from "./user.controller";
import {UserService} from "./user.service";
import {TeacherModule} from "../teacher/teacher.module";
import {StudentModule} from "../student/student.module";
import {TypeOrmModule} from "@nestjs/typeorm";
import {Teacher} from "../teacher/entities/teacher.entity";
import {Student} from "../student/entities/student.entity";
import {ClassroomModule} from "../classroom/classroom.module";
import { TokenService } from "./token.service";
import { JwtModule } from "@nestjs/jwt";
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { TeacherModule } from '../teacher/teacher.module';
import { StudentModule } from '../student/student.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Teacher } from '../teacher/entities/teacher.entity';
import { Student } from '../student/entities/student.entity';
import { ClassroomModule } from '../classroom/classroom.module';
import { TokenService } from './token.service';
import { JwtModule } from '@nestjs/jwt';
import * as dotenv from 'dotenv';
import { RoleGuard } from "./role.guard";

dotenv.config();
@Module({
Expand All @@ -22,10 +21,12 @@ dotenv.config();
signOptions: { expiresIn: '10h' },
secret: process.env.JWT_SECRET_KEY,
}),
TeacherModule, StudentModule, ClassroomModule],
TeacherModule,
StudentModule,
ClassroomModule,
],
controllers: [UserController],
providers: [UserService,TokenService],
exports: [TokenService]
providers: [UserService, TokenService],
exports: [TokenService],
})
export class UserModule {
}
export class UserModule {}
Loading