module cleanup
This commit is contained in:
163
apps/api/src/domain/driver/DriverController.test.ts
Normal file
163
apps/api/src/domain/driver/DriverController.test.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { vi } from 'vitest';
|
||||
import { DriverController } from './DriverController';
|
||||
import { DriverService } from './DriverService';
|
||||
import type { Request } from 'express';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: { userId: string };
|
||||
}
|
||||
import { CompleteOnboardingInputDTO } from './dtos/CompleteOnboardingInputDTO';
|
||||
import { CompleteOnboardingOutputDTO } from './dtos/CompleteOnboardingOutputDTO';
|
||||
import { DriversLeaderboardDTO } from './dtos/DriversLeaderboardDTO';
|
||||
import { DriverStatsDTO } from './dtos/DriverStatsDTO';
|
||||
import { GetDriverOutputDTO } from './dtos/GetDriverOutputDTO';
|
||||
import { GetDriverProfileOutputDTO } from './dtos/GetDriverProfileOutputDTO';
|
||||
import { DriverRegistrationStatusDTO } from './dtos/DriverRegistrationStatusDTO';
|
||||
|
||||
describe('DriverController', () => {
|
||||
let controller: DriverController;
|
||||
let service: ReturnType<typeof vi.mocked<DriverService>>;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [DriverController],
|
||||
providers: [
|
||||
{
|
||||
provide: DriverService,
|
||||
useValue: {
|
||||
getDriversLeaderboard: vi.fn(),
|
||||
getTotalDrivers: vi.fn(),
|
||||
getCurrentDriver: vi.fn(),
|
||||
completeOnboarding: vi.fn(),
|
||||
getDriverRegistrationStatus: vi.fn(),
|
||||
getDriver: vi.fn(),
|
||||
getDriverProfile: vi.fn(),
|
||||
updateDriverProfile: vi.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<DriverController>(DriverController);
|
||||
service = vi.mocked(module.get(DriverService));
|
||||
});
|
||||
|
||||
describe('getDriversLeaderboard', () => {
|
||||
it('should return drivers leaderboard', async () => {
|
||||
const leaderboard: DriversLeaderboardDTO = { items: [] };
|
||||
service.getDriversLeaderboard.mockResolvedValue(leaderboard);
|
||||
|
||||
const result = await controller.getDriversLeaderboard();
|
||||
|
||||
expect(service.getDriversLeaderboard).toHaveBeenCalled();
|
||||
expect(result).toEqual(leaderboard);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTotalDrivers', () => {
|
||||
it('should return total drivers stats', async () => {
|
||||
const stats: DriverStatsDTO = { totalDrivers: 100 };
|
||||
service.getTotalDrivers.mockResolvedValue(stats);
|
||||
|
||||
const result = await controller.getTotalDrivers();
|
||||
|
||||
expect(service.getTotalDrivers).toHaveBeenCalled();
|
||||
expect(result).toEqual(stats);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCurrentDriver', () => {
|
||||
it('should return current driver if userId exists', async () => {
|
||||
const userId = 'user-123';
|
||||
const driver: GetDriverOutputDTO = { id: 'driver-123', name: 'Driver' };
|
||||
service.getCurrentDriver.mockResolvedValue(driver);
|
||||
|
||||
const mockReq: Partial<AuthenticatedRequest> = { user: { userId } };
|
||||
|
||||
const result = await controller.getCurrentDriver(mockReq as AuthenticatedRequest);
|
||||
|
||||
expect(service.getCurrentDriver).toHaveBeenCalledWith(userId);
|
||||
expect(result).toEqual(driver);
|
||||
});
|
||||
|
||||
it('should return null if no userId', async () => {
|
||||
const mockReq: Partial<AuthenticatedRequest> = {};
|
||||
|
||||
const result = await controller.getCurrentDriver(mockReq as AuthenticatedRequest);
|
||||
|
||||
expect(service.getCurrentDriver).not.toHaveBeenCalled();
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('completeOnboarding', () => {
|
||||
it('should complete onboarding', async () => {
|
||||
const userId = 'user-123';
|
||||
const input: CompleteOnboardingInputDTO = { someField: 'value' };
|
||||
const output: CompleteOnboardingOutputDTO = { success: true };
|
||||
service.completeOnboarding.mockResolvedValue(output);
|
||||
|
||||
const mockReq: Partial<AuthenticatedRequest> = { user: { userId } };
|
||||
|
||||
const result = await controller.completeOnboarding(input, mockReq as AuthenticatedRequest);
|
||||
|
||||
expect(service.completeOnboarding).toHaveBeenCalledWith(userId, input);
|
||||
expect(result).toEqual(output);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDriverRegistrationStatus', () => {
|
||||
it('should return registration status', async () => {
|
||||
const driverId = 'driver-123';
|
||||
const raceId = 'race-456';
|
||||
const status: DriverRegistrationStatusDTO = { registered: true };
|
||||
service.getDriverRegistrationStatus.mockResolvedValue(status);
|
||||
|
||||
const result = await controller.getDriverRegistrationStatus(driverId, raceId);
|
||||
|
||||
expect(service.getDriverRegistrationStatus).toHaveBeenCalledWith({ driverId, raceId });
|
||||
expect(result).toEqual(status);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDriver', () => {
|
||||
it('should return driver by id', async () => {
|
||||
const driverId = 'driver-123';
|
||||
const driver: GetDriverOutputDTO = { id: driverId, name: 'Driver' };
|
||||
service.getDriver.mockResolvedValue(driver);
|
||||
|
||||
const result = await controller.getDriver(driverId);
|
||||
|
||||
expect(service.getDriver).toHaveBeenCalledWith(driverId);
|
||||
expect(result).toEqual(driver);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDriverProfile', () => {
|
||||
it('should return driver profile', async () => {
|
||||
const driverId = 'driver-123';
|
||||
const profile: GetDriverProfileOutputDTO = { id: driverId, bio: 'Bio' };
|
||||
service.getDriverProfile.mockResolvedValue(profile);
|
||||
|
||||
const result = await controller.getDriverProfile(driverId);
|
||||
|
||||
expect(service.getDriverProfile).toHaveBeenCalledWith(driverId);
|
||||
expect(result).toEqual(profile);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateDriverProfile', () => {
|
||||
it('should update driver profile', async () => {
|
||||
const driverId = 'driver-123';
|
||||
const body = { bio: 'New bio', country: 'US' };
|
||||
const updated: GetDriverOutputDTO = { id: driverId, name: 'Driver' };
|
||||
service.updateDriverProfile.mockResolvedValue(updated);
|
||||
|
||||
const result = await controller.updateDriverProfile(driverId, body);
|
||||
|
||||
expect(service.updateDriverProfile).toHaveBeenCalledWith(driverId, body.bio, body.country);
|
||||
expect(result).toEqual(updated);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,10 @@
|
||||
import { Controller, Get, Post, Body, Req, Param } from '@nestjs/common';
|
||||
import { Request } from 'express';
|
||||
import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: { userId: string };
|
||||
}
|
||||
import { DriverService } from './DriverService';
|
||||
import { DriversLeaderboardDTO } from './dtos/DriversLeaderboardDTO';
|
||||
import { DriverStatsDTO } from './dtos/DriverStatsDTO';
|
||||
@@ -35,9 +39,9 @@ export class DriverController {
|
||||
@ApiOperation({ summary: 'Get current authenticated driver' })
|
||||
@ApiResponse({ status: 200, description: 'Current driver data', type: GetDriverOutputDTO })
|
||||
@ApiResponse({ status: 404, description: 'Driver not found' })
|
||||
async getCurrentDriver(@Req() req: Request): Promise<GetDriverOutputDTO | null> {
|
||||
async getCurrentDriver(@Req() req: AuthenticatedRequest): Promise<GetDriverOutputDTO | null> {
|
||||
// Assuming userId is available from the request (e.g., via auth middleware)
|
||||
const userId = req['user']?.userId;
|
||||
const userId = req.user?.userId;
|
||||
if (!userId) {
|
||||
return null;
|
||||
}
|
||||
@@ -49,10 +53,10 @@ export class DriverController {
|
||||
@ApiResponse({ status: 200, description: 'Onboarding complete', type: CompleteOnboardingOutputDTO })
|
||||
async completeOnboarding(
|
||||
@Body() input: CompleteOnboardingInputDTO,
|
||||
@Req() req: Request,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
): Promise<CompleteOnboardingOutputDTO> {
|
||||
// Assuming userId is available from the request (e.g., via auth middleware)
|
||||
const userId = req['user'].userId; // Placeholder for actual user extraction
|
||||
const userId = req.user!.userId; // Placeholder for actual user extraction
|
||||
return this.driverService.completeOnboarding(userId, input);
|
||||
}
|
||||
|
||||
|
||||
30
apps/api/src/domain/driver/DriverModule.test.ts
Normal file
30
apps/api/src/domain/driver/DriverModule.test.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { DriverModule } from './DriverModule';
|
||||
import { DriverController } from './DriverController';
|
||||
import { DriverService } from './DriverService';
|
||||
|
||||
describe('DriverModule', () => {
|
||||
let module: TestingModule;
|
||||
|
||||
beforeEach(async () => {
|
||||
module = await Test.createTestingModule({
|
||||
imports: [DriverModule],
|
||||
}).compile();
|
||||
});
|
||||
|
||||
it('should compile the module', () => {
|
||||
expect(module).toBeDefined();
|
||||
});
|
||||
|
||||
it('should provide DriverController', () => {
|
||||
const controller = module.get<DriverController>(DriverController);
|
||||
expect(controller).toBeDefined();
|
||||
expect(controller).toBeInstanceOf(DriverController);
|
||||
});
|
||||
|
||||
it('should provide DriverService', () => {
|
||||
const service = module.get<DriverService>(DriverService);
|
||||
expect(service).toBeDefined();
|
||||
expect(service).toBeInstanceOf(DriverService);
|
||||
});
|
||||
});
|
||||
@@ -9,25 +9,24 @@ import { DriverRatingProvider } from '@core/racing/application/ports/DriverRatin
|
||||
import { IImageServicePort } from '@core/racing/application/ports/IImageServicePort';
|
||||
import { IRaceRegistrationRepository } from '@core/racing/domain/repositories/IRaceRegistrationRepository';
|
||||
import { INotificationPreferenceRepository } from '@core/notifications/domain/repositories/INotificationPreferenceRepository';
|
||||
import type { Logger } from "@gridpilot/core/shared/application";
|
||||
import type { Logger } from "@core/shared/application";
|
||||
|
||||
// Import use cases
|
||||
import { GetDriversLeaderboardUseCase } from '@core/racing/application/use-cases/GetDriversLeaderboardUseCase';
|
||||
import { GetTotalDriversUseCase } from '@core/racing/application/use-cases/GetTotalDriversUseCase';
|
||||
import { CompleteDriverOnboardingUseCase } from '@core/racing/application/use-cases/CompleteDriverOnboardingUseCase';
|
||||
import { GetProfileOverviewUseCase } from '@core/racing/application/use-cases/GetProfileOverviewUseCase';
|
||||
import { GetDriverTeamUseCase } from '@core/racing/application/use-cases/GetDriverTeamUseCase';
|
||||
import { UpdateDriverProfileUseCase } from '@core/racing/application/use-cases/UpdateDriverProfileUseCase';
|
||||
import { IsDriverRegisteredForRaceUseCase } from '@core/racing/application/use-cases/IsDriverRegisteredForRaceUseCase';
|
||||
|
||||
// Import concrete in-memory implementations
|
||||
import { InMemoryDriverRepository } from '../../..//racing/persistence/inmemory/InMemoryDriverRepository';
|
||||
import { InMemoryRankingService } from '../../..//racing/services/InMemoryRankingService';
|
||||
import { InMemoryDriverStatsService } from '../../..//racing/services/InMemoryDriverStatsService';
|
||||
import { InMemoryDriverRatingProvider } from '../../..//racing/ports/InMemoryDriverRatingProvider';
|
||||
import { InMemoryImageServiceAdapter } from '../../..//media/ports/InMemoryImageServiceAdapter';
|
||||
import { InMemoryRaceRegistrationRepository } from '../../..//racing/persistence/inmemory/InMemoryRaceRegistrationRepository';
|
||||
import { InMemoryNotificationPreferenceRepository } from '../../..//notifications/persistence/inmemory/InMemoryNotificationPreferenceRepository';
|
||||
import { ConsoleLogger } from '../../..//logging/ConsoleLogger';
|
||||
import { InMemoryDriverRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverRepository';
|
||||
import { InMemoryRankingService } from '@adapters/racing/services/InMemoryRankingService';
|
||||
import { InMemoryDriverStatsService } from '@adapters/racing/services/InMemoryDriverStatsService';
|
||||
import { InMemoryDriverRatingProvider } from '@adapters/racing/ports/InMemoryDriverRatingProvider';
|
||||
import { InMemoryImageServiceAdapter } from '@adapters/media/ports/InMemoryImageServiceAdapter';
|
||||
import { InMemoryRaceRegistrationRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRegistrationRepository';
|
||||
import { InMemoryNotificationPreferenceRepository } from '@adapters/notifications/persistence/inmemory/InMemoryNotificationPreferenceRepository';
|
||||
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
|
||||
|
||||
// Define injection tokens
|
||||
export const DRIVER_REPOSITORY_TOKEN = 'IDriverRepository';
|
||||
@@ -44,8 +43,6 @@ export const GET_DRIVERS_LEADERBOARD_USE_CASE_TOKEN = 'GetDriversLeaderboardUseC
|
||||
export const GET_TOTAL_DRIVERS_USE_CASE_TOKEN = 'GetTotalDriversUseCase';
|
||||
export const COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN = 'CompleteDriverOnboardingUseCase';
|
||||
export const IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN = 'IsDriverRegisteredForRaceUseCase';
|
||||
export const GET_PROFILE_OVERVIEW_USE_CASE_TOKEN = 'GetProfileOverviewUseCase';
|
||||
export const GET_DRIVER_TEAM_USE_CASE_TOKEN = 'GetDriverTeamUseCase';
|
||||
export const UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN = 'UpdateDriverProfileUseCase';
|
||||
|
||||
export const DriverProviders: Provider[] = [
|
||||
@@ -92,14 +89,14 @@ export const DriverProviders: Provider[] = [
|
||||
// Use cases
|
||||
{
|
||||
provide: GET_DRIVERS_LEADERBOARD_USE_CASE_TOKEN,
|
||||
useFactory: (driverRepo: IDriverRepository, rankingService: IRankingService, driverStatsService: IDriverStatsService, imageService: IImageServicePort) =>
|
||||
new GetDriversLeaderboardUseCase(driverRepo, rankingService, driverStatsService, imageService),
|
||||
inject: [DRIVER_REPOSITORY_TOKEN, RANKING_SERVICE_TOKEN, DRIVER_STATS_SERVICE_TOKEN, IMAGE_SERVICE_PORT_TOKEN],
|
||||
useFactory: (driverRepo: IDriverRepository, rankingService: IRankingService, driverStatsService: IDriverStatsService, imageService: IImageServicePort, logger: Logger) =>
|
||||
new GetDriversLeaderboardUseCase(driverRepo, rankingService, driverStatsService, imageService, logger),
|
||||
inject: [DRIVER_REPOSITORY_TOKEN, RANKING_SERVICE_TOKEN, DRIVER_STATS_SERVICE_TOKEN, IMAGE_SERVICE_PORT_TOKEN, LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: GET_TOTAL_DRIVERS_USE_CASE_TOKEN,
|
||||
useFactory: (driverRepo: IDriverRepository) => new GetTotalDriversUseCase(driverRepo),
|
||||
inject: [DRIVER_REPOSITORY_TOKEN],
|
||||
useFactory: (driverRepo: IDriverRepository, logger: Logger) => new GetTotalDriversUseCase(driverRepo, logger),
|
||||
inject: [DRIVER_REPOSITORY_TOKEN, LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN,
|
||||
@@ -108,8 +105,8 @@ export const DriverProviders: Provider[] = [
|
||||
},
|
||||
{
|
||||
provide: IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN,
|
||||
useFactory: (registrationRepo: IRaceRegistrationRepository) => new IsDriverRegisteredForRaceUseCase(registrationRepo),
|
||||
inject: [RACE_REGISTRATION_REPOSITORY_TOKEN],
|
||||
useFactory: (registrationRepo: IRaceRegistrationRepository, logger: Logger) => new IsDriverRegisteredForRaceUseCase(registrationRepo, logger),
|
||||
inject: [RACE_REGISTRATION_REPOSITORY_TOKEN, LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN,
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { vi } from 'vitest';
|
||||
import { DriverService } from './DriverService';
|
||||
import { GetDriversLeaderboardUseCase } from '@core/racing/application/use-cases/GetDriversLeaderboardUseCase';
|
||||
import { GetTotalDriversUseCase } from '@core/racing/application/use-cases/GetTotalDriversUseCase';
|
||||
import { CompleteDriverOnboardingUseCase } from '@core/racing/application/use-cases/CompleteDriverOnboardingUseCase';
|
||||
import { IsDriverRegisteredForRaceUseCase } from '@core/racing/application/use-cases/IsDriverRegisteredForRaceUseCase';
|
||||
import { UpdateDriverProfileUseCase } from '@core/racing/application/use-cases/UpdateDriverProfileUseCase';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
import type { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';
|
||||
|
||||
describe('DriverService', () => {
|
||||
let service: DriverService;
|
||||
let getDriversLeaderboardUseCase: jest.Mocked<GetDriversLeaderboardUseCase>;
|
||||
let getTotalDriversUseCase: jest.Mocked<GetTotalDriversUseCase>;
|
||||
let completeDriverOnboardingUseCase: jest.Mocked<CompleteDriverOnboardingUseCase>;
|
||||
let isDriverRegisteredForRaceUseCase: jest.Mocked<IsDriverRegisteredForRaceUseCase>;
|
||||
let logger: jest.Mocked<Logger>;
|
||||
let getDriversLeaderboardUseCase: ReturnType<typeof vi.mocked<GetDriversLeaderboardUseCase>>;
|
||||
let getTotalDriversUseCase: ReturnType<typeof vi.mocked<GetTotalDriversUseCase>>;
|
||||
let completeDriverOnboardingUseCase: ReturnType<typeof vi.mocked<CompleteDriverOnboardingUseCase>>;
|
||||
let isDriverRegisteredForRaceUseCase: ReturnType<typeof vi.mocked<IsDriverRegisteredForRaceUseCase>>;
|
||||
let updateDriverProfileUseCase: ReturnType<typeof vi.mocked<UpdateDriverProfileUseCase>>;
|
||||
let driverRepository: ReturnType<typeof vi.mocked<IDriverRepository>>;
|
||||
let logger: ReturnType<typeof vi.mocked<Logger>>;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
@@ -21,42 +26,57 @@ describe('DriverService', () => {
|
||||
{
|
||||
provide: 'GetDriversLeaderboardUseCase',
|
||||
useValue: {
|
||||
execute: jest.fn(),
|
||||
execute: vi.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: 'GetTotalDriversUseCase',
|
||||
useValue: {
|
||||
execute: jest.fn(),
|
||||
execute: vi.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: 'CompleteDriverOnboardingUseCase',
|
||||
useValue: {
|
||||
execute: jest.fn(),
|
||||
execute: vi.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: 'IsDriverRegisteredForRaceUseCase',
|
||||
useValue: {
|
||||
execute: jest.fn(),
|
||||
execute: vi.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: 'UpdateDriverProfileUseCase',
|
||||
useValue: {
|
||||
execute: vi.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: 'IDriverRepository',
|
||||
useValue: {
|
||||
findById: vi.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: 'Logger',
|
||||
useValue: {
|
||||
debug: jest.fn(),
|
||||
debug: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<DriverService>(DriverService);
|
||||
getDriversLeaderboardUseCase = module.get('GetDriversLeaderboardUseCase');
|
||||
getTotalDriversUseCase = module.get('GetTotalDriversUseCase');
|
||||
completeDriverOnboardingUseCase = module.get('CompleteDriverOnboardingUseCase');
|
||||
isDriverRegisteredForRaceUseCase = module.get('IsDriverRegisteredForRaceUseCase');
|
||||
logger = module.get('Logger');
|
||||
getDriversLeaderboardUseCase = vi.mocked(module.get('GetDriversLeaderboardUseCase'));
|
||||
getTotalDriversUseCase = vi.mocked(module.get('GetTotalDriversUseCase'));
|
||||
completeDriverOnboardingUseCase = vi.mocked(module.get('CompleteDriverOnboardingUseCase'));
|
||||
isDriverRegisteredForRaceUseCase = vi.mocked(module.get('IsDriverRegisteredForRaceUseCase'));
|
||||
updateDriverProfileUseCase = vi.mocked(module.get('UpdateDriverProfileUseCase'));
|
||||
driverRepository = vi.mocked(module.get('IDriverRepository'));
|
||||
logger = vi.mocked(module.get('Logger'));
|
||||
});
|
||||
|
||||
describe('getDriversLeaderboard', () => {
|
||||
|
||||
@@ -143,7 +143,12 @@ export class DriverProfileSocialSummaryDTO {
|
||||
|
||||
export type DriverProfileSocialPlatform = 'twitter' | 'youtube' | 'twitch' | 'discord';
|
||||
|
||||
export type DriverProfileAchievementRarity = 'common' | 'rare' | 'epic' | 'legendary';
|
||||
export enum DriverProfileAchievementRarity {
|
||||
COMMON = 'common',
|
||||
RARE = 'rare',
|
||||
EPIC = 'epic',
|
||||
LEGENDARY = 'legendary',
|
||||
}
|
||||
|
||||
export class DriverProfileAchievementDTO {
|
||||
@ApiProperty()
|
||||
|
||||
Reference in New Issue
Block a user