Skip to content

Commit f656b4d

Browse files
authored
Merge pull request #212 from devchant/XP-Level-Tracking
feat: Added XP and level tracking to users
2 parents c08a5c9 + 2cd345e commit f656b4d

34 files changed

Lines changed: 1882 additions & 3116 deletions

backend/http/endpoint.http

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEsImVtYWlsI
99
"password": "FatimaAminu@123"
1010
}
1111

12+
GET http://localhost:3000/users
13+
1214

1315
POST http://localhost:3000/auth/signIn
1416
Content-Type: application/json
@@ -17,6 +19,16 @@ Content-Type: application/json
1719
"password": "FatimaAminu@123"
1820
}
1921

22+
### Submit puzzle answer (earns XP)
23+
POST http://localhost:3000/progress/submit
24+
Content-Type: application/json
25+
26+
{
27+
"userId": "1",
28+
"puzzleId": "dcebf04a-542f-464d-92e4-3ad983cde9ba",
29+
"answer": "42"
30+
}
31+
2032
POST http://localhost:3000/auth/signIn
2133
Content-Type: application/json
2234
Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEsImVtYWlsIjoiYW1pbnVmYXRpbWFAZ21haWwuY29tIiwiaWF0IjoxNzY5MzI0Mjk0LCJleHAiOjE3NjkzMjc4OTQsImF1ZCI6ImxvY2FsaG9zdDozMDAwIiwiaXNzIjoibG9jYWxob3N0OjMwMDAifQ.vqjgnN33AMD0j1wxX6e6912PDB2VMW23eVJUQYBZRAA
@@ -47,6 +59,7 @@ GET http://localhost:3000/puzzles?page=1&limit=10
4759
GET http://localhost:3000/puzzles?categoryId=397b1a88-3a41-4c14-afee-20f57554368b&difficulty=INTERMEDIATE&page=1&limit=10
4860

4961

62+
GET http://localhost:3000/users/1/xp-level
5063

5164

5265
GET http://localhost:3000/users?limit=10&page=1

backend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"@types/express": "^5.0.0",
6868
"@types/jest": "^29.5.14",
6969
"@types/node": "^22.10.7",
70+
"@types/nodemailer": "^7.0.9",
7071
"@types/passport-jwt": "^4.0.1",
7172
"@types/supertest": "^6.0.2",
7273
"eslint": "^9.18.0",

