Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Adding Assessments dir #56

Merged
merged 5 commits into from
Aug 14, 2024
Merged
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
4 changes: 4 additions & 0 deletions .github/workflows/branches.yml
Original file line number Diff line number Diff line change
@@ -33,6 +33,10 @@ jobs:
npm run build:spec
cd ui
npx vue-tsc --noEmit
- name: Assessments TypeScript Error Free
run: |
cd assessments
npx vue-tsc --noEmit
- name: API TypeScript Error Free
run: |
cd api
1 change: 1 addition & 0 deletions api/.env
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
NODE_ENV=development
JWT_SECRET=
35 changes: 18 additions & 17 deletions api/package.json
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:dev": "nest start -w",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
@@ -21,12 +21,13 @@
"explode": "npx rimraf node_modules package-lock.json && npm i"
},
"dependencies": {
"@nestjs/common": "^10.3.8",
"@nestjs/config": "^3.2.2",
"@nestjs/core": "^10.3.8",
"@nestjs/platform-express": "^10.3.8",
"@nestjs/common": "^10.4.1",
"@nestjs/config": "^3.2.3",
"@nestjs/core": "^10.4.1",
"@nestjs/jwt": "^10.2.0",
"@nestjs/platform-express": "^10.4.1",
"@nestjs/sequelize": "^10.0.1",
"@nestjs/swagger": "^7.3.1",
"@nestjs/swagger": "^7.4.0",
"just-diff": "^6.0.2",
"lodash": "^4.17.21",
"reflect-metadata": "^0.2.2",
@@ -38,29 +39,29 @@
},
"devDependencies": {
"@faker-js/faker": "^8.4.1",
"@nestjs/cli": "^10.3.2",
"@nestjs/schematics": "^10.1.1",
"@nestjs/testing": "^10.3.8",
"@nestjs/cli": "^10.4.4",
"@nestjs/schematics": "^10.1.3",
"@nestjs/testing": "^10.4.1",
"@openapitools/openapi-generator-cli": "^2.13.4",
"@types/express": "^4.17.21",
"@types/jest": "^29.5.12",
"@types/lodash": "^4.17.4",
"@types/node": "^20.12.12",
"@types/lodash": "^4.17.7",
"@types/node": "^22.2.0",
"@types/sequelize": "^4.28.20",
"@types/supertest": "^6.0.2",
"@typescript-eslint/eslint-plugin": "^7.10.0",
"@typescript-eslint/parser": "^7.10.0",
"@typescript-eslint/eslint-plugin": "^8.1.0",
"@typescript-eslint/parser": "^8.1.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-prettier": "^5.2.1",
"jest": "^29.7.0",
"prettier": "^3.2.5",
"prettier": "^3.3.3",
"source-map-support": "^0.5.21",
"supertest": "^7.0.0",
"ts-jest": "^29.1.3",
"ts-jest": "^29.2.4",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.4.5"
"typescript": "^5.5.4"
},
"jest": {
"moduleFileExtensions": [
37 changes: 32 additions & 5 deletions api/src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,39 @@
import { Controller, Get } from "@nestjs/common";
import { Controller, Get, Request, UseGuards } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import { AppService } from "src/app.service";
import { AuthGuard } from "src/auth.guard";
import { AccessTokenEntity } from "src/models/access.token.entity";
import { ProfileEntity } from "src/models/profile.entity";
import { VersionEntity } from "src/models/version.entity";

@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
constructor(private readonly appService: AppService, private jwtService: JwtService) {}

@Get()
getHello(): string {
return this.appService.getHello();
@Get("version")
getVersion(): VersionEntity {
return {
version: process.env.npm_package_version as string,
};
}

@Get("access-token")
async getAccessToken(): Promise<AccessTokenEntity> {
const response = await this.jwtService.signAsync(
// Just a test user generated from jwt.io
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJKVFQgMDQ3MTAxMTExIiwibmFtZSI6IkZveCBNdWxkZXIiLCJpYXQiOjE1MTYyMzkwMjJ9.VVRekDEA-uQXGjvVOMEyySpO3D3s2zWPkEGs_mV-XZA",
{
secret: process.env.JWT_SECRET,
},
);
return {
accessToken: response,
};
}

@UseGuards(AuthGuard)
@Get("profile")
getProfile(@Request() req): ProfileEntity {
return req.user;
}
}
9 changes: 7 additions & 2 deletions api/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Module } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
import { JwtService } from "@nestjs/jwt";
import { SequelizeModule } from "@nestjs/sequelize";
import { AccountsModule } from "src/accounts/accounts.module";
import { AppController } from "src/app.controller";
import { AppService } from "src/app.service";
import { DBConfig } from "src/db";
import { DiffModule } from "src/diff/diff.module";
import { LeaguesModule } from "src/leagues/leagues.module";
import { RandomModule } from "src/random/random.module";
import { UsersModule } from "src/users/users.module";

@@ -15,10 +17,13 @@ import { UsersModule } from "src/users/users.module";
AccountsModule,
RandomModule,
DiffModule,
ConfigModule.forRoot(),
LeaguesModule,
ConfigModule.forRoot({
envFilePath: [".env.local", ".env"],
}),
SequelizeModule.forRoot(DBConfig),
],
controllers: [AppController],
providers: [AppService],
providers: [AppService, JwtService],
})
export class AppModule {}
3 changes: 0 additions & 3 deletions api/src/app.service.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,4 @@ import { Injectable } from "@nestjs/common";

@Injectable()
export class AppService {
getHello() {
return "Hello World!";
}
}
41 changes: 41 additions & 0 deletions api/src/auth.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
} from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import { Request } from "express";

