Feat : create games
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
version: '3.1'
|
||||
|
||||
services:
|
||||
|
||||
mongo:
|
||||
image: docker.io/mongo
|
||||
restart: always
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: example
|
||||
ports:
|
||||
- 27017:27017
|
||||
Generated
+54
@@ -16,6 +16,7 @@
|
||||
"@nestjs/mongoose": "^10.0.6",
|
||||
"@nestjs/platform-express": "^10.3.2",
|
||||
"@nestjs/swagger": "^7.3.1",
|
||||
"connect-mongo": "^5.1.0",
|
||||
"express-session": "^1.18.0",
|
||||
"mongoose": "^8.4.1",
|
||||
"reflect-metadata": "^0.2.1",
|
||||
@@ -3428,6 +3429,18 @@
|
||||
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/asn1.js": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
|
||||
"integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bn.js": "^4.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"safer-buffer": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
@@ -3715,6 +3728,12 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/bn.js": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
@@ -4262,6 +4281,23 @@
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/connect-mongo": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/connect-mongo/-/connect-mongo-5.1.0.tgz",
|
||||
"integrity": "sha512-xT0vxQLqyqoUTxPLzlP9a/u+vir0zNkhiy9uAdHjSCcUUf7TS5b55Icw8lVyYFxfemP3Mf9gdwUOgeF3cxCAhw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.1",
|
||||
"kruptein": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"express-session": "^1.17.1",
|
||||
"mongodb": ">= 5.1.0 < 7"
|
||||
}
|
||||
},
|
||||
"node_modules/consola": {
|
||||
"version": "2.15.3",
|
||||
"resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
|
||||
@@ -7121,6 +7157,18 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/kruptein": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/kruptein/-/kruptein-3.0.6.tgz",
|
||||
"integrity": "sha512-EQJjTwAJfQkC4NfdQdo3HXM2a9pmBm8oidzH270cYu1MbgXPNPMJuldN7OPX+qdhPO5rw4X3/iKz0BFBfkXGKA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asn1.js": "^5.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">8"
|
||||
}
|
||||
},
|
||||
"node_modules/leven": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||
@@ -7381,6 +7429,12 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/minimalistic-assert": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"@nestjs/mongoose": "^10.0.6",
|
||||
"@nestjs/platform-express": "^10.3.2",
|
||||
"@nestjs/swagger": "^7.3.1",
|
||||
"connect-mongo": "^5.1.0",
|
||||
"express-session": "^1.18.0",
|
||||
"mongoose": "^8.4.1",
|
||||
"reflect-metadata": "^0.2.1",
|
||||
|
||||
+5
-2
@@ -10,8 +10,11 @@ import { CardsService } from './cards/cards.service';
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot(),
|
||||
MongooseModule.forRoot('mongodb://localhost:27017', {
|
||||
auth: { password: 'example', username: 'root' },
|
||||
MongooseModule.forRoot(process.env.MONGO_ENDPOINT, {
|
||||
auth: {
|
||||
password: process.env.MONGO_PASSWORD,
|
||||
username: process.env.MONGO_USER,
|
||||
},
|
||||
dbName: 'heron',
|
||||
}),
|
||||
GamesModule,
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export class CreateGameDto {}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Types } from 'mongoose';
|
||||
|
||||
export class DatabaseObjectDto {
|
||||
constructor(data: { _id: Types.ObjectId }) {
|
||||
this._id = data._id.toString();
|
||||
}
|
||||
|
||||
@ApiProperty()
|
||||
_id: string;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { DatabaseObjectDto } from './database-object.dto';
|
||||
import { Container, Team } from '../schemas/game.schema';
|
||||
import { User } from 'src/users/schemas/user.entity';
|
||||
|
||||
export class ReadTeamDto extends DatabaseObjectDto {
|
||||
constructor(data: ConstructorParameters<typeof DatabaseObjectDto>[0]) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
export class ReadContainerDto extends DatabaseObjectDto {
|
||||
constructor(data: ConstructorParameters<typeof DatabaseObjectDto>[0]) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
export class ReadUserDto extends DatabaseObjectDto {
|
||||
constructor(
|
||||
data: { username: string; avatar: string } & ConstructorParameters<
|
||||
typeof DatabaseObjectDto
|
||||
>[0],
|
||||
) {
|
||||
super(data);
|
||||
this.username = data.username;
|
||||
this.avatar = data.avatar;
|
||||
}
|
||||
|
||||
@ApiProperty()
|
||||
username: string;
|
||||
|
||||
@ApiProperty()
|
||||
avatar: string;
|
||||
}
|
||||
|
||||
export class ReadGameDto extends DatabaseObjectDto {
|
||||
constructor(
|
||||
data: {
|
||||
teams: Team[];
|
||||
market: Container;
|
||||
marketStack: Container;
|
||||
fireGems: Container;
|
||||
currentTurn?: Team;
|
||||
started: boolean;
|
||||
ended: boolean;
|
||||
owner: User;
|
||||
} & ConstructorParameters<typeof DatabaseObjectDto>[0],
|
||||
) {
|
||||
super(data);
|
||||
this.teams = data.teams.map((e) => new ReadTeamDto(e));
|
||||
this.market = new ReadContainerDto(data.market);
|
||||
this.marketStack = new ReadContainerDto(data.marketStack);
|
||||
this.fireGems = new ReadContainerDto(data.fireGems);
|
||||
this.started = data.started;
|
||||
this.ended = data.ended;
|
||||
this.owner = new ReadUserDto(data.owner);
|
||||
|
||||
if (data.currentTurn) {
|
||||
this.currentTurn = new ReadTeamDto(data.currentTurn);
|
||||
}
|
||||
}
|
||||
|
||||
@ApiProperty()
|
||||
teams: ReadTeamDto[];
|
||||
|
||||
@ApiProperty()
|
||||
market: ReadContainerDto;
|
||||
|
||||
@ApiProperty()
|
||||
marketStack: ReadContainerDto;
|
||||
|
||||
@ApiProperty()
|
||||
fireGems: ReadContainerDto;
|
||||
|
||||
@ApiProperty()
|
||||
currentTurn?: ReadTeamDto;
|
||||
|
||||
@ApiProperty()
|
||||
started: boolean;
|
||||
|
||||
@ApiProperty()
|
||||
ended: boolean;
|
||||
|
||||
@ApiProperty()
|
||||
owner: ReadUserDto;
|
||||
}
|
||||
@@ -1,4 +1 @@
|
||||
import { PartialType } from '@nestjs/mapped-types';
|
||||
import { CreateGameDto } from './create-game.dto';
|
||||
|
||||
export class UpdateGameDto extends PartialType(CreateGameDto) {}
|
||||
export class UpdateGameDto {}
|
||||
|
||||
@@ -2,32 +2,56 @@ import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
UseGuards,
|
||||
Session,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
import { GamesService } from './games.service';
|
||||
import { CreateGameDto } from './dto/create-game.dto';
|
||||
import { UpdateGameDto } from './dto/update-game.dto';
|
||||
import { AuthGuard } from './guards/auth.guard';
|
||||
import { ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import { DatabaseObjectDto } from './dto/database-object.dto';
|
||||
|
||||
@Controller('games')
|
||||
export class GamesController {
|
||||
constructor(private readonly gamesService: GamesService) {}
|
||||
|
||||
@Post()
|
||||
create() {
|
||||
return this.gamesService.create();
|
||||
@ApiOperation({ summary: 'Create game' })
|
||||
@ApiResponse({
|
||||
status: 201,
|
||||
description: 'Game successfully created.',
|
||||
type: DatabaseObjectDto,
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'You can only create one game at a time',
|
||||
})
|
||||
@ApiResponse({ status: 403, description: 'Forbidden.' })
|
||||
@UseGuards(AuthGuard)
|
||||
async create(@Session() session: Record<string, any>) {
|
||||
const games = await this.gamesService.findByOwner(session.user._id);
|
||||
if (games.length > 0) {
|
||||
throw new HttpException(
|
||||
'You can only create one game at a time',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
return this.gamesService.create(session.user);
|
||||
}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'List all games' })
|
||||
findAll() {
|
||||
return this.gamesService.findAll();
|
||||
const games = this.gamesService.findAll();
|
||||
return games;
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
findOne(@Param('id') id: string) {
|
||||
return this.gamesService.findOne(id);
|
||||
return this.gamesService.findById(id);
|
||||
}
|
||||
|
||||
// @Patch(':id')
|
||||
|
||||
@@ -1,24 +1,33 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CreateGameDto } from './dto/create-game.dto';
|
||||
import { UpdateGameDto } from './dto/update-game.dto';
|
||||
import { DatabaseObjectDto } from './dto/database-object.dto';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Game } from './schemas/game.schema';
|
||||
import { Model } from 'mongoose';
|
||||
import { ReadGameDto } from './dto/read-games.dto';
|
||||
import { User } from 'src/users/schemas/user.entity';
|
||||
|
||||
@Injectable()
|
||||
export class GamesService {
|
||||
constructor(@InjectModel(Game.name) private gameModel: Model<Game>) {}
|
||||
async create(): Promise<Game> {
|
||||
|
||||
async create(owner: User): Promise<DatabaseObjectDto> {
|
||||
const createdGame = new this.gameModel();
|
||||
return createdGame.save();
|
||||
createdGame.owner = owner;
|
||||
const gamedata = await createdGame.save();
|
||||
return new DatabaseObjectDto(gamedata);
|
||||
}
|
||||
|
||||
findAll() {
|
||||
return this.gameModel.find();
|
||||
async findAll(): Promise<ReadGameDto[]> {
|
||||
const games = await this.gameModel.find().exec();
|
||||
return games.map((e) => new ReadGameDto(e));
|
||||
}
|
||||
|
||||
findOne(id: string) {
|
||||
return this.gameModel.find({ _id: id }).exec();
|
||||
findById(id: string) {
|
||||
return this.gameModel.findById(id).exec();
|
||||
}
|
||||
|
||||
findByOwner(_id: string) {
|
||||
return this.gameModel.find({ owner: _id }).exec();
|
||||
}
|
||||
|
||||
// update(id: number, updateGameDto: UpdateGameDto) {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import {
|
||||
Injectable,
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
import { Request } from 'express';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class AuthGuard implements CanActivate {
|
||||
canActivate(
|
||||
context: ExecutionContext,
|
||||
): boolean | Promise<boolean> | Observable<boolean> {
|
||||
const http = context.switchToHttp();
|
||||
const request = http.getRequest<Request>();
|
||||
if (!(request.session as Record<string, any>).user) {
|
||||
throw new HttpException('Please log in', HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,17 @@
|
||||
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||
import mongoose, { HydratedDocument } from 'mongoose';
|
||||
import mongoose, { HydratedDocument, Types } from 'mongoose';
|
||||
import { Card } from 'src/cards/schemas/cards.schema';
|
||||
import { User } from 'src/users/schemas/user.entity';
|
||||
|
||||
export type GameDocument = HydratedDocument<Game>;
|
||||
|
||||
@Schema()
|
||||
class GameObject {}
|
||||
|
||||
@Schema()
|
||||
export class Team extends GameObject {}
|
||||
export class Team extends Types.ObjectId {}
|
||||
|
||||
export const TeamSchema = SchemaFactory.createForClass(Team);
|
||||
|
||||
@Schema()
|
||||
export class Container extends GameObject {
|
||||
export class Container extends Types.ObjectId {
|
||||
@Prop([{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }])
|
||||
cards: Card[];
|
||||
}
|
||||
@@ -22,7 +19,7 @@ export class Container extends GameObject {
|
||||
export const ContainerSchema = SchemaFactory.createForClass(Container);
|
||||
|
||||
@Schema()
|
||||
export class Game extends GameObject {
|
||||
export class Game extends Types.ObjectId {
|
||||
@Prop([Team])
|
||||
teams: Team[];
|
||||
|
||||
@@ -42,7 +39,7 @@ export class Game extends GameObject {
|
||||
started: boolean;
|
||||
|
||||
@Prop({ default: false })
|
||||
private ended: boolean;
|
||||
ended: boolean;
|
||||
|
||||
@Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'User' })
|
||||
owner: User;
|
||||
|
||||
+14
-2
@@ -2,6 +2,7 @@ import { NestFactory } from '@nestjs/core';
|
||||
import * as session from 'express-session';
|
||||
import { AppModule } from './app.module';
|
||||
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||
import MongoStore from 'connect-mongo';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
@@ -15,11 +16,22 @@ async function bootstrap() {
|
||||
SwaggerModule.setup('api', app, document);
|
||||
|
||||
app.use(
|
||||
session({
|
||||
secret: 'my-secret',
|
||||
session.default({
|
||||
secret: process.env.SESSION_SECRET,
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
name: 'heron.session',
|
||||
store: MongoStore.create({
|
||||
collectionName: 'sessions',
|
||||
dbName: 'heron',
|
||||
mongoUrl: process.env.MONGO_ENDPOINT,
|
||||
mongoOptions: {
|
||||
auth: {
|
||||
password: process.env.MONGO_PASSWORD,
|
||||
username: process.env.MONGO_USER,
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
import { PartialType } from '@nestjs/mapped-types';
|
||||
import { CreateUserDto } from './create-user.dto';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class LoginDto extends PartialType(CreateUserDto) {
|
||||
constructor(id: string, global_name: string, avatar: string) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.global_name = global_name;
|
||||
export class LoginDto {
|
||||
constructor(userId: string, username: string, avatar: string) {
|
||||
this.userId = userId;
|
||||
this.username = username;
|
||||
this.avatar = avatar;
|
||||
}
|
||||
@ApiProperty()
|
||||
id: string;
|
||||
userId: string;
|
||||
|
||||
@ApiProperty()
|
||||
global_name: string;
|
||||
username: string;
|
||||
|
||||
@ApiProperty()
|
||||
avatar: string;
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
import { Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||
import { HydratedDocument } from 'mongoose';
|
||||
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||
import { HydratedDocument, Types } from 'mongoose';
|
||||
|
||||
export type UserDocument = HydratedDocument<User>;
|
||||
|
||||
@Schema()
|
||||
export class User {}
|
||||
export class User extends Types.ObjectId {
|
||||
@Prop()
|
||||
userId: string;
|
||||
|
||||
@Prop()
|
||||
avatar: string;
|
||||
|
||||
@Prop()
|
||||
username: string;
|
||||
}
|
||||
|
||||
export const UserSchema = SchemaFactory.createForClass(User);
|
||||
|
||||
@@ -19,13 +19,9 @@ export class UsersController {
|
||||
async login(
|
||||
@Query('code') code: string,
|
||||
@Session() session: Record<string, any>,
|
||||
) {
|
||||
const tokenData = await this.usersService.saveDiscordToken(code);
|
||||
session.tokenData = tokenData;
|
||||
const user = await this.usersService.useDiscordToken(
|
||||
tokenData.token_type,
|
||||
tokenData.token,
|
||||
);
|
||||
): Promise<LoginDto> {
|
||||
await this.usersService.createDiscordToken({ code }, session);
|
||||
const user = await this.usersService.discordLogin(session);
|
||||
return user;
|
||||
}
|
||||
|
||||
@@ -37,10 +33,7 @@ export class UsersController {
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const user = await this.usersService.useDiscordToken(
|
||||
session.tokenData.token_type,
|
||||
session.tokenData.token,
|
||||
);
|
||||
const user = await this.usersService.discordLogin(session);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
+94
-25
@@ -1,30 +1,67 @@
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { LoginDto } from './dto/login.dto';
|
||||
import { URLSearchParams } from 'url';
|
||||
import { User } from './schemas/user.entity';
|
||||
import { Model } from 'mongoose';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
async saveDiscordToken(code: string) {
|
||||
constructor(@InjectModel(User.name) private userModel: Model<User>) {}
|
||||
|
||||
async createDiscordToken(
|
||||
{
|
||||
code,
|
||||
refresh_token,
|
||||
}: {
|
||||
code?: string;
|
||||
refresh_token?: string;
|
||||
},
|
||||
session: Record<string, any>,
|
||||
): Promise<void> {
|
||||
let body;
|
||||
if (code) {
|
||||
body = new URLSearchParams({
|
||||
client_id: process.env.DISCORD_CLIENTID,
|
||||
client_secret: process.env.DISCORD_CLIENTSECRET,
|
||||
code,
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: process.env.API_ENDPOINT + '/login',
|
||||
});
|
||||
} else if (refresh_token) {
|
||||
body = new URLSearchParams({
|
||||
client_id: process.env.DISCORD_CLIENTID,
|
||||
client_secret: process.env.DISCORD_CLIENTSECRET,
|
||||
refresh_token,
|
||||
grant_type: 'refresh_token',
|
||||
});
|
||||
} else {
|
||||
throw new HttpException(
|
||||
'Invalid internal call',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const req = await fetch('https://discord.com/api/oauth2/token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
client_id: process.env.DISCORD_CLIENTID,
|
||||
client_secret: process.env.DISCORD_CLIENTSECRET,
|
||||
code: code,
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: process.env.API_ENDPOINT + '/login',
|
||||
scope: 'identify',
|
||||
}),
|
||||
body,
|
||||
});
|
||||
if (!req.ok) {
|
||||
console.error(await req.json());
|
||||
throw new HttpException(
|
||||
"Couldn't fetch Discord api",
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
const data = await req.json();
|
||||
if (data.error == 'invalid_grant') {
|
||||
throw new HttpException(
|
||||
'Invalid code in request',
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
} else {
|
||||
console.error(data);
|
||||
throw new HttpException(
|
||||
"Couldn't fetch Discord api",
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
const data = await req.json();
|
||||
if (!data.token_type || !data.access_token) {
|
||||
@@ -34,27 +71,59 @@ export class UsersService {
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const token_type = data.token_type;
|
||||
const token = data.access_token;
|
||||
|
||||
return { token, token_type };
|
||||
const expires = new Date(Date.now() + data.expires_in);
|
||||
session.tokenData = {
|
||||
access_token: data.access_token,
|
||||
token_type: data.token_type,
|
||||
refresh_token: data.refresh_token,
|
||||
expires,
|
||||
};
|
||||
}
|
||||
|
||||
async useDiscordToken(token_type: string, token: string) {
|
||||
async discordLogin(
|
||||
session: Record<string, any>,
|
||||
recursive: boolean = false,
|
||||
): Promise<LoginDto> {
|
||||
const req2 = await fetch('https://discord.com/api/users/@me', {
|
||||
headers: {
|
||||
authorization: token_type + ' ' + token,
|
||||
authorization:
|
||||
session.tokenData.token_type + ' ' + session.tokenData.access_token,
|
||||
},
|
||||
});
|
||||
|
||||
if (!req2.ok) {
|
||||
throw new HttpException(
|
||||
"Couldn't fetch Discord api",
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
const error = await req2.json();
|
||||
if (error.error == 'invalid_grant' && !recursive) {
|
||||
await this.createDiscordToken(
|
||||
{
|
||||
refresh_token: session.tokenData.refresh_token,
|
||||
},
|
||||
session,
|
||||
);
|
||||
return this.discordLogin(session);
|
||||
} else {
|
||||
console.error(error);
|
||||
throw new HttpException(
|
||||
"Couldn't fetch Discord api",
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
const data2 = await req2.json();
|
||||
return new LoginDto(data2.id, data2.global_name, data2.avatar);
|
||||
console.log(data2);
|
||||
const dto = new LoginDto(data2.id, data2.global_name, data2.avatar);
|
||||
const user = await this.getOrCreateUser(dto.userId, dto);
|
||||
session.user = user;
|
||||
return dto;
|
||||
}
|
||||
|
||||
async getOrCreateUser(userId: string, data?: LoginDto) {
|
||||
let user = await this.userModel.findOne({ userId }).exec();
|
||||
if (!user) {
|
||||
const createdUser = new this.userModel({ ...data, userId });
|
||||
user = await createdUser.save();
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
remove(id: number) {
|
||||
|
||||
+2
-1
@@ -11,6 +11,7 @@
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user