Skip to content
Closed

fix #151

Show file tree
Hide file tree
Changes from all commits
Commits
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
816 changes: 19 additions & 797 deletions BackEnd/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion BackEnd/src/modules/analytics/entities/payout.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
JoinColumn,
} from 'typeorm';
import { Submission } from './submission.entity';
import { User } from 'src/modules/users/entities/user.entity';
import { User } from '../../users/entities/user.entity';

/**
* Payout entity for tracking reward distributions
Expand Down
2 changes: 1 addition & 1 deletion BackEnd/src/modules/analytics/entities/quest.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
OneToMany,
} from 'typeorm';
import { Submission } from './submission.entity';
import { User } from 'src/modules/users/entities/user.entity';
import { User } from '../../users/entities/user.entity';

export enum QuestStatus {
ACTIVE = 'Active',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from 'typeorm';
import { Quest } from './quest.entity';
import { Payout } from './payout.entity';
import { User } from 'src/modules/users/entities/user.entity';
import { User } from '../../users/entities/user.entity';

export enum SubmissionStatus {
PENDING = 'Pending',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { UserAnalyticsQueryDto } from '../dto/analytics-query.dto';
import { DateRangeUtil } from '../utils/date-range.util';
import { ConversionUtil } from '../utils/conversion.util';
import { CacheService } from './cache.service';
import { User } from 'src/modules/users/entities/user.entity';
import { User } from '../../users/entities/user.entity';

@Injectable()
export class UserAnalyticsService {
Expand Down
2 changes: 1 addition & 1 deletion BackEnd/src/modules/auth/decorators/roles.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { SetMetadata } from '@nestjs/common';
import { UserRole } from 'src/modules/users/entities/user.entity';
import { UserRole } from '../../users/entities/user.entity';

export const ROLES_KEY = 'roles';
export const Roles = (...roles: UserRole[]) => SetMetadata(ROLES_KEY, roles);
2 changes: 1 addition & 1 deletion BackEnd/src/modules/auth/guards/roles.guard.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { ROLES_KEY } from '../decorators/roles.decorator';
import { UserRole } from 'src/modules/users/entities/user.entity';
import { UserRole } from '../../users/entities/user.entity';

@Injectable()
export class RolesGuard implements CanActivate {
Expand Down
36 changes: 34 additions & 2 deletions BackEnd/src/modules/cache/cache.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ export class CacheService {
}

/**
* Return current cache statistics.
* Get cache statistics.
*/
getStats(): CacheStats {
getStats(key?: string): CacheStats {
const total = this.hits + this.misses;
return {
hits: this.hits,
Expand All @@ -141,6 +141,38 @@ export class CacheService {
};
}

/**
* Clear all cache entries.
*/
async clear(): Promise<void> {
try {
await (this.cacheManager as any).reset();
this.logger.log('Cache cleared');
} catch (err) {
this.logger.warn(`Cache clear error: ${err.message}`);
}
}

/**
* Delete keys matching a pattern.
*/
async deletePattern(pattern: string): Promise<void> {
try {
const store = (this.cacheManager as any).store;
if (store && typeof store.keys === 'function') {
const keys: string[] = await store.keys(pattern);
if (keys.length > 0) {
await Promise.all(keys.map((k) => this.cacheManager.del(k)));
this.logger.log(`Deleted ${keys.length} keys matching "${pattern}"`);
}
} else {
this.logger.warn('Cache store does not support key scanning; skipping pattern deletion.');
}
} catch (err) {
this.logger.warn(`Cache deletePattern error for "${pattern}": ${err.message}`);
}
}

/**
* Flush the entire cache. Use with care in production.
*/
Expand Down
14 changes: 7 additions & 7 deletions BackEnd/src/modules/health/indicators/database.indicator.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { Injectable } from '@nestjs/common';
import {
HealthIndicatorResult,
HealthIndicatorService,
HealthIndicator,
} from '@nestjs/terminus';
import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';

@Injectable()
export class DatabaseIndicator {
export class DatabaseIndicator extends HealthIndicator {
constructor(
private readonly healthIndicatorService: HealthIndicatorService,
@InjectDataSource() private readonly dataSource: DataSource,
) {}
) {
super();
}

async isHealthy(key: string): Promise<HealthIndicatorResult> {
const indicator = this.healthIndicatorService.check(key);
try {
await this.dataSource.query('SELECT 1');
return indicator.up();
return this.getStatus(key, true);
} catch (error) {
return indicator.down({ message: (error as Error).message });
return this.getStatus(key, false, { message: (error as Error).message });
}
}
}
16 changes: 8 additions & 8 deletions BackEnd/src/modules/health/indicators/redis.indicator.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { Injectable } from '@nestjs/common';
import {
HealthIndicatorResult,
HealthIndicatorService,
HealthIndicator,
} from '@nestjs/terminus';
import { ConfigService } from '@nestjs/config';
import { createClient } from 'redis';

@Injectable()
export class RedisIndicator {
export class RedisIndicator extends HealthIndicator {
constructor(
private readonly healthIndicatorService: HealthIndicatorService,
private readonly configService: ConfigService,
) {}
) {
super();
}

async isHealthy(key: string): Promise<HealthIndicatorResult> {
const indicator = this.healthIndicatorService.check(key);
const cacheType = this.configService.get<string>('CACHE_TYPE', 'memory');

if (cacheType !== 'redis') {
return indicator.up({ note: 'skipped (CACHE_TYPE is not redis)' });
return this.getStatus(key, true, { note: 'skipped (CACHE_TYPE is not redis)' });
}

const client = createClient({
Expand All @@ -34,9 +34,9 @@ export class RedisIndicator {
try {
await client.connect();
await client.ping();
return indicator.up();
return this.getStatus(key, true);
} catch (error) {
return indicator.down({ message: (error as Error).message });
return this.getStatus(key, false, { message: (error as Error).message });
} finally {
await client.disconnect().catch(() => undefined);
}
Expand Down
10 changes: 3 additions & 7 deletions BackEnd/src/modules/users/entities/user.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Quest } from 'src/modules/quests/entities/quest.entity';
import { Submission } from 'src/modules/submissions/entities/submission.entity';
import {
Entity,
PrimaryGeneratedColumn,
Expand Down Expand Up @@ -113,11 +111,9 @@ export class User {
@Column({ type: 'timestamp', nullable: true })
lastSyncedAt: Date;

@OneToMany(() => Submission, (submission) => submission.user)
submissions: Submission[];

@OneToMany(() => Quest, (quest) => quest.creator)
createdQuests: Quest[];
// Relations (using type references to avoid circular imports)
submissions: any[];
createdQuests: any[];

// Helper methods
calculateLevel(): number {
Expand Down
2 changes: 1 addition & 1 deletion BackEnd/test/analytics/analytics.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
SubmissionStatus,
} from '../../src/modules/analytics/entities/submission.entity';
import { Payout } from '../../src/modules/analytics/entities/payout.entity';
import { User } from 'src/modules/users/entities/user.entity';
import { User } from '../../src/modules/users/entities/user.entity';

describe('Analytics (e2e)', () => {
let app: INestApplication;
Expand Down