Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1927a19
fix: add missing entity relationships to Post entity
clintjeff2 Jul 23, 2025
f9978e7
fix: correct import path for Post entity in Like entity
clintjeff2 Jul 23, 2025
53ae541
fix: correct import path for Post entity in Comment entity
clintjeff2 Jul 23, 2025
6e18d2c
fix: correct Post import and entity relationships in SavedPost
clintjeff2 Jul 23, 2025
af55828
fix: correct freelancer relationship type from any to User entity
clintjeff2 Jul 23, 2025
2e0ea89
feat: create JobAdapter to bridge Job entity and job-posting DTOs
clintjeff2 Jul 23, 2025
81a93b7
fix: update DataSource injection and implement JobAdapter usage
clintjeff2 Jul 23, 2025
751849d
fix: add proper DataSource injection decorator
clintjeff2 Jul 23, 2025
96233ab
fix: resolve circular dependency with forwardRef for JobsService
clintjeff2 Jul 23, 2025
fcb27a1
fix: disable JobCleanupTask temporarily and remove duplicate providers
clintjeff2 Jul 23, 2025
cd1ecda
fix: rename JobModule to JobPostingModule to resolve naming conflict
clintjeff2 Jul 23, 2025
18e93ad
fix: remove duplicate JwtAuthGuard provider registration
clintjeff2 Jul 23, 2025
0e67daf
fix: add missing entities to TypeORM configuration and resolve imports
clintjeff2 Jul 23, 2025
16f44fe
fix: add proper DataSource injection decorator to BackupService
clintjeff2 Jul 23, 2025
e7084f0
fix: add error handling for mail transporter initialization and SSL i…
clintjeff2 Jul 23, 2025
a3d8984
fix: add Job relationship and additional timestamp fields to Escrow e…
clintjeff2 Jul 23, 2025
09f557b
fix: add missing imports and clean up controller methods
clintjeff2 Jul 23, 2025
0f3ec7b
feat: add escrow methods for fund locking and releasing
clintjeff2 Jul 23, 2025
6a2a3ad
feat: add CreateEscrowDto extending InitiatePaymentDto
clintjeff2 Jul 23, 2025
39e32e6
feat: create ReleaseEscrowDto for payment release functionality
clintjeff2 Jul 23, 2025
3531e3e
fix: update import paths and add missing decorators for auth endpoints
clintjeff2 Jul 23, 2025
ba99ca4
fix: add JwtAuthGuard to providers and resolve module configuration
clintjeff2 Jul 23, 2025
06ace4f
fix: update LoginDto import and add missing auth methods
clintjeff2 Jul 23, 2025
f04c5d8
fix: add UnauthorizedException import for proper error handling
clintjeff2 Jul 23, 2025
34e80b8
fix: add null check for freelancer in job status notification
clintjeff2 Jul 23, 2025
10eda03
feat: add missing job status values (ACTIVE, EXPIRED, ARCHIVED)
clintjeff2 Jul 23, 2025
cd1ad1a
feat: add EXPIRED and ARCHIVED status values to JobStatus enum
clintjeff2 Jul 23, 2025
db35b06
fix: add MailModule import to notifications module
clintjeff2 Jul 23, 2025
b566e87
fix: improve notification service method structure and error handling
clintjeff2 Jul 23, 2025
a971af5
fix: add missing entities (SkillVerification, Like) to data source co…
clintjeff2 Jul 23, 2025
77a6020
fix: update compression import to use default import syntax
clintjeff2 Jul 23, 2025
3f4c543
feat: add comprehensive git commit script for all NestJS project fixes
clintjeff2 Jul 23, 2025
97af55e
feat: implement comprehensive pagination DTO with filtering and sorti…
clintjeff2 Jul 23, 2025
e79b011
feat: implement findAll method with advanced filtering, pagination an…
clintjeff2 Jul 23, 2025
332b00b
feat: enhance job controller with comprehensive API documentation and…
clintjeff2 Jul 23, 2025
f7e3376
chore: remove temporary commit script file
clintjeff2 Jul 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/admin/admin.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { RolesGuard } from '../auth/guards/roles.guard';
}),
],
controllers: [AdminController],
providers: [AdminService, JwtAuthGuard, RolesGuard],
providers: [AdminService, RolesGuard],
exports: [AdminService],
})
export class AdminModule {}
24 changes: 18 additions & 6 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { ScheduleModule } from '@nestjs/schedule';
import { AuthModule } from './auth/auth.module';
import { User } from './auth/entities/user.entity';
import { Message } from './messaging/entities/message.entity';
import { EmailToken } from './auth/entities/email-token.entity';
import { PasswordReset } from './auth/entities/password-reset.entity';
import { Message } from './messaging/entities/messaging.entity';
import { FeedModule } from './feed/feed.module';
import { PostModule } from './post/post.module';
import * as dotenv from 'dotenv';
import { SavedPost } from './feed/entities/savedpost.entity';
import { Post } from './post/entities/post.entity';
import { Post } from './feed/entities/post.entity';
import { MessagingModule } from './messaging/messaging.module';
import { Team } from './auth/entities/team.entity';
import { TeamMember } from './auth/entities/team-member.entity';
Expand All @@ -21,8 +23,12 @@ import { ApplicationsModule } from './applications/applications.module';
import { AdminModule } from './admin/admin.module';
import { ReportsModule } from './reports/reports.module';
import { Comment } from './feed/entities/comment.entity';
import { Like } from './feed/entities/like.entity';
import { Job } from './jobs/entities/job.entity';
import { SavedJob } from './jobs/entities/saved-job.entity';
import { Recommendation } from './jobs/entities/recommendation.entity';
import { Portfolio } from './auth/entities/portfolio.entity';
import { SkillVerification } from './auth/entities/skills-verification.entity';
import { Report } from './reports/entities/report.entity';
import { BackupModule } from './backup/backup.module';
import { Backup } from './backup/entities/backup.entity';
Expand Down Expand Up @@ -55,13 +61,19 @@ dotenv.config();
database: configService.get<string>('DB_NAME'),
entities: [
User,
EmailToken,
PasswordReset,
SavedPost,
Post,
Application,
Message,
Comment,
Like,
Job,
SavedJob,
Recommendation,
Portfolio,
SkillVerification,
Report,
Team,
TeamMember,
Expand Down Expand Up @@ -95,10 +107,10 @@ dotenv.config();
AvailabilityModule,
],
providers: [
{
provide: APP_GUARD,
useClass: RateLimitGuard,
},
// {
// provide: APP_GUARD,
// useClass: RateLimitGuard,
// },
Comment on lines +110 to +113
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify if RateLimitGuard should remain commented out.

The global RateLimitGuard provider is commented out, which removes rate limiting protection from the entire application. This could be a security concern if intentional for production.

Please confirm if this is intentional:


🏁 Script executed:

#!/bin/bash
# Description: Check if there are alternative rate limiting mechanisms in place
# Expected: Find other rate limiting configurations or guards

rg -i "rate.?limit|throttl" --type ts -A 3 -B 3

Length of output: 2478


Global RateLimitGuard is disabled—no rate limiting in effect
The ThrottlerModule is configured (100 requests per minute), but the global RateLimitGuard provider is commented out and not used elsewhere. This means no rate-limiting guard is bound, leaving the app unprotected.

• File src/app.module.ts (around lines 110–113):

   providers: [
-    // {
-    //   provide: APP_GUARD,
-    //   useClass: RateLimitGuard,
-    // },
+    {
+      provide: APP_GUARD,
+      useClass: RateLimitGuard,
+    },
   ],

If you intentionally disabled global throttling for development, ensure you apply @UseGuards(RateLimitGuard) on critical controllers or restore the provider before production.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// {
// provide: APP_GUARD,
// useClass: RateLimitGuard,
// },
providers: [
{
provide: APP_GUARD,
useClass: RateLimitGuard,
},
],
🤖 Prompt for AI Agents
In src/app.module.ts around lines 110 to 113, the global RateLimitGuard provider
is commented out, so no rate limiting is enforced despite the ThrottlerModule
configuration. To fix this, either uncomment and restore the global
RateLimitGuard provider in the module's providers array to enable app-wide
throttling, or if you want selective throttling, apply the
@UseGuards(RateLimitGuard) decorator on critical controllers where rate limiting
is needed.

],
})
export class AppModule {}
19 changes: 16 additions & 3 deletions src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,25 @@ import {
UnauthorizedException,
Put,
} from '@nestjs/common';
import {
ApiTags,
ApiOperation,
ApiResponse,
ApiUnauthorizedResponse,
ApiBearerAuth,
} from '@nestjs/swagger';
import type { AuthService } from './auth.service';
import type { RegisterDto } from './dto/register-user.dto';
import { LoginDto } from './dto/login-user.dto';
import { RefreshTokenDto } from './dto/refresh-token.dto';
import { User } from './entities/user.entity';
import type { FeedService } from '../feed/feed.service';
import type { JobsService } from '../jobs/jobs.service';
import type { GetUsersDto } from './dto/get-users.dto';
import type { SuspendUserDto } from './dto/suspend-user.dto';
import type { TeamService } from './services/team.service';
import { LogInProvider } from './providers/loginProvider';
import { Public } from './decorators/public.decorator';
// ... keep other imports from main ...