@Injectable()
export class AuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
if (!token) {
throw new UnauthorizedException();
}
try {
// 💡 We're assigning the payload to the request object here
// so that we can access it in our route handlers
const jwt = await this.jwtService.verifyAsync(
token,
{
secret: process.env.JWT_SECRET,
},
);
request.user = this.jwtService.decode(jwt);
}
catch {
throw new UnauthorizedException();
}
return true;
}

private extractTokenFromHeader(request: Request): string | undefined {
const [type, token] = request.headers.authorization?.split(" ") ?? [];
return type === "Bearer" ? token : undefined;
}
}
Binary file modified api/src/db/data.db
Binary file not shown.
3 changes: 2 additions & 1 deletion api/src/db/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { SequelizeModuleOptions } from "@nestjs/sequelize";
import { Address } from "src/db/models/Address";
import { LeagueMatch } from "src/db/models/LeagueMatch";
import { User } from "src/db/models/User";

export const DBConfig: SequelizeModuleOptions = {
dialect: "sqlite",
storage: "src/db/data.db",
host: "localhost",
models: [User, Address],
models: [User, Address, LeagueMatch],
};
35 changes: 35 additions & 0 deletions api/src/db/models/LeagueMatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Column, Model, Table } from "sequelize-typescript";
import { PrimaryKeyGuid } from "src/db/decorators";

@Table({
tableName: "league_matches",
timestamps: false,
})
export class LeagueMatch extends Model {
@PrimaryKeyGuid()
declare id: string;

@Column
match_date: number;

@Column
stadium: string;

@Column
home_team: string;

@Column
away_team: string;

@Column
match_played: boolean;

@Column
home_team_score: number;

@Column
away_team_score: number;

@Column
group_id: number;
}
18 changes: 18 additions & 0 deletions api/src/leagues/leagues.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Controller, Get, UseGuards } from "@nestjs/common";
import { ApiTags } from "@nestjs/swagger";
import { AuthGuard } from "src/auth.guard";
import { LeaguesService } from "src/leagues/leagues.service";
import { LeagueMatchResponseModel } from "src/models/responses.entity";

@ApiTags("leagues")
@Controller("leagues")
export class LeaguesController {
constructor(private readonly service: LeaguesService) {
}

@UseGuards(AuthGuard)
@Get("matches")
async getMatches(): Promise<LeagueMatchResponseModel> {
return this.service.getMatches();
}
}
18 changes: 18 additions & 0 deletions api/src/leagues/leagues.mapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { LeagueMatch } from "src/db/models/LeagueMatch";
import { LeagueMatchEntity } from "src/models/league.match.entity";

export class LeaguesMapper {
matchToViewModel(leagueMatch: LeagueMatch): LeagueMatchEntity {
return {
id: leagueMatch.id,
groupId: leagueMatch.group_id,
stadium: leagueMatch.stadium,
matchDate: leagueMatch.match_date,
matchPlayed: leagueMatch.match_played,
homeTeam: leagueMatch.home_team,
homeTeamScore: leagueMatch.home_team_score,
awayTeam: leagueMatch.away_team,
awayTeamScore: leagueMatch.away_team_score,
};
}
}
15 changes: 15 additions & 0 deletions api/src/leagues/leagues.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Module } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import { SequelizeModule } from "@nestjs/sequelize";
import { LeagueMatch } from "src/db/models/LeagueMatch";
import { LeaguesController } from "src/leagues/leagues.controller";
import { LeaguesMapper } from "src/leagues/leagues.mapper";
import { LeaguesService } from "src/leagues/leagues.service";

@Module({
imports: [SequelizeModule.forFeature([LeagueMatch])],
controllers: [LeaguesController],
providers: [LeaguesService, LeaguesMapper, JwtService],
})
export class LeaguesModule {
}
19 changes: 19 additions & 0 deletions api/src/leagues/leagues.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Injectable } from "@nestjs/common";
import { LeagueMatch } from "src/db/models/LeagueMatch";
import { LeaguesMapper } from "src/leagues/leagues.mapper";

@Injectable()
export class LeaguesService {
constructor(private mapper: LeaguesMapper) {
}

async getMatches() {
const { rows, count } = await LeagueMatch.findAndCountAll({
raw: true,
});
return {
data: rows.map((row) => this.mapper.matchToViewModel(row)),
total: count,
};
}
}
3 changes: 3 additions & 0 deletions api/src/models/access.token.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export class AccessTokenEntity {
accessToken: string;
}
11 changes: 11 additions & 0 deletions api/src/models/league.match.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export class LeagueMatchEntity {
id: string;
groupId: number;
matchDate: number;
stadium: string;
homeTeam: string;
awayTeam: string;
matchPlayed: boolean;
homeTeamScore: number;
awayTeamScore: number;
}
5 changes: 5 additions & 0 deletions api/src/models/profile.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export class ProfileEntity {
sub: string;
name: string;
iat: number;
}
2 changes: 2 additions & 0 deletions api/src/models/responses.entity.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { GetResponseModel } from "src/models/base.list.entity";
import { TreeChangeModel } from "src/models/diff.entity";
import { LeagueMatchEntity } from "src/models/league.match.entity";
import { UserEntity } from "src/models/user.entity";

export class TreeChangeResponseModel extends GetResponseModel<TreeChangeModel>(TreeChangeModel) {}
export class UserResponseModel extends GetResponseModel<UserEntity>(UserEntity) {}
export class LeagueMatchResponseModel extends GetResponseModel<LeagueMatchEntity>(LeagueMatchEntity) {}
export class BulkResponse {
index: number;
message: string[];
3 changes: 3 additions & 0 deletions api/src/models/version.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export class VersionEntity {
version: string;
}
24 changes: 24 additions & 0 deletions assessments/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
5 changes: 5 additions & 0 deletions assessments/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Vue 3 + TypeScript + Vite

This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.

Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
Loading
Loading