Skip to content

Commit

Permalink
stats, jwt, existing user
Browse files Browse the repository at this point in the history
  • Loading branch information
Koushik Phani authored and Koushik Phani committed Jun 23, 2024
1 parent 7a7f565 commit eb2e33a
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Place your settings in this file to overwrite default and user settings.
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"eslint.validate": ["javascript", "typescript"],
"editor.formatOnSave": true,
Expand Down
1 change: 1 addition & 0 deletions src/config/passport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ passport.use(

const existingUser = await prisma.user.findUnique({
where: { googleId: profile.id },
include: { chessInfo: true },
});

if (existingUser) {
Expand Down
25 changes: 22 additions & 3 deletions src/controllers/authController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { ChessVerificationService } from '../services/chessVerificationService';
import { logger } from '../utils/logger';
import { PrismaClient } from '@prisma/client';
import { User } from '../models/User';
import jwt from 'jsonwebtoken';
import { createOrUpdateChessInfo } from '../services/chessInfoService';

const prisma = new PrismaClient();

Expand All @@ -19,12 +21,14 @@ export class AuthController {
public initiateChessVerification = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const { chessUsername } = req.body;
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
const isValid = await this.chessVerificationService.isValidChessComId(chessUsername);
if (!isValid) {
res.status(400).json({ error: 'Invalid Chess.com username' });
return;
}
const verificationCode = await this.chessVerificationService.generateVerificationCode(chessUsername);
const verificationCode = token;
res.json({ verificationCode });
} catch (error) {
next(error);
Expand All @@ -35,13 +39,24 @@ export class AuthController {
try {
const { chessUsername } = req.body;
const user = req.user as User;
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];

if (!user) {
res.status(400).json({ error: 'User not found' });
return;
}

const isVerified = await this.chessVerificationService.verifyChessProfile(chessUsername);
let verificationCode: string | undefined;
const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as { [key: string]: any };
verificationCode = decoded.verificationCode;

if (!verificationCode) {
res.status(400).json({ error: 'Verification token not found in JWT' });
return;
}

const isVerified = await this.chessVerificationService.verifyChessProfile(chessUsername,verificationCode);
if (isVerified) {
await prisma.user.update({
where: { id: user.id },
Expand All @@ -60,7 +75,11 @@ export class AuthController {
try {
const user = req.user as User;
const token = await this.authService.generateToken(user);
res.json({ token });
let stats
if(user.chessUsername){
stats = await createOrUpdateChessInfo(user.chessUsername, user.id);
}
res.json({ token, stats });
} catch (error) {
next(error);
}
Expand Down
7 changes: 5 additions & 2 deletions src/services/authService.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import jwt from 'jsonwebtoken';
import { User } from '../models/User';
import { ChessVerificationService } from './chessVerificationService';
import { generateVerificationCode } from '../utils/generator';

export class AuthService {
public generateToken(user: User): string {
return jwt.sign({ id: user.id }, process.env.JWT_SECRET as string, {
public async generateToken(user: User): Promise<string> {
const verificationCode = await generateVerificationCode();
return jwt.sign({ id: user.id, verificationCode:verificationCode, chessUsername: user.chessUsername }, process.env.JWT_SECRET as string, {
expiresIn: '1d',
});
}
Expand Down
38 changes: 34 additions & 4 deletions src/services/chessInfoService.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,49 @@
import axios from 'axios';
import { PrismaClient } from '@prisma/client';
import { chessComConfig } from '../config/chesscom';
import { chessComConfig } from '../config/chesscom'; // Adjust the import according to your project structure

const prisma = new PrismaClient();

interface ChessStats {
chess_rapid: {
last: {
rating: number;
};
};
chess_bullet: {
last: {
rating: number;
};
};
chess_blitz: {
last: {
rating: number;
};
};
puzzle_rush: {
best: {
score: number;
};
};
}

export const createOrUpdateChessInfo = async (chessUsername: string, userId: string) => {
try {
const response = await axios.get(`${chessComConfig.baseURL}/${chessUsername}/stats`, { headers: chessComConfig.headers });
const { blitz, bullet, rapid, puzzle } = response.data;
const data: ChessStats = response.data;

const blitz = data.chess_blitz?.last?.rating ?? 0;
const bullet = data.chess_bullet?.last?.rating ?? 0;
const rapid = data.chess_rapid?.last?.rating ?? 0;
const puzzle = data.puzzle_rush?.best?.score ?? 0;

await prisma.chessInfo.upsert({
const stats = await prisma.chessInfo.upsert({
where: { userId },
update: { blitz, bullet, rapid, puzzle },
create: { id: userId, blitz, bullet, rapid, puzzle, userId },
create: { blitz, bullet, rapid, puzzle, user: { connect: { id: userId } } },
});

return stats;
} catch (error) {
console.error('Failed to fetch or update Chess.com stats', error);
}
Expand Down
9 changes: 4 additions & 5 deletions src/services/chessVerificationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,21 @@ export class ChessVerificationService {
return isValidChessComId(chessUsername);
}

public async generateVerificationCode(chessUsername: string): Promise<string> {
public async generateVerificationCodeWithUsername(chessUsername: string): Promise<string> {
const verificationCode = Math.random().toString(36).substring(2, 15);
await redisClient.set(chessUsername, verificationCode, { EX: 3600 }); // Expires in 1 hour
return verificationCode;
}

public async verifyChessProfile(chessUsername: string): Promise<boolean> {
const storedCode = await redisClient.get(chessUsername);
if (!storedCode) {
public async verifyChessProfile(chessUsername: string, verificationCode: string): Promise<boolean> {
if (!verificationCode) {
throw new Error('Verification code expired or not found');
}

try {
const response = await axios.get(`${chessComConfig.baseURL}/${chessUsername}`, { headers: chessComConfig.headers });
const profileData = response.data;
return profileData.location === storedCode;
return profileData.location === verificationCode;
} catch (error) {
throw new Error('Failed to verify Chess.com profile');
}
Expand Down
4 changes: 4 additions & 0 deletions src/utils/generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const generateVerificationCode= async() :Promise<string> =>{
const verificationCode = Math.random().toString(36).substring(2, 15);
return verificationCode;
}

0 comments on commit eb2e33a

Please sign in to comment.