Template
feat: game creation and login
This commit is contained in:
@@ -1,33 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
parser: '@typescript-eslint/parser',
|
|
||||||
parserOptions: {
|
|
||||||
project: 'tsconfig.json',
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
sourceType: 'module',
|
|
||||||
},
|
|
||||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
|
||||||
extends: [
|
|
||||||
'plugin:@typescript-eslint/recommended',
|
|
||||||
'plugin:prettier/recommended',
|
|
||||||
],
|
|
||||||
root: true,
|
|
||||||
env: {
|
|
||||||
node: true,
|
|
||||||
jest: true,
|
|
||||||
},
|
|
||||||
ignorePatterns: ['.eslintrc.js'],
|
|
||||||
rules: {
|
|
||||||
'@typescript-eslint/interface-name-prefix': 'off',
|
|
||||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
||||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
|
||||||
'@typescript-eslint/no-unused-vars': [
|
|
||||||
'warn', // or "error"
|
|
||||||
{
|
|
||||||
argsIgnorePattern: '^_',
|
|
||||||
varsIgnorePattern: '^_',
|
|
||||||
caughtErrorsIgnorePattern: '^_',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Vendored
+1
-2
@@ -18,7 +18,6 @@
|
|||||||
"console": "internalConsole",
|
"console": "internalConsole",
|
||||||
"outputCapture": "std",
|
"outputCapture": "std",
|
||||||
"internalConsoleOptions": "openOnSessionStart",
|
"internalConsoleOptions": "openOnSessionStart",
|
||||||
"envFile": "${workspaceFolder}/.env"
|
},
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-1
@@ -1,4 +1,5 @@
|
|||||||
services:
|
services:
|
||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres
|
image: postgres
|
||||||
ports:
|
ports:
|
||||||
@@ -7,6 +8,27 @@ services:
|
|||||||
- pg_data:/var/lib/postgresql/data
|
- pg_data:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_PASSWORD=test
|
- POSTGRES_PASSWORD=test
|
||||||
|
|
||||||
|
pgadmin:
|
||||||
|
image: dpage/pgadmin4
|
||||||
|
ports:
|
||||||
|
- 8080:80
|
||||||
|
environment:
|
||||||
|
- PGADMIN_DEFAULT_EMAIL=postgres@postgres.com
|
||||||
|
- PGADMIN_DEFAULT_PASSWORD=postgres
|
||||||
|
- PGADMIN_DISABLE_POSTFIX=true
|
||||||
|
volumes:
|
||||||
|
- pgadmin_data:/var/lib/pgadmin
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis
|
||||||
|
ports:
|
||||||
|
- 6379:6379
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
command: "redis-server --save 60 1"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pg_data:
|
pg_data:
|
||||||
|
pgadmin_data:
|
||||||
|
redis_data:
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import typescriptEslintEslintPlugin from '@typescript-eslint/eslint-plugin';
|
||||||
|
import globals from 'globals';
|
||||||
|
import tsParser from '@typescript-eslint/parser';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import js from '@eslint/js';
|
||||||
|
import { FlatCompat } from '@eslint/eslintrc';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
const compat = new FlatCompat({
|
||||||
|
baseDirectory: __dirname,
|
||||||
|
recommendedConfig: js.configs.recommended,
|
||||||
|
allConfig: js.configs.all,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
ignores: ['**/.eslintrc.js'],
|
||||||
|
},
|
||||||
|
...compat.extends(
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'plugin:prettier/recommended',
|
||||||
|
),
|
||||||
|
{
|
||||||
|
plugins: {
|
||||||
|
'@typescript-eslint': typescriptEslintEslintPlugin,
|
||||||
|
},
|
||||||
|
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
...globals.node,
|
||||||
|
...globals.jest,
|
||||||
|
},
|
||||||
|
|
||||||
|
parser: tsParser,
|
||||||
|
ecmaVersion: 5,
|
||||||
|
sourceType: 'module',
|
||||||
|
|
||||||
|
parserOptions: {
|
||||||
|
project: 'tsconfig.json',
|
||||||
|
tsconfigRootDir: '/home/legonzaur/Documents/code/concept/back',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/interface-name-prefix': 'off',
|
||||||
|
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||||
|
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
|
||||||
|
'@typescript-eslint/no-unused-vars': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
argsIgnorePattern: '^_',
|
||||||
|
varsIgnorePattern: '^_',
|
||||||
|
caughtErrorsIgnorePattern: '^_',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
Generated
+1354
-948
File diff suppressed because it is too large
Load Diff
+15
-4
@@ -16,7 +16,11 @@
|
|||||||
"test:watch": "jest --watch",
|
"test:watch": "jest --watch",
|
||||||
"test:cov": "jest --coverage",
|
"test:cov": "jest --coverage",
|
||||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/jest/bin/jest --runInBand",
|
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/jest/bin/jest --runInBand",
|
||||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||||
|
"migration:generate": "npx ts-node -P ./tsconfig.json -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:generate -d ./src/db/typeorm.config.ts ./src/db/migrations/migration",
|
||||||
|
"migration:create": "npx ts-node -P ./tsconfig.json -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:create -d ./src/db/typeorm.config.ts ./src/db/migrations/migration",
|
||||||
|
"migration:run": "npx ts-node -P ./tsconfig.json -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:run -d ./src/db/typeorm.config.ts",
|
||||||
|
"migration:revert": "npx ts-node -P ./tsconfig.json -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:revert -d ./src/db/typeorm.config.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nestjs/common": "^10.3.2",
|
"@nestjs/common": "^10.3.2",
|
||||||
@@ -27,14 +31,19 @@
|
|||||||
"@nestjs/platform-express": "^10.3.2",
|
"@nestjs/platform-express": "^10.3.2",
|
||||||
"@nestjs/swagger": "^7.3.1",
|
"@nestjs/swagger": "^7.3.1",
|
||||||
"@nestjs/typeorm": "^10.0.2",
|
"@nestjs/typeorm": "^10.0.2",
|
||||||
"connect-mongo": "^5.1.0",
|
"@types/ranjs": "^1.22.7",
|
||||||
|
"connect-redis": "^8.0.1",
|
||||||
"express-session": "^1.18.0",
|
"express-session": "^1.18.0",
|
||||||
"mongoose-autopopulate": "^1.1.0",
|
"pg": "^8.13.1",
|
||||||
|
"ranjs": "^1.24.5",
|
||||||
|
"redis": "^4.7.0",
|
||||||
"reflect-metadata": "^0.2.1",
|
"reflect-metadata": "^0.2.1",
|
||||||
"rxjs": "^7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
"typeorm": "^0.3.20"
|
"typeorm": "^0.3.20"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@eslint/eslintrc": "^3.2.0",
|
||||||
|
"@eslint/js": "^9.17.0",
|
||||||
"@nestjs/cli": "^10.3.1",
|
"@nestjs/cli": "^10.3.1",
|
||||||
"@nestjs/schematics": "^10.1.0",
|
"@nestjs/schematics": "^10.1.0",
|
||||||
"@nestjs/testing": "^10.3.2",
|
"@nestjs/testing": "^10.3.2",
|
||||||
@@ -47,9 +56,11 @@
|
|||||||
"@types/supertest": "^6.0.2",
|
"@types/supertest": "^6.0.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||||
"@typescript-eslint/parser": "^6.21.0",
|
"@typescript-eslint/parser": "^6.21.0",
|
||||||
"eslint": "^8.56.0",
|
"@typescript-eslint/typescript-estree": "^8.18.2",
|
||||||
|
"eslint": "^8.57.1",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
|
"globals": "^15.14.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
|
|||||||
+21
-11
@@ -6,23 +6,33 @@ import { GamesModule } from './games/games.module';
|
|||||||
import { UsersModule } from './users/users.module';
|
import { UsersModule } from './users/users.module';
|
||||||
import { EventEmitterModule } from '@nestjs/event-emitter';
|
import { EventEmitterModule } from '@nestjs/event-emitter';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { User } from './users/schemas/user.entity';
|
import { User } from './users/entities/user.entity';
|
||||||
import { Game } from './games/schemas/game.schema';
|
import { Game } from './games/entities/game.entity';
|
||||||
import { Topic } from './words/schemas/topic.schema';
|
import { Topic } from './words/entities/topic.entity';
|
||||||
import { Word } from './words/schemas/word.schema';
|
import { Word } from './words/entities/word.entity';
|
||||||
import { Player } from './games/schemas/player.schema';
|
import { Player } from './games/entities/player.entity';
|
||||||
|
import { Concept } from './games/entities/concept.entity';
|
||||||
|
import { ConceptInTurn } from './games/entities/concept_in_turn.entity';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
|
const configService = new ConfigService();
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
EventEmitterModule.forRoot(),
|
EventEmitterModule.forRoot(),
|
||||||
ConfigModule.forRoot(),
|
ConfigModule.forRoot({
|
||||||
|
envFilePath: '.env',
|
||||||
|
isGlobal: true,
|
||||||
|
}),
|
||||||
TypeOrmModule.forRoot({
|
TypeOrmModule.forRoot({
|
||||||
type: 'postgres',
|
type: 'postgres',
|
||||||
url: process.env.PG_ENDPOINT,
|
host: configService.get('PG_HOST'),
|
||||||
password: process.env.PG_PASSWORD,
|
// url: process.env.PG_ENDPOINT,
|
||||||
username: process.env.PG_USER,
|
password: configService.get('PG_PASSWORD'),
|
||||||
synchronize: process.env.DEV_MODE == 'true',
|
username: configService.get('PG_USER'),
|
||||||
entities: [User, Player, Game, Topic, Word],
|
database: 'concept',
|
||||||
|
synchronize: configService.get('DEV_MODE') == 'true',
|
||||||
|
entities: [User, Player, Game, Concept, ConceptInTurn, Topic, Word],
|
||||||
}),
|
}),
|
||||||
GamesModule,
|
GamesModule,
|
||||||
UsersModule,
|
UsersModule,
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
|
export class Migration1735396726613 implements MigrationInterface {
|
||||||
|
name = 'Migration1735396726613';
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TABLE "user" ("userId" character varying NOT NULL, "avatar" character varying NOT NULL, "username" character varying NOT NULL, CONSTRAINT "PK_d72ea127f30e21753c9e229891e" PRIMARY KEY ("userId"))`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TABLE "topic" ("id" SERIAL NOT NULL, CONSTRAINT "PK_33aa4ecb4e4f20aa0157ea7ef61" PRIMARY KEY ("id"))`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TABLE "word" ("id" SERIAL NOT NULL, "value" character varying NOT NULL, "ownerUserId" character varying, CONSTRAINT "PK_ad026d65e30f80b7056ca31f666" PRIMARY KEY ("id"))`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TABLE "concept" ("id" SERIAL NOT NULL, "value" character varying NOT NULL, CONSTRAINT "UQ_3275d953a4dc4dadeef5a8aeed4" UNIQUE ("value"), CONSTRAINT "PK_83c1330866b9866ac2d0ed2b36b" PRIMARY KEY ("id"))`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TABLE "concept_in_turn" ("id" SERIAL NOT NULL, "order" integer NOT NULL DEFAULT '0', "subconcept" integer NOT NULL DEFAULT '0', "markers" integer NOT NULL DEFAULT '1', "conceptId" integer, "gameId" integer, CONSTRAINT "PK_c44692f972ab31a6245c8599b4b" PRIMARY KEY ("id"))`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TABLE "game" ("id" SERIAL NOT NULL, "seed" character varying NOT NULL, "currentWord" character varying NOT NULL, "started" boolean NOT NULL, "ownerUserId" character varying, CONSTRAINT "PK_352a30652cd352f552fef73dec5" PRIMARY KEY ("id"))`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TABLE "player" ("id" SERIAL NOT NULL, "score" integer NOT NULL, "userUserId" character varying, "gameId" integer, CONSTRAINT "PK_65edadc946a7faf4b638d5e8885" PRIMARY KEY ("id"))`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TABLE "word_topics_topic" ("wordId" integer NOT NULL, "topicId" integer NOT NULL, CONSTRAINT "PK_cc5d13565912abf7d0e1dcfc3a7" PRIMARY KEY ("wordId", "topicId"))`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE INDEX "IDX_66e5a60dcdb89fc3be327eb139" ON "word_topics_topic" ("wordId") `,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE INDEX "IDX_3346a237bd507b395347a64ddc" ON "word_topics_topic" ("topicId") `,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "word" ADD CONSTRAINT "FK_4472fdeaf534031039106aa04de" FOREIGN KEY ("ownerUserId") REFERENCES "user"("userId") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "concept_in_turn" ADD CONSTRAINT "FK_6dfaa966f86139a62aba3b2114a" FOREIGN KEY ("conceptId") REFERENCES "concept"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "concept_in_turn" ADD CONSTRAINT "FK_f1c8614584bd8afcac818bacfd9" FOREIGN KEY ("gameId") REFERENCES "game"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "game" ADD CONSTRAINT "FK_9b45658e1fea65880fd35c9bacc" FOREIGN KEY ("ownerUserId") REFERENCES "user"("userId") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "player" ADD CONSTRAINT "FK_2b8a672d52e840e6c4e3bf79f58" FOREIGN KEY ("userUserId") REFERENCES "user"("userId") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "player" ADD CONSTRAINT "FK_7dfdd31fcd2b5aa3b08ed15fe8a" FOREIGN KEY ("gameId") REFERENCES "game"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "word_topics_topic" ADD CONSTRAINT "FK_66e5a60dcdb89fc3be327eb139a" FOREIGN KEY ("wordId") REFERENCES "word"("id") ON DELETE CASCADE ON UPDATE CASCADE`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "word_topics_topic" ADD CONSTRAINT "FK_3346a237bd507b395347a64ddcb" FOREIGN KEY ("topicId") REFERENCES "topic"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "word_topics_topic" DROP CONSTRAINT "FK_3346a237bd507b395347a64ddcb"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "word_topics_topic" DROP CONSTRAINT "FK_66e5a60dcdb89fc3be327eb139a"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "player" DROP CONSTRAINT "FK_7dfdd31fcd2b5aa3b08ed15fe8a"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "player" DROP CONSTRAINT "FK_2b8a672d52e840e6c4e3bf79f58"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "game" DROP CONSTRAINT "FK_9b45658e1fea65880fd35c9bacc"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "concept_in_turn" DROP CONSTRAINT "FK_f1c8614584bd8afcac818bacfd9"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "concept_in_turn" DROP CONSTRAINT "FK_6dfaa966f86139a62aba3b2114a"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "word" DROP CONSTRAINT "FK_4472fdeaf534031039106aa04de"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`DROP INDEX "public"."IDX_3346a237bd507b395347a64ddc"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`DROP INDEX "public"."IDX_66e5a60dcdb89fc3be327eb139"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(`DROP TABLE "word_topics_topic"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "player"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "game"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "concept_in_turn"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "concept"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "word"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "topic"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "user"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { DataSource } from 'typeorm';
|
||||||
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
|
ConfigModule.forRoot({
|
||||||
|
envFilePath: '.env',
|
||||||
|
isGlobal: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const configService = new ConfigService();
|
||||||
|
|
||||||
|
const AppDataSource = new DataSource({
|
||||||
|
type: 'postgres',
|
||||||
|
host: configService.get('PG_HOST'),
|
||||||
|
// url: process.env.PG_ENDPOINT,
|
||||||
|
password: configService.get('PG_PASSWORD'),
|
||||||
|
username: configService.get('PG_USER'),
|
||||||
|
database: 'concept',
|
||||||
|
synchronize: false,
|
||||||
|
entities: ['**/*.entity.ts'],
|
||||||
|
migrations: ['src/db/migrations/*-migration.ts'],
|
||||||
|
migrationsRun: false,
|
||||||
|
logging: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default AppDataSource;
|
||||||
@@ -12,12 +12,13 @@ import {
|
|||||||
import { LobbyService } from '../services/lobby.service';
|
import { LobbyService } from '../services/lobby.service';
|
||||||
import { AuthGuard } from '../guards/auth.guard';
|
import { AuthGuard } from '../guards/auth.guard';
|
||||||
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
import { Game } from '../schemas/game.schema';
|
import { Game } from '../entities/game.entity';
|
||||||
import { GamePipe, GameStartedPipe } from '../pipe/game.pipe';
|
import { GamePipe, GameStartedPipe } from '../pipe/game.pipe';
|
||||||
|
|
||||||
import { Observable, fromEvent, map } from 'rxjs';
|
import { Observable, fromEvent, map } from 'rxjs';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { GameService } from '../services/games.service';
|
import { GameService } from '../services/games.service';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
@ApiTags('game')
|
@ApiTags('game')
|
||||||
@Controller('games/:id')
|
@Controller('games/:id')
|
||||||
@@ -26,6 +27,7 @@ export class GamesController {
|
|||||||
private readonly lobbyService: LobbyService,
|
private readonly lobbyService: LobbyService,
|
||||||
private readonly gameService: GameService,
|
private readonly gameService: GameService,
|
||||||
private eventEmitter: EventEmitter2,
|
private eventEmitter: EventEmitter2,
|
||||||
|
private configService: ConfigService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Post('/start')
|
@Post('/start')
|
||||||
@@ -51,7 +53,7 @@ export class GamesController {
|
|||||||
if (game.started) {
|
if (game.started) {
|
||||||
throw new HttpException('Game already started', HttpStatus.BAD_REQUEST);
|
throw new HttpException('Game already started', HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
if (game.players.length < 2 && !process.env.DEV_MODE) {
|
if (game.players.length < 2 && !this.configService.get('DEV_MODE')) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'Not enough teams to start the game',
|
'Not enough teams to start the game',
|
||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { LobbyController } from './games.lobby.controller';
|
import { LobbyController } from './lobby.controller';
|
||||||
import { LobbyService } from '../services/lobby.service';
|
import { LobbyService } from '../services/lobby.service';
|
||||||
|
|
||||||
describe('GamesController', () => {
|
describe('GamesController', () => {
|
||||||
|
|||||||
+2
-4
@@ -8,15 +8,13 @@ import {
|
|||||||
Session,
|
Session,
|
||||||
HttpException,
|
HttpException,
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Patch,
|
|
||||||
Body,
|
|
||||||
Sse,
|
Sse,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { LobbyService } from '../services/lobby.service';
|
import { LobbyService } from '../services/lobby.service';
|
||||||
import { AuthGuard } from '../guards/auth.guard';
|
import { AuthGuard } from '../guards/auth.guard';
|
||||||
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
import { GamePipe } from '../pipe/game.pipe';
|
import { GamePipe } from '../pipe/game.pipe';
|
||||||
import { Game } from '../schemas/game.schema';
|
import { Game } from '../entities/game.entity';
|
||||||
import { Observable, fromEvent, map } from 'rxjs';
|
import { Observable, fromEvent, map } from 'rxjs';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
|
|
||||||
@@ -43,7 +41,7 @@ export class LobbyController {
|
|||||||
@UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
async create(@Session() session: Record<string, any>) {
|
async create(@Session() session: Record<string, any>) {
|
||||||
const games = await this.lobbyService.findByOwner(session.user);
|
const games = await this.lobbyService.findByOwner(session.user);
|
||||||
if (games) {
|
if (games.length > 0) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'You can only create one game at a time',
|
'You can only create one game at a time',
|
||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn,
|
||||||
Unique,
|
Unique,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
import { Player } from './player.schema';
|
import { Player } from './player.entity';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
@Unique(['value'])
|
@Unique(['value'])
|
||||||
+2
-2
@@ -8,8 +8,8 @@ import {
|
|||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn,
|
||||||
Unique,
|
Unique,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
import { Concept } from './concept.schema';
|
import { Concept } from './concept.entity';
|
||||||
import { Game } from './game.schema';
|
import { Game } from './game.entity';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class ConceptInTurn {
|
export class ConceptInTurn {
|
||||||
@@ -7,9 +7,9 @@ import {
|
|||||||
OneToOne,
|
OneToOne,
|
||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
import { Player } from './player.schema';
|
import { Player } from './player.entity';
|
||||||
import { ConceptInTurn } from './concept_in_turn.schema';
|
import { ConceptInTurn } from './concept_in_turn.entity';
|
||||||
import { User } from 'src/users/schemas/user.entity';
|
import { User } from 'src/users/entities/user.entity';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Game {
|
export class Game {
|
||||||
@@ -29,10 +29,10 @@ export class Game {
|
|||||||
@OneToOne(() => Player)
|
@OneToOne(() => Player)
|
||||||
currentPlayer: Player;
|
currentPlayer: Player;
|
||||||
|
|
||||||
@Column()
|
@Column({ nullable: true })
|
||||||
currentWord: string;
|
currentWord: string;
|
||||||
|
|
||||||
@Column()
|
@Column({ default: false })
|
||||||
started: boolean;
|
started: boolean;
|
||||||
|
|
||||||
@OneToMany(() => ConceptInTurn, (cit) => cit.game)
|
@OneToMany(() => ConceptInTurn, (cit) => cit.game)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { User } from 'src/users/schemas/user.entity';
|
import { User } from 'src/users/entities/user.entity';
|
||||||
import {
|
import {
|
||||||
Column,
|
Column,
|
||||||
Entity,
|
Entity,
|
||||||
@@ -9,20 +9,20 @@ import {
|
|||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn,
|
||||||
Unique,
|
Unique,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
import { Game } from './game.schema';
|
import { Game } from './game.entity';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
@Unique(['user, game'])
|
// @Unique(['user, game'])
|
||||||
export class Player {
|
export class Player {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
@ManyToOne((type) => User)
|
@ManyToOne(() => User)
|
||||||
user: User;
|
user: User;
|
||||||
|
|
||||||
@ManyToOne((type) => Game)
|
@ManyToOne(() => Game)
|
||||||
game: Promise<Game>;
|
game: Game;
|
||||||
|
|
||||||
@Column()
|
@Column({ default: 0 })
|
||||||
score: number;
|
score: number;
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,19 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { LobbyService } from './services/lobby.service';
|
import { LobbyService } from './services/lobby.service';
|
||||||
import { LobbyController } from './controllers/games.lobby.controller';
|
import { LobbyController } from './controllers/lobby.controller';
|
||||||
import { Game } from './schemas/game.schema';
|
import { Game } from './entities/game.entity';
|
||||||
import { UsersModule } from 'src/users/users.module';
|
import { UsersModule } from 'src/users/users.module';
|
||||||
import { GamesController } from './controllers/games.controller';
|
import { GamesController } from './controllers/games.controller';
|
||||||
import { GameService } from './services/games.service';
|
import { GameService } from './services/games.service';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { Player } from './entities/player.entity';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [UsersModule, TypeOrmModule.forFeature([Game])],
|
imports: [
|
||||||
|
UsersModule,
|
||||||
|
TypeOrmModule.forFeature([Game]),
|
||||||
|
TypeOrmModule.forFeature([Player]),
|
||||||
|
],
|
||||||
controllers: [LobbyController, GamesController],
|
controllers: [LobbyController, GamesController],
|
||||||
providers: [LobbyService, GameService],
|
providers: [LobbyService, GameService],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
HttpStatus,
|
HttpStatus,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
|
|
||||||
import { Game } from '../schemas/game.schema';
|
import { Game } from '../entities/game.entity';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import {
|
|||||||
Injectable,
|
Injectable,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Game } from '../schemas/game.schema';
|
import { Game } from '../entities/game.entity';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { Player } from '../schemas/player.schema';
|
import { Player } from '../entities/player.entity';
|
||||||
import { User } from 'src/users/schemas/user.entity';
|
import { User } from 'src/users/entities/user.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GameService {
|
export class GameService {
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
|||||||
import { GameService } from './games.service';
|
import { GameService } from './games.service';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { Game } from '../schemas/game.schema';
|
import { Game } from '../entities/game.entity';
|
||||||
import { User } from 'src/users/schemas/user.entity';
|
import { User } from 'src/users/entities/user.entity';
|
||||||
import { Player } from '../schemas/player.schema';
|
import { Player } from '../entities/player.entity';
|
||||||
|
import { randomUUID } from 'node:crypto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LobbyService {
|
export class LobbyService {
|
||||||
@@ -19,6 +20,8 @@ export class LobbyService {
|
|||||||
async create(owner: User) {
|
async create(owner: User) {
|
||||||
const createdGame = this.gameRepository.create();
|
const createdGame = this.gameRepository.create();
|
||||||
createdGame.owner = owner;
|
createdGame.owner = owner;
|
||||||
|
createdGame.seed = randomUUID();
|
||||||
|
this.gameRepository.save(createdGame);
|
||||||
await this.joinGame(createdGame, owner);
|
await this.joinGame(createdGame, owner);
|
||||||
this.eventEmitter.emit('sse.lobby', { type: 'create', ...createdGame });
|
this.eventEmitter.emit('sse.lobby', { type: 'create', ...createdGame });
|
||||||
return createdGame;
|
return createdGame;
|
||||||
@@ -27,7 +30,7 @@ export class LobbyService {
|
|||||||
async joinGame(game: Game, user: User) {
|
async joinGame(game: Game, user: User) {
|
||||||
const player = this.playerRepository.create();
|
const player = this.playerRepository.create();
|
||||||
player.user = user;
|
player.user = user;
|
||||||
game.players.push();
|
player.game = game;
|
||||||
|
|
||||||
this.eventEmitter.emit('sse.lobby', {
|
this.eventEmitter.emit('sse.lobby', {
|
||||||
type: 'joinGame',
|
type: 'joinGame',
|
||||||
@@ -39,7 +42,6 @@ export class LobbyService {
|
|||||||
player: player,
|
player: player,
|
||||||
});
|
});
|
||||||
this.playerRepository.save(player);
|
this.playerRepository.save(player);
|
||||||
this.gameRepository.save(game);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
findByOwner(user: User) {
|
findByOwner(user: User) {
|
||||||
|
|||||||
+9
-18
@@ -2,40 +2,31 @@ import { NestFactory } from '@nestjs/core';
|
|||||||
import * as session from 'express-session';
|
import * as session from 'express-session';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||||
import MongoStore from 'connect-mongo';
|
import { RedisStore } from 'connect-redis';
|
||||||
import mongoose from 'mongoose';
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
|
const redisClient = createClient();
|
||||||
|
redisClient.connect().catch(console.error);
|
||||||
|
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
app.enableCors({ origin: 'http://localhost:3000', credentials: true });
|
app.enableCors({ origin: 'http://localhost:3000', credentials: true });
|
||||||
app.setGlobalPrefix(process.env.API_PREFIX);
|
app.setGlobalPrefix(process.env.API_PREFIX);
|
||||||
const config = new DocumentBuilder()
|
const config = new DocumentBuilder()
|
||||||
.setTitle('Heron Game')
|
.setTitle('Concept Game')
|
||||||
.setDescription('Heron')
|
.setDescription('Concept')
|
||||||
.setVersion('1.0')
|
.setVersion('1.0')
|
||||||
.build();
|
.build();
|
||||||
const document = SwaggerModule.createDocument(app, config);
|
const document = SwaggerModule.createDocument(app, config);
|
||||||
SwaggerModule.setup('api', app, document);
|
SwaggerModule.setup('api', app, document);
|
||||||
|
|
||||||
mongoose.set('transactionAsyncLocalStorage', true);
|
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
session.default({
|
session.default({
|
||||||
secret: process.env.SESSION_SECRET,
|
secret: process.env.SESSION_SECRET,
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: false,
|
saveUninitialized: false,
|
||||||
name: 'heron.session',
|
name: 'concept.session',
|
||||||
store: MongoStore.create({
|
store: new RedisStore({ client: redisClient, prefix: 'concept:' }),
|
||||||
collectionName: 'sessions',
|
|
||||||
dbName: 'heron',
|
|
||||||
mongoUrl: process.env.MONGO_ENDPOINT,
|
|
||||||
mongoOptions: {
|
|
||||||
auth: {
|
|
||||||
password: process.env.MONGO_PASSWORD,
|
|
||||||
username: process.env.MONGO_USER,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Entity, Column, PrimaryColumn } from 'typeorm';
|
import { Entity, Column, PrimaryColumn } from 'typeorm';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
@@ -11,25 +11,31 @@ import { UsersService } from './users.service';
|
|||||||
import { LoginDto } from './dto/login.dto';
|
import { LoginDto } from './dto/login.dto';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiTags } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
|
const configService = new ConfigService();
|
||||||
|
|
||||||
@ApiTags('auth')
|
@ApiTags('auth')
|
||||||
@Controller()
|
@Controller()
|
||||||
export class UsersController {
|
export class UsersController {
|
||||||
constructor(private readonly usersService: UsersService) {}
|
constructor(private readonly usersService: UsersService) {}
|
||||||
|
|
||||||
@Get('/login')
|
@Get('/login')
|
||||||
@Redirect(process.env.CLIENT_ENDPOINT)
|
@Redirect()
|
||||||
async login(
|
async login(
|
||||||
@Query('code') code: string,
|
@Query('code') code: string,
|
||||||
@Session() session: Record<string, any>,
|
@Session() session: Record<string, any>,
|
||||||
): Promise<void> {
|
) {
|
||||||
await this.usersService.createDiscordToken({ code }, session);
|
await this.usersService.createDiscordToken({ code }, session);
|
||||||
await this.usersService.discordLogin(session);
|
await this.usersService.discordLogin(session);
|
||||||
|
return { url: configService.get('CLIENT_ENDPOINT') };
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('/logout')
|
@Get('/logout')
|
||||||
@Redirect(process.env.CLIENT_ENDPOINT)
|
@Redirect()
|
||||||
async logout(@Session() session: Record<string, any>): Promise<void> {
|
async logout(@Session() session: Record<string, any>) {
|
||||||
await this.usersService.discordLogout(session);
|
await this.usersService.discordLogout(session);
|
||||||
|
return { url: configService.get('CLIENT_ENDPOINT') };
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('/whoami')
|
@Get('/whoami')
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { UsersService } from './users.service';
|
import { UsersService } from './users.service';
|
||||||
import { UsersController } from './users.controller';
|
import { UsersController } from './users.controller';
|
||||||
import { User } from './schemas/user.entity';
|
import { User } from './entities/user.entity';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
@@ -9,5 +9,4 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
|||||||
controllers: [UsersController],
|
controllers: [UsersController],
|
||||||
providers: [UsersService],
|
providers: [UsersService],
|
||||||
})
|
})
|
||||||
export class UsersModule {
|
export class UsersModule {}
|
||||||
}
|
|
||||||
|
|||||||
+18
-12
@@ -1,13 +1,17 @@
|
|||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { LoginDto } from './dto/login.dto';
|
import { LoginDto } from './dto/login.dto';
|
||||||
import { URLSearchParams } from 'url';
|
import { URLSearchParams } from 'url';
|
||||||
import { User } from './schemas/user.entity';
|
import { User } from './entities/user.entity';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UsersService {
|
export class UsersService {
|
||||||
constructor(@InjectRepository(User) private usersRepository: Repository<User>) {}
|
constructor(
|
||||||
|
@InjectRepository(User) private usersRepository: Repository<User>,
|
||||||
|
private configService: ConfigService,
|
||||||
|
) {}
|
||||||
|
|
||||||
async createDiscordToken(
|
async createDiscordToken(
|
||||||
{
|
{
|
||||||
@@ -22,17 +26,19 @@ export class UsersService {
|
|||||||
let body;
|
let body;
|
||||||
if (code) {
|
if (code) {
|
||||||
body = new URLSearchParams({
|
body = new URLSearchParams({
|
||||||
client_id: process.env.DISCORD_CLIENTID,
|
// client_id: this.configService.get('DISCORD_CLIENTID'),
|
||||||
client_secret: process.env.DISCORD_CLIENTSECRET,
|
// client_secret: this.configService.get('DISCORD_CLIENTSECRET'),
|
||||||
code,
|
code,
|
||||||
grant_type: 'authorization_code',
|
grant_type: 'authorization_code',
|
||||||
redirect_uri:
|
redirect_uri:
|
||||||
process.env.API_ENDPOINT + process.env.API_PREFIX + '/login',
|
this.configService.get('API_ENDPOINT') +
|
||||||
|
this.configService.get('API_PREFIX') +
|
||||||
|
'/login',
|
||||||
});
|
});
|
||||||
} else if (refresh_token) {
|
} else if (refresh_token) {
|
||||||
body = new URLSearchParams({
|
body = new URLSearchParams({
|
||||||
client_id: process.env.DISCORD_CLIENTID,
|
// client_id: this.configService.get('DISCORD_CLIENTID'),
|
||||||
client_secret: process.env.DISCORD_CLIENTSECRET,
|
// client_secret: this.configService.get('DISCORD_CLIENTSECRET'),
|
||||||
refresh_token,
|
refresh_token,
|
||||||
grant_type: 'refresh_token',
|
grant_type: 'refresh_token',
|
||||||
});
|
});
|
||||||
@@ -42,10 +48,11 @@ export class UsersService {
|
|||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const req = await fetch('https://discord.com/api/oauth2/token', {
|
const req = await fetch('https://discord.com/api/v10/oauth2/token', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
Authorization: `Basic ${Buffer.from(this.configService.get('DISCORD_CLIENTID') + ':' + this.configService.get('DISCORD_CLIENTSECRET')).toString('base64')}`,
|
||||||
},
|
},
|
||||||
body,
|
body,
|
||||||
});
|
});
|
||||||
@@ -83,8 +90,8 @@ export class UsersService {
|
|||||||
|
|
||||||
async revokeDiscordToken(refresh_token: string) {
|
async revokeDiscordToken(refresh_token: string) {
|
||||||
const body = new URLSearchParams({
|
const body = new URLSearchParams({
|
||||||
client_id: process.env.DISCORD_CLIENTID,
|
client_id: this.configService.get('DISCORD_CLIENTID'),
|
||||||
client_secret: process.env.DISCORD_CLIENTSECRET,
|
client_secret: this.configService.get('DISCORD_CLIENTSECRET'),
|
||||||
token: refresh_token,
|
token: refresh_token,
|
||||||
token_type_hint: 'refresh_token',
|
token_type_hint: 'refresh_token',
|
||||||
});
|
});
|
||||||
@@ -138,11 +145,10 @@ export class UsersService {
|
|||||||
let user = await this.usersRepository.findOneBy({ userId });
|
let user = await this.usersRepository.findOneBy({ userId });
|
||||||
if (!user) {
|
if (!user) {
|
||||||
user = this.usersRepository.create({ ...data, userId });
|
user = this.usersRepository.create({ ...data, userId });
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Object.assign(user, data);
|
Object.assign(user, data);
|
||||||
}
|
}
|
||||||
this.usersRepository.save(user)
|
this.usersRepository.save(user);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { User } from 'src/users/entities/user.entity';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
Entity,
|
||||||
|
JoinTable,
|
||||||
|
ManyToMany,
|
||||||
|
ManyToOne,
|
||||||
|
OneToMany,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Unique,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { Word } from './word.entity';
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class Topic {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ManyToMany((type) => Word, (word) => word.topics)
|
||||||
|
words: Word[];
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { User } from 'src/users/entities/user.entity';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
Entity,
|
||||||
|
JoinTable,
|
||||||
|
ManyToMany,
|
||||||
|
ManyToOne,
|
||||||
|
OneToMany,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Unique,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { Topic } from './topic.entity';
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class Word {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
value: string;
|
||||||
|
|
||||||
|
@ManyToOne((type) => User)
|
||||||
|
owner: User;
|
||||||
|
|
||||||
|
@ManyToMany((type) => Topic, (topic) => topic.words)
|
||||||
|
@JoinTable()
|
||||||
|
topics: Topic[];
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { User } from 'src/users/schemas/user.entity';
|
|
||||||
import { Column, Entity, JoinTable, ManyToMany, ManyToOne, OneToMany, PrimaryGeneratedColumn, Unique } from 'typeorm';
|
|
||||||
import { Word } from './word.schema';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class Topic{
|
|
||||||
@PrimaryGeneratedColumn()
|
|
||||||
id: number
|
|
||||||
|
|
||||||
name: string
|
|
||||||
|
|
||||||
@ManyToMany(type=>Word, word=>word.topics)
|
|
||||||
words: Word[]
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { User } from 'src/users/schemas/user.entity';
|
|
||||||
import { Column, Entity, JoinTable, ManyToMany, ManyToOne, OneToMany, PrimaryGeneratedColumn, Unique } from 'typeorm';
|
|
||||||
import { Topic } from './topic.schema';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class Word{
|
|
||||||
@PrimaryGeneratedColumn()
|
|
||||||
id: number
|
|
||||||
|
|
||||||
@Column()
|
|
||||||
value: string
|
|
||||||
|
|
||||||
@ManyToOne(type=>User)
|
|
||||||
owner: User
|
|
||||||
|
|
||||||
@ManyToMany(type=>Topic, topic => topic.words)
|
|
||||||
@JoinTable()
|
|
||||||
topics: Topic[]
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user