backend/src/auth/controllers/auth.controller.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ export class AuthController {
130130
public checkNonceStatus(@Query('nonce') nonce: string) {
131131
return this.authservice.checkNonceStatus(nonce);
132132
}
133-
134133
@Post('/forgot-password')
135134
@Throttle({ default: { limit: 3, ttl: 60000 } }) // 3 requests per minute
136135
@HttpCode(HttpStatus.OK)

backend/src/auth/providers/auth.service.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@ import { ResetPasswordProvider } from './reset-password.provider';
1212
import { ForgotPasswordDto } from '../dtos/forgot-password.dto';
1313
import { ResetPasswordDto } from '../dtos/reset-password.dto';
1414

15-
// interface OAuthUser {
16-
// email: string;
17-
// username: string;
18-
// picture: string;
19-
// accessToken: string;
20-
// }
21-
2215
@Injectable()
2316
export class AuthService {
2417
private nonces = new Map<
@@ -165,7 +158,6 @@ export class AuthService {
165158
public refreshToken(refreshTokenDto: RefreshTokenDto) {
166159
return this.refreshTokensProvider.refreshTokens(refreshTokenDto);
167160
}
168-
169161
public async forgotPassword(forgotPasswordDto: ForgotPasswordDto) {
170162
return await this.forgotPasswordProvider.forgotPassword(forgotPasswordDto);
171163
}

backend/src/auth/providers/generate-tokens.provider.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* eslint-disable prettier/prettier */
21
import { forwardRef, Inject, Injectable } from '@nestjs/common';
32
import { ApiTags, ApiOperation } from '@nestjs/swagger';
43
import { JwtService } from '@nestjs/jwt';
@@ -40,7 +39,12 @@ export class GenerateTokensProvider {
4039
* @returns A signed JWT token
4140
*/
4241
@ApiOperation({ summary: 'Sign JWT Token' })
43-
public async signToken<T>(userId: string, username: string, expiresIn: number, payload?: T) {
42+
public async signToken<T>(
43+
userId: string,
44+
username: string,
45+
expiresIn: number,
46+
payload?: T,
47+
) {
4448
return await this.jwtService.signAsync(
4549
{
4650
sub: userId,
@@ -62,17 +66,18 @@ export class GenerateTokensProvider {
6266
* @returns An object containing access and refresh tokens
6367
*/
6468
@ApiOperation({ summary: 'Generate Access and Refresh Tokens' })
65-
public async generateTokens(user: User) {
66-
if (!user.username) {
67-
throw new Error('user not found');
68-
}
69+
public async generateTokens(user: User) {
70+
if (!user.username) {
71+
throw new Error('user not found');
72+
}
6973

70-
const [accessToken, refreshToken] = await Promise.all([
71-
this.signToken(user.id, user.username, this.jwtConfiguration.ttl, { email: user.email }),
72-
this.signToken(user.id, user.username, this.jwtConfiguration.ttl)
73-
]);
74+
const [accessToken, refreshToken] = await Promise.all([
75+
this.signToken(user.id, user.username, this.jwtConfiguration.ttl, {
76+
email: user.email,
77+
}),
78+
this.signToken(user.id, user.username, this.jwtConfiguration.ttl),
79+
]);
7480

75-
return { accessToken, refreshToken, user };
81+
return { accessToken, refreshToken, user };
82+
}
7683
}
77-
78-
}

backend/src/auth/strategies/jwt.strategy.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { PassportStrategy } from '@nestjs/passport';
33
import { ExtractJwt, Strategy } from 'passport-jwt';
44
import { ConfigType } from '@nestjs/config';
55
import jwtConfig from '../authConfig/jwt.config';
6-
76
interface JwtPayload {
87
sub: string;
98
email: string;

backend/src/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ async function bootstrap() {
3737

3838
await app.listen(3000);
3939
}
40-
bootstrap();
40+
void bootstrap();

backend/src/progress/controllers/progress.controller.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ import {
66
UseGuards,
77
BadRequestException,
88
} from '@nestjs/common';
9-
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
9+
import {
10+
ApiTags,
11+
ApiOperation,
12+
ApiResponse,
13+
ApiBearerAuth,
14+
} from '@nestjs/swagger';
1015
import { AuthGuard } from '@nestjs/passport';
1116
import { paginationQueryDto } from '../../common/pagination/paginationQueryDto';
1217
import { GetProgressHistoryProvider } from '../providers/get-progress-history.provider';
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Controller, Post, Body } from '@nestjs/common';
2+
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
3+
import { ProgressService } from './progress.service';
4+
import { SubmitAnswerDto } from './dtos/submit-answer.dto';
5+
6+
@Controller('progress')
7+
@ApiTags('progress')
8+
export class ProgressController {
9+
constructor(private readonly progressService: ProgressService) {}
10+
11+
@Post('submit')
12+
@ApiOperation({ summary: 'Submit a puzzle answer' })
13+
@ApiResponse({ status: 200, description: 'Answer processed successfully' })
14+
async submitAnswer(@Body() submitAnswerDto: SubmitAnswerDto) {
15+
return this.progressService.submitAnswer(submitAnswerDto);
16+
}
17+
}

backend/src/progress/progress.module.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { GetCategoryStatsProvider } from './providers/get-category-stats.provide
1111
import { GetOverallStatsProvider } from './providers/get-overall-stats.provider';
1212
import { ProgressCalculationProvider } from './providers/progress-calculation.provider';
1313
import { Puzzle } from '../puzzles/entities/puzzle.entity';
14-
14+
import { XpLevelService } from '../users/providers/xp-level.service';
1515

1616
@Module({
1717
imports: [
@@ -24,7 +24,8 @@ import { Puzzle } from '../puzzles/entities/puzzle.entity';
2424
GetCategoryStatsProvider,
2525
GetOverallStatsProvider,
2626
ProgressCalculationProvider,
27+
XpLevelService,
2728
],
28-
exports: [ProgressService, ProgressCalculationProvider, TypeOrmModule],
29+
exports: [ProgressService, ProgressCalculationProvider],
2930
})
30-
export class ProgressModule {}
31+
export class ProgressModule {}

0 commit comments

Comments
 (0)