Skip to content

Commit

Permalink
- follower system
Browse files Browse the repository at this point in the history
  • Loading branch information
Lamarcke committed Mar 1, 2024
1 parent 733089d commit 0a9dea4
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 7 deletions.
2 changes: 1 addition & 1 deletion server_swagger.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/follow/entity/user-follow.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
JoinTable,
ManyToMany,
PrimaryGeneratedColumn,
Unique,
UpdateDateColumn,
} from "typeorm";
import { Profile } from "../../profile/entities/profile.entity";
Expand Down
15 changes: 9 additions & 6 deletions src/follow/follow.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { FollowService } from "./follow.service";
import { FollowRegisterDto } from "./dto/follow-register.dto";
import { SessionContainer } from "supertokens-node/recipe/session";
import { Session } from "../auth/session.decorator";
import { ApiOkResponse } from "@nestjs/swagger";
import { ApiOkResponse, ApiTags } from "@nestjs/swagger";
import { FollowStatusDto } from "./dto/follow-status.dto";

@Controller("follow")
@ApiTags("follow")
@UseGuards(AuthGuard)
export class FollowController {
constructor(private followService: FollowService) {}
Expand All @@ -29,12 +30,14 @@ export class FollowController {
type: FollowStatusDto,
})
async getFollowerStatus(
@Session() session: SessionContainer,
@Query("followerUserId") followerUserId: string,
@Query("followedUserId") followedUserId: string,
) {
return this.followService.getStatus(
session.getUserId(),
followedUserId,
);
return this.followService.getStatus(followerUserId, followedUserId);
}

@Get("count")
async getFollowersCount(@Query("targetUserId") targetUserId: string) {
return await this.followService.getFollowersCount(targetUserId);
}
}
21 changes: 21 additions & 0 deletions src/follow/follow.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ export class FollowService {
followerUserId: string,
followedUserId: string,
) {
if (followerUserId === followedUserId) {
throw new HttpException(
"User can't follow itself.",
HttpStatus.I_AM_A_TEAPOT,
);
}
try {
await this.userFollowRepository.save({
follower: {
Expand Down Expand Up @@ -49,6 +55,13 @@ export class FollowService {
);
}
}

if (followerUserId === followedUserId) {
return {
isFollowing: false,
};
}

const exist = await this.userFollowRepository.exist({
where: {
follower: {
Expand All @@ -64,4 +77,12 @@ export class FollowService {
isFollowing: exist,
};
}

public async getFollowersCount(userId: string) {
return await this.userFollowRepository.countBy({
followed: {
userId,
},
});
}
}
7 changes: 7 additions & 0 deletions src/reviews/dto/review-score-request.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { IsNotEmpty, IsNumber } from "class-validator";

export class ReviewScoreRequestDto {
@IsNotEmpty()
@IsNumber()
gameId: number;
}
19 changes: 19 additions & 0 deletions src/reviews/dto/review-score-response.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Number of times a given review rating appears for a specific game
*/
export class ReviewScoreDistribution {
1: number;
2: number;
3: number;
4: number;
5: number;
/**
* Total number of reviews
*/
total: number;
}

export class ReviewScoreResponseDto {
median: number;
distribution: ReviewScoreDistribution;
}
8 changes: 8 additions & 0 deletions src/reviews/reviews.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { FindReviewPaginatedDto } from "./dto/find-review-paginated.dto";
import { Review } from "./entities/review.entity";
import { FindReviewDto } from "./dto/find-review.dto";
import { Public } from "../auth/public.decorator";
import { ReviewScoreRequestDto } from "./dto/review-score-request.dto";

@Controller("reviews")
@ApiTags("reviews")
Expand All @@ -38,6 +39,11 @@ export class ReviewsController {
);
}

@Get("/score")
async getScoreForGameId(@Query() dto: ReviewScoreRequestDto) {
return this.reviewsService.getScore(dto.gameId);
}

@Get("profile/:userId")
@UseInterceptors(PaginationInterceptor)
@ApiOkResponse({
Expand Down Expand Up @@ -67,6 +73,7 @@ export class ReviewsController {
}

@Get()
@Public()
@ApiOkResponse({
type: Review,
status: 200,
Expand All @@ -82,6 +89,7 @@ export class ReviewsController {
}

@Get(":id")
@Public()
async findOneById(@Param("id") id: string) {
return this.reviewsService.findOneByIdOrFail(id);
}
Expand Down
60 changes: 60 additions & 0 deletions src/reviews/reviews.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import { AchievementsQueueService } from "../achievements/achievements-queue/ach
import { AchievementCategory } from "../achievements/achievements.constants";
import { StatisticsService } from "../statistics/statistics.service";
import { StatisticsSourceType } from "../statistics/statistics.constants";
import {
ReviewScoreDistribution,
ReviewScoreResponseDto,
} from "./dto/review-score-response.dto";

export class ReviewsService {
private readonly logger = new Logger(ReviewsService.name);
Expand Down Expand Up @@ -100,6 +104,62 @@ export class ReviewsService {
});
}

private getReviewsScoreDistribution(
reviews: Review[],
): ReviewScoreDistribution {
const distribution: ReviewScoreDistribution = {
"1": 0,
"2": 0,
"3": 0,
"4": 0,
"5": 0,
total: reviews.length,
};
for (const num of [1, 2, 3, 4, 5] as const) {
const items = reviews
.filter(
(review) => review != undefined && review.rating === num,
)
.map((review) => review.rating);
distribution[num] = items.length;
}

return distribution;
}

private getScoresMedian(scores: number[]) {
if (scores.length === 0) {
return 0;
} else if (scores.length === 1) {
return scores[0];
}
const sortedScores = scores.toSorted((a, b) => a - b);
const middleIndex = Math.ceil(sortedScores.length / 2);
if (sortedScores.length % 2) {
return (
(sortedScores[middleIndex - 1] + sortedScores[middleIndex]) / 2
);
}

return sortedScores[middleIndex];
}

async getScore(gameId: number): Promise<ReviewScoreResponseDto> {
const reviews = await this.reviewsRepository.findBy({
gameId: gameId,
});
const scores = reviews.map((review) => {
return review.rating;
});
const median = this.getScoresMedian(scores);
const distribution = this.getReviewsScoreDistribution(reviews);
console.log(scores, median, distribution);
return {
median,
distribution,
};
}

async createOrUpdate(userId: string, createReviewDto: CreateReviewDto) {
const collectionEntry =
await this.collectionsEntriesService.findOneByUserIdAndGameIdOrFail(
Expand Down
1 change: 1 addition & 0 deletions src/statistics/statistics.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ export class StatisticsService {
likesCount: "DESC",
viewsCount: "DESC",
},
relationLoadStrategy: "query",
});
}

Expand Down

0 comments on commit 0a9dea4

Please sign in to comment.