Skip to content

Commit

Permalink
Merge pull request #101 from Boost-Coder/feature/compare-#100
Browse files Browse the repository at this point in the history
[#100] 사용자끼리 역량을 비교하는 기능 구현
  • Loading branch information
namewhat99 authored Jun 2, 2024
2 parents f3efcde + 15563ec commit bc52907
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 3 deletions.
40 changes: 40 additions & 0 deletions src/stat/dto/compareUsers.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';

export class CompareUsersDto {
@ApiProperty({ required: true })
@IsString()
user1: string;

@ApiProperty({ required: true })
user2: string;
}

export class CompareUsersResponseDto {
@ApiProperty()
algorithmScoreDifference: number;

@ApiProperty()
algorithmRankDifference: number;

@ApiProperty()
githubScoreDifference: number;

@ApiProperty()
githubRankDifference: number;

@ApiProperty()
gradeScoreDifference: number;

@ApiProperty()
gradeRankDifference: number;

@ApiProperty()
totalScoreDifference: number;

@ApiProperty()
totalRankDifference: number;

@ApiProperty()
mostSignificantScoreDifferenceStat: string;
}
173 changes: 173 additions & 0 deletions src/stat/service/total.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Algorithm } from '../../Entity/algorithm';
import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto';
import { PointFindDto } from '../dto/rank-find.dto';
import { StatFindDto } from '../dto/stat-find.dto';
import { CompareUsersResponseDto } from '../dto/compareUsers.dto';

@Injectable()
export class TotalService {
Expand Down Expand Up @@ -83,4 +84,176 @@ export class TotalService {
public async getIndividualTotalRank(userId: string, options: PointFindDto) {
return await this.totalRepository.findIndividualRank(userId, options);
}

public async compareUsers(user1: string, user2: string) {
const comparison = new CompareUsersResponseDto();
[
comparison.algorithmScoreDifference,
comparison.algorithmRankDifference,
] = await this.compareAlgorithm(user1, user2);

[comparison.githubScoreDifference, comparison.githubRankDifference] =
await this.compareGithub(user1, user2);

[comparison.gradeScoreDifference, comparison.gradeRankDifference] =
await this.compareGrade(user1, user2);

[comparison.totalScoreDifference, comparison.totalRankDifference] =
await this.compareTotal(user1, user2);

comparison.mostSignificantScoreDifferenceStat =
this.findMaxScoreDifference(comparison);
return comparison;
}

findMaxScoreDifference(response: CompareUsersResponseDto): string | null {
const scoreDifferences = {
algorithm: response.algorithmScoreDifference,
github: response.githubScoreDifference,
grade: response.gradeScoreDifference,
};

let maxDifference = 0;
let maxDifferenceKey: string | null = null;

for (const [key, value] of Object.entries(scoreDifferences)) {
if (value !== null && value < 0 && value < maxDifference) {
maxDifference = value;
maxDifferenceKey = key;
}
}

return maxDifferenceKey;
}

private async compareGithub(user1: string, user2: string) {
const githubScoreDifference = await this.compareGithubScore(
user1,
user2,
);
if (githubScoreDifference === null) {
return [null, null];
}
const githubRankDifference = await this.compareGithubRank(user1, user2);
return [githubScoreDifference, githubRankDifference];
}

private async compareGithubScore(user1: string, user2: string) {
const user1Github = await this.githubService.findGithub(user1);
const user2Github = await this.githubService.findGithub(user2);
if (user1Github == null || user2Github == null) {
return null;
}
return user1Github.score - user2Github.score;
}

private async compareGithubRank(user1: string, user2: string) {
const user1Rank = await this.githubService.getIndividualGithubRank(
user1,
new PointFindDto(),
);
const user2Rank = await this.githubService.getIndividualGithubRank(
user2,
new PointFindDto(),
);
return user1Rank.rank - user2Rank.rank;
}

private async compareAlgorithm(user1: string, user2: string) {
const algorithmScoreDifference = await this.compareAlgorithmScore(
user1,
user2,
);
if (algorithmScoreDifference === null) {
return [null, null];
}
const algorithmRankDifference = await this.compareAlgorithmRank(
user1,
user2,
);
return [algorithmScoreDifference, algorithmRankDifference];
}

private async compareAlgorithmScore(user1: string, user2: string) {
const user1Algorithm = await this.algorithmService.findAlgorithm(user1);
const user2Algorithm = await this.algorithmService.findAlgorithm(user2);
if (user1Algorithm == null || user2Algorithm == null) {
return null;
}
return user1Algorithm.score - user2Algorithm.score;
}

private async compareAlgorithmRank(user1: string, user2: string) {
const user1Rank =
await this.algorithmService.getIndividualAlgorithmRank(
user1,
new PointFindDto(),
);
const user2Rank =
await this.algorithmService.getIndividualAlgorithmRank(
user2,
new PointFindDto(),
);
return user1Rank.rank - user2Rank.rank;
}

private async compareGrade(user1: string, user2: string) {
const gradeScoreDifference = await this.compareGradeScore(user1, user2);
if (gradeScoreDifference === null) {
return [null, null];
}
const gradeRankDifference = await this.compareGradeRank(user1, user2);
return [gradeScoreDifference, gradeRankDifference];
}

private async compareGradeScore(user1: string, user2: string) {
const user1Grade = await this.gradeService.findGrade(user1);
const user2Grade = await this.gradeService.findGrade(user2);
if (user1Grade == null || user2Grade == null) {
return null;
}
return user1Grade.score - user2Grade.score;
}

private async compareGradeRank(user1: string, user2: string) {
const user1Rank = await this.gradeService.getIndividualGradeRank(
user1,
new PointFindDto(),
);
const user2Rank = await this.gradeService.getIndividualGradeRank(
user2,
new PointFindDto(),
);
return user1Rank.rank - user2Rank.rank;
}

private async compareTotal(user1: string, user2: string) {
const totalScoreDifference = await this.compareTotalScore(user1, user2);
if (totalScoreDifference === null) {
return [null, null];
}
const totalRankDifference = await this.compareTotalRank(user1, user2);
return [totalScoreDifference, totalRankDifference];
}

private async compareTotalScore(user1: string, user2: string) {
const user1Total = await this.totalRepository.findOneById(user1);
const user2Total = await this.totalRepository.findOneById(user2);
if (user1Total == null || user2Total == null) {
return null;
}
return user1Total.score - user2Total.score;
}

private async compareTotalRank(user1: string, user2: string) {
const user1Rank = await this.getIndividualTotalRank(
user1,
new PointFindDto(),
);
const user2Rank = await this.getIndividualTotalRank(
user2,
new PointFindDto(),
);
return user1Rank.rank - user2Rank.rank;
}
}
21 changes: 21 additions & 0 deletions src/stat/stat.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
Param,
Patch,
Post,
Query,
UseGuards,
} from '@nestjs/common';
import { AlgorithmService } from './service/algorithm.service';
Expand All @@ -32,6 +33,10 @@ import {
ApiUnauthorizedResponse,
} from '@nestjs/swagger';
import { Transactional } from 'typeorm-transactional';
import {
CompareUsersDto,
CompareUsersResponseDto,
} from './dto/compareUsers.dto';

