diff --git a/packages/bridge-server/migrations/20231220172744-create-users-racer.js b/packages/bridge-server/migrations/20231220172744-create-users-racer.js new file mode 100644 index 0000000..bba57ba --- /dev/null +++ b/packages/bridge-server/migrations/20231220172744-create-users-racer.js @@ -0,0 +1,39 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('UsersRacers', { + userId: { + primaryKey: true, + type: Sequelize.STRING, + references: { + model: { + tableName: 'Users', + }, + key: 'auth0id', + }, + }, + racerId: { + primaryKey: true, + type: Sequelize.NUMBER, + references: { + model: { + tableName: 'Racers', + }, + key: 'id', + }, + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('UsersRacers'); + } +}; \ No newline at end of file diff --git a/packages/bridge-server/models/usersracer.js b/packages/bridge-server/models/usersracer.js new file mode 100644 index 0000000..f7c27a7 --- /dev/null +++ b/packages/bridge-server/models/usersracer.js @@ -0,0 +1,24 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class UsersRacer extends Model { + /** + * Helper method for defining associations. + * This method is not a part of Sequelize lifecycle. + * The `models/index` file will call this method automatically. + */ + static associate(models) { + // define association here + } + } + UsersRacer.init({ + racerId: DataTypes.NUMBER, + userId: DataTypes.STRING + }, { + sequelize, + modelName: 'UsersRacer', + }); + return UsersRacer; +}; \ No newline at end of file diff --git a/packages/bridge-server/src/racers/racers.service.ts b/packages/bridge-server/src/racers/racers.service.ts index b950938..d76f073 100644 --- a/packages/bridge-server/src/racers/racers.service.ts +++ b/packages/bridge-server/src/racers/racers.service.ts @@ -12,6 +12,10 @@ export class RacersService { ) {} + async findOne(gameHandle: string) { + return this.racerModel.findOne({ where: {gameHandle: gameHandle} }); + } + async findOrCreate(gameHandle: string): Promise { try { return this.sequelize.transaction( async t => { diff --git a/packages/bridge-server/src/upload/upload.service.ts b/packages/bridge-server/src/upload/upload.service.ts index b2d8b88..7d1adb6 100644 --- a/packages/bridge-server/src/upload/upload.service.ts +++ b/packages/bridge-server/src/upload/upload.service.ts @@ -24,6 +24,24 @@ export class UploadService { ) {} + async getRacerFromReplay(file: Express.Multer.File) { + let buffer = readFileSync(file.path); + let buff = new AdvancableBuffer(buffer); + let header = new gbxHeader(); + + header.parse(buff); + if (header.is_vaild == false) + { + unlinkSync(file.path); + throw new NotAcceptableException('GBXInvalid', {cause: new Error(), description: 'This is not a valid replay file'}); + } + + let replay = new gbxReplay(); + replay.parse(buff); + + return await this.racersService.findOne(replay.gamerHandle); + } + async replayUploaded(file: Express.Multer.File, body: any) { const hash = createHash('sha256'); diff --git a/packages/bridge-server/src/users/users-racer.model.ts b/packages/bridge-server/src/users/users-racer.model.ts new file mode 100644 index 0000000..26dc445 --- /dev/null +++ b/packages/bridge-server/src/users/users-racer.model.ts @@ -0,0 +1,16 @@ +import { Column, ForeignKey, HasMany, Model, PrimaryKey, Table } from "sequelize-typescript"; +import { Racer } from "src/racers/racer.model"; +import { User } from "./users.model"; + +@Table +export class UsersRacer extends Model { + @ForeignKey(() => User) + @PrimaryKey + @Column + userId: string; + + @ForeignKey(() => Racer) + @PrimaryKey + @Column + racerId: number; +} \ No newline at end of file diff --git a/packages/bridge-server/src/users/users.controller.ts b/packages/bridge-server/src/users/users.controller.ts index ed0a350..b6bbe65 100644 --- a/packages/bridge-server/src/users/users.controller.ts +++ b/packages/bridge-server/src/users/users.controller.ts @@ -18,4 +18,6 @@ export class UsersController { updateLastLogin(@Body() body: any) { return this.usersService.updateLastLogin(body.id, body.nickname, body.picture, body.time); } + + } diff --git a/packages/bridge-server/src/users/users.module.ts b/packages/bridge-server/src/users/users.module.ts index 8e9efb6..9a7d2e4 100644 --- a/packages/bridge-server/src/users/users.module.ts +++ b/packages/bridge-server/src/users/users.module.ts @@ -3,10 +3,12 @@ import { SequelizeModule } from '@nestjs/sequelize'; import { UsersService } from './users.service'; import { UsersController } from './users.controller'; import { User } from './users.model'; +import { UsersRacer } from './users-racer.model'; @Module({ imports: [ SequelizeModule.forFeature([User]), + SequelizeModule.forFeature([UsersRacer]), ], providers: [UsersService], controllers: [UsersController], diff --git a/packages/bridge-server/src/users/users.service.ts b/packages/bridge-server/src/users/users.service.ts index 76bd512..bf4f62c 100644 --- a/packages/bridge-server/src/users/users.service.ts +++ b/packages/bridge-server/src/users/users.service.ts @@ -2,6 +2,8 @@ import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/sequelize'; import { Sequelize } from 'sequelize-typescript'; import { User } from './users.model'; +import { Racer } from 'src/racers/racer.model'; +import { UsersRacer } from './users-racer.model'; // This should be a real class/interface representing a user entity //export type User = any; @@ -15,6 +17,7 @@ export class UsersService { constructor( @InjectModel(User) private userModel: typeof User, + @InjectModel(UsersRacer) private usersRacerModel: typeof UsersRacer, private sequelize: Sequelize ) {} @@ -22,4 +25,18 @@ export class UsersService { updateLastLogin(id, nickname, picture, time) { this.userModel.upsert({auth0id: id, nickname: nickname, picture: picture, lastLogin: time}); } + + async claimRacer(user, racer: Racer) { + try { + await this.sequelize.transaction( async t => { + const transactionHost = { transaction: t }; + await this.usersRacerModel.create( + { userId: user.sub, racerId: racer.id }, + transactionHost + ); + }); + } catch (error) { + + } + } } \ No newline at end of file diff --git a/packages/bridge-ui/src/app/pages/user/user.component.html b/packages/bridge-ui/src/app/pages/user/user.component.html index 8105fa5..a1a107a 100644 --- a/packages/bridge-ui/src/app/pages/user/user.component.html +++ b/packages/bridge-ui/src/app/pages/user/user.component.html @@ -12,7 +12,19 @@ - + + + + + Racer Stats + + + + + + + +
diff --git a/packages/bridge-ui/src/app/pages/user/user.component.scss b/packages/bridge-ui/src/app/pages/user/user.component.scss index f9f89d8..76a87b4 100644 --- a/packages/bridge-ui/src/app/pages/user/user.component.scss +++ b/packages/bridge-ui/src/app/pages/user/user.component.scss @@ -19,3 +19,7 @@ .user-image { width: 200px; } + +mat-card { + margin-bottom: 1rem; +} diff --git a/packages/bridge-ui/src/app/services/users.service.ts b/packages/bridge-ui/src/app/services/users.service.ts index dc2c027..f895149 100644 --- a/packages/bridge-ui/src/app/services/users.service.ts +++ b/packages/bridge-ui/src/app/services/users.service.ts @@ -84,9 +84,9 @@ export class UsersService { } getUserRealName() : string { - if(!this.isAuthenticated || !this.user || !this.additionalInfo) {return ""} + if(!this.isAuthenticated || !this.user || !this.additionalInfo) {return "??? ???"} - return ""; + return "??? ???"; } canCreateSeasons() : boolean {