@ApiTags('auth')
Expand Down Expand Up @@ -53,7 +64,7 @@ export class AuthController {
},
})
@ApiUnauthorizedResponse({ description: 'Invalid credentials' })
async login(@Body() loginDto: LogInDto) {
async login(@Body() loginDto: LoginDto) {
return this.authService.login(loginDto);
}

Expand All @@ -75,7 +86,9 @@ export class AuthController {
@ApiUnauthorizedResponse({ description: 'Invalid refresh token' })
async refreshToken(@Body() refreshTokenDto: RefreshTokenDto) {
try {
const tokens = await this.authService.refreshTokens(refreshTokenDto.refreshToken);
const tokens = await this.authService.refreshTokens(
refreshTokenDto.refreshToken,
);
return {
accessToken: tokens.accessToken,
refreshToken: tokens.refreshToken,
Expand All @@ -93,4 +106,4 @@ export class AuthController {
}

// ... keep all other endpoints from main branch ...
}
}
11 changes: 7 additions & 4 deletions src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,16 @@ import { SkillVerification } from './entities/skills-verification.entity';
useFactory: async (configService: ConfigService) => {
const secret = configService.get<string>('JWT_SECRET');
const refreshSecret = configService.get<string>('JWT_REFRESH_SECRET');

if (!secret) {
throw new Error('JWT_SECRET environment variable is required');
}
if (!refreshSecret) {
throw new Error('JWT_REFRESH_SECRET environment variable is required');
throw new Error(
'JWT_REFRESH_SECRET environment variable is required',
);
}

return {
secret,
signOptions: { expiresIn: '15m' },
Expand All @@ -82,6 +84,7 @@ import { SkillVerification } from './entities/skills-verification.entity';
},
JwtStrategy,
JwtRefreshStrategy,
JwtAuthGuard,
{
provide: APP_GUARD,
useClass: JwtAuthGuard,
Expand All @@ -102,4 +105,4 @@ import { SkillVerification } from './entities/skills-verification.entity';
GenerateTokensProvider,
],
})
export class AuthModule {}
export class AuthModule {}
148 changes: 136 additions & 12 deletions src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,18 @@ import { addHours, addDays, addMinutes } from 'date-fns';
import * as crypto from 'crypto';
import { MailService } from '../mail/mail.service';
import { ConfigService } from '@nestjs/config';
import type { LogInDto } from './dto/loginDto';
import type { LoginDto } from './dto/login-user.dto';
import { LogInProvider } from './providers/loginProvider';
import { JwtPayload } from './interfaces/jwt-payload.interface';
import { TeamService } from './services/team.service';
import { SkillVerification, VerificationStatus } from './entities/skills-verification.entity';
import type {
CreateSkillVerificationDto,
SkillAssessmentDto,
UpdateSkillVerificationDto
import {
SkillVerification,
VerificationStatus,
} from './entities/skills-verification.entity';
import type {
CreateSkillVerificationDto,
SkillAssessmentDto,
UpdateSkillVerificationDto,
} from './dto/skills.dto';
Comment on lines +27 to 35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove unused imports

The following imports are not used in this file and should be removed:

  • VerificationStatus (line 29)
  • CreateSkillVerificationDto (line 32)
  • SkillAssessmentDto (line 33)
  • UpdateSkillVerificationDto (line 34)
-import {
-  SkillVerification,
-  VerificationStatus,
-} from './entities/skills-verification.entity';
-import type {
-  CreateSkillVerificationDto,
-  SkillAssessmentDto,
-  UpdateSkillVerificationDto,
-} from './dto/skills.dto';
+import {
+  SkillVerification,
+} from './entities/skills-verification.entity';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import {
SkillVerification,
VerificationStatus,
} from './entities/skills-verification.entity';
import type {
CreateSkillVerificationDto,
SkillAssessmentDto,
UpdateSkillVerificationDto,
} from './dto/skills.dto';
import {
SkillVerification,
} from './entities/skills-verification.entity';
🧰 Tools
🪛 ESLint

[error] 29-29: 'VerificationStatus' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 32-32: 'CreateSkillVerificationDto' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 33-33: 'SkillAssessmentDto' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 34-34: 'UpdateSkillVerificationDto' is defined but never used.

(@typescript-eslint/no-unused-vars)

🤖 Prompt for AI Agents
In src/auth/auth.service.ts between lines 27 and 35, remove the unused imports
VerificationStatus, CreateSkillVerificationDto, SkillAssessmentDto, and
UpdateSkillVerificationDto to clean up the code and avoid unnecessary
dependencies.


@Injectable()
Expand Down Expand Up @@ -66,8 +69,8 @@ export class AuthService {

// ... [keep all other methods exactly as they are] ...

async login(loginDto: LogInDto): Promise<{
accessToken: string;
async login(loginDto: LoginDto): Promise<{
accessToken: string;
refreshToken: string;
user: Omit<User, 'password'>;
}> {
Expand All @@ -87,15 +90,136 @@ export class AuthService {
// Generate tokens using the refresh token flow
const tokens = await this.getTokens(user.id, user.email);
await this.updateRefreshToken(user.id, tokens.refreshToken);

// Remove password from the user object
const { password: _, ...userWithoutPassword } = user;

return {
...tokens,
user: userWithoutPassword
user: userWithoutPassword,
};
}

async getTokens(
userId: string,
email: string,
): Promise<{
accessToken: string;
refreshToken: string;
}> {
const jwtPayload: JwtPayload = {
sub: userId,
email: email,
};

const [accessToken, refreshToken] = await Promise.all([
this.jwtService.signAsync(jwtPayload, {
secret: this.configService.get<string>('JWT_SECRET'),
expiresIn: '15m',
}),
this.jwtService.signAsync(jwtPayload, {
secret: this.configService.get<string>('JWT_REFRESH_SECRET'),
expiresIn: '7d',
}),
]);

return {
accessToken,
refreshToken,
};
}

async updateRefreshToken(
userId: string,
refreshToken: string,
): Promise<void> {
const hashedRefreshToken = await bcrypt.hash(refreshToken, 10);
await this.userRepository.update(userId, {
refreshToken: hashedRefreshToken,
});
}

async refreshTokens(refreshToken: string): Promise<{
accessToken: string;
refreshToken: string;
}> {
const payload = this.jwtService.verify(refreshToken, {
secret: this.configService.get<string>('JWT_REFRESH_SECRET'),
});

const user = await this.userRepository.findOne({
where: { id: payload.sub },
});

if (!user || !user.refreshToken) {
throw new ForbiddenException('Access Denied');
}

const refreshTokenMatches = await bcrypt.compare(
refreshToken,
user.refreshToken,
);

if (!refreshTokenMatches) {
throw new ForbiddenException('Access Denied');
}

const tokens = await this.getTokens(user.id, user.email);
await this.updateRefreshToken(user.id, tokens.refreshToken);

return tokens;
}

async sendPasswordResetEmail(email: string): Promise<{ message: string }> {
const user = await this.userRepository.findOne({ where: { email } });

if (!user) {
// Don't reveal if email exists
return {
message:
'If an account with that email exists, a password reset email has been sent.',
};
}

// Generate reset token
const resetToken = crypto.randomBytes(32).toString('hex');
const expiresAt = addHours(new Date(), 1); // 1 hour expiration

// Save reset token
const passwordReset = this.passwordResetRepository.create({
user,
token: resetToken,
expiresAt,
});

await this.passwordResetRepository.save(passwordReset);

// Send email with reset link
const resetUrl = `${this.configService.get<string>('FRONTEND_URL')}/auth/reset-password?token=${resetToken}`;

await this.mailService.sendEmail({
to: email,
subject: 'Password Reset Request',
template: 'password-reset',
context: {
resetUrl,
expiresIn: '1 hour',
},
});

return {
message:
'If an account with that email exists, a password reset email has been sent.',
};
}

async getOneByEmail(email: string): Promise<User | null> {
return this.userRepository.findOne({ where: { email } });
}

async validateUserById(userId: string): Promise<User | null> {
return this.userRepository.findOne({ where: { id: userId } });
}

// ... [keep all other methods exactly as they are] ...
}
}
8 changes: 6 additions & 2 deletions src/auth/guards/jwt-auth.guard.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { ExecutionContext, Injectable } from '@nestjs/common';
import {
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { IS_PUBLIC_KEY } from '../decorators/public.decorator';
Expand Down Expand Up @@ -28,4 +32,4 @@ export class JwtAuthGuard extends AuthGuard('jwt') {
}
return user;
}
}
}
3 changes: 2 additions & 1 deletion src/backup/backup.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
NotFoundException,
BadRequestException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { InjectRepository, InjectDataSource } from '@nestjs/typeorm';
import { Repository, DataSource, LessThan } from 'typeorm';
import { ConfigService } from '@nestjs/config';
import { v4 as uuidv4 } from 'uuid';
Expand Down Expand Up @@ -47,6 +47,7 @@ export class BackupService {
constructor(
@InjectRepository(Backup)
private readonly backupRepository: Repository<Backup>,
@InjectDataSource()
private readonly dataSource: DataSource,
private readonly configService: ConfigService,
) {
Expand Down
4 changes: 4 additions & 0 deletions src/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { User } from './auth/entities/user.entity';
import { EmailToken } from './auth/entities/email-token.entity';
import { PasswordReset } from './auth/entities/password-reset.entity';
import { Portfolio } from './auth/entities/portfolio.entity';
import { SkillVerification } from './auth/entities/skills-verification.entity';
import { Post } from './feed/entities/post.entity';
import { Comment } from './feed/entities/comment.entity';
import { Like } from './feed/entities/like.entity';
import { SavedPost } from './feed/entities/savedpost.entity';
import { Job } from './jobs/entities/job.entity';
import { SavedJob } from './jobs/entities/saved-job.entity';
Expand All @@ -33,8 +35,10 @@ export const AppDataSource = new DataSource({
EmailToken,
PasswordReset,
Portfolio,
SkillVerification,
Post,
Comment,
Like,
SavedPost,
Job,
SavedJob,
Expand Down
Loading