Feat : create games
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user