@UseGuards(JwtAuthGuard)
@Controller('api/stat')
Expand All @@ -43,6 +48,22 @@ export class StatController {
private readonly totalService: TotalService,
) {}

@ApiTags('stat')
@ApiOperation({
summary: '개발 역량 비교 API',
description:
'두 사용자의 역량을 비교한다. user1 - user2 한 결과를 반환한다. 둘중 하나라도 역량이 등록되지 않은 경우 null 반환. 가장차이나는 역량은 user1이 user2 보다 작은 역량중에서 찾아 반환한다. user1이 user2 보다 모든 역량이 크거나 같다면 null 반환',
})
@ApiBearerAuth('accessToken')
@ApiOkResponse({
description: '유저 정보 비교 성공',
type: CompareUsersResponseDto,
})
@Get('compare')
public async compareUsers(@Query() users: CompareUsersDto) {
return await this.totalService.compareUsers(users.user1, users.user2);
}

@ApiTags('stat')
@ApiOperation({
summary: '유저의 개발 역량 반환 API',
Expand Down
10 changes: 7 additions & 3 deletions src/utils/stat.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,19 @@ export class StatRepository extends Repository<any> {
.distinct(true)
.from((sub) => {
return sub
.select('RANK() OVER (ORDER BY a.score DESC)', 'rank')
.select(
'RANK() OVER (ORDER BY a.score DESC, user_id ASC)',
'rank',
)
.addSelect('a.user_id', 'user_id')
.from(this.entity, 'a')
.innerJoin(User, 'u', 'a.user_id = u.user_id')
.addSelect('u.major', 'major')
.where(this.createClassificationOption(options));
.where(this.createClassificationOption(options))
.orderBy('score', 'DESC')
.addOrderBy('user_id');
}, 'b')
.where(`b.user_id = '${userId}'`);

return await queryBuilder.getRawOne();
}
createCursorOption(options: RankListOptionDto) {
Expand Down

0 comments on commit bc52907

Please sign in to comment.