Skip to content

Commit

Permalink
Merge pull request #128 from game-node-app/dev
Browse files Browse the repository at this point in the history
Changes to the IGDB sync system and notifications system
  • Loading branch information
Lamarcke authored Dec 6, 2024
2 parents 6a1aa6d + 413a21c commit 1f26621
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 28 deletions.
2 changes: 1 addition & 1 deletion server_swagger.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
Controller,
Get,
Param,
Query,
UseGuards,
UseInterceptors,
Expand All @@ -12,6 +13,7 @@ import { ActivitiesPaginatedResponseDto } from "./dto/activities-paginated-respo
import { PaginationInterceptor } from "../../interceptor/pagination.interceptor";
import { AuthGuard } from "../../auth/auth.guard";
import { Public } from "../../auth/public.decorator";
import { Activity } from "./entities/activity.entity";

@Controller("activities")
@ApiTags("activities")
Expand All @@ -30,4 +32,17 @@ export class ActivitiesRepositoryController {
async findLatest(@Query() dto: FindLatestActivitiesDto) {
return this.activitiesRepositoryService.findLatest(dto);
}

@Get("detail/:id")
@ApiOkResponse({
type: Activity,
})
@Public()
async findOneById(@Param("id") activityId: string) {
return this.activitiesRepositoryService.findOneByOrFail({
where: {
id: activityId,
},
});
}
}
12 changes: 11 additions & 1 deletion src/comment/comment.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
UseGuards,
UseInterceptors,
} from "@nestjs/common";
import { ApiOkResponse, ApiTags } from "@nestjs/swagger";
import { ApiOkResponse, ApiTags, getSchemaPath } from "@nestjs/swagger";
import { CommentService } from "./comment.service";
import { CreateCommentDto } from "./dto/create-comment.dto";
import { Session } from "../auth/session.decorator";
Expand All @@ -28,6 +28,8 @@ import { DeleteCommentDto } from "./dto/delete-comment.dto";
import { SuspensionGuard } from "../suspension/suspension.guard";
import { BaseFindDto } from "../utils/base-find.dto";
import { UserComment } from "./entity/user-comment.entity";
import { ReviewComment } from "./entity/review-comment.entity";
import { ActivityComment } from "./entity/activity-comment.entity";

@Controller("comment")
@ApiTags("comment")
Expand All @@ -48,6 +50,14 @@ export class CommentController {
}

@Get(":sourceType/:id")
@ApiOkResponse({
schema: {
oneOf: [
{ type: getSchemaPath(ReviewComment) },
{ type: getSchemaPath(ActivityComment) },
],
},
})
@Public()
async findOneById(
@Param("sourceType") sourceType: CommentSourceType,
Expand Down
55 changes: 42 additions & 13 deletions src/game/game-repository/game-repository-create.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { GameEngineLogo } from "./entities/game-engine-logo.entity";
import { PartialGame } from "./game-repository.types";
import { StatisticsQueueService } from "../../statistics/statistics-queue/statistics-queue.service";
import { StatisticsSourceType } from "../../statistics/statistics.constants";
import { days } from "@nestjs/throttler";

/**
* Service responsible for data inserting and updating for all game-related models.
Expand Down Expand Up @@ -101,6 +102,39 @@ export class GameRepositoryCreateService {
private readonly statisticsQueueService: StatisticsQueueService,
) {}

async shouldUpdate(game: PartialGame) {
if (game.id == null || typeof game.id !== "number") {
return false;
} else if (
game.name == undefined &&
(game.alternativeNames == undefined ||
game.alternativeNames.length === 0)
) {
return false;
} else if (
(await this.gameRepository.existsBy({ id: game.id })) &&
game.updatedAt != undefined
) {
const now = new Date();
const lastUpdateDate = game.updatedAt as Date;
const dayInMs = 1000 * 3600 * 24;

const differenceInTime = now.getTime() - lastUpdateDate.getTime();
const approximateDifferenceInDays = Math.round(
differenceInTime / dayInMs,
);

// game already exists and it has been more than thirty days since it's last update
// this logic only works if the 'updated_at' property is being returned by igdb-sync.
if (approximateDifferenceInDays >= 30) {
return false;
}
const one = 2;
}

return true;
}

/**
* Creates or updates a game in our database. <br>
* ManyToMany models can't be easily upserted, since the junction table is not inserted/updated automatically (without .save).
Expand All @@ -109,16 +143,11 @@ export class GameRepositoryCreateService {
* @param game
*/
async createOrUpdate(game: PartialGame) {
if (game.id == null || typeof game.id !== "number") {
throw new Error("Game ID must be a number.");
} else if (
game.name == undefined &&
(game.alternativeNames == undefined ||
game.alternativeNames.length === 0)
) {
throw new Error(
"Game name or alternative names must be specified.",
);
const shouldProcess = await this.shouldUpdate(game);

if (!shouldProcess) {
// Do not log here, as most games are skipped after the first run.
return;
}

const isUpdateAction = await this.gameRepository.existsBy({
Expand Down Expand Up @@ -163,9 +192,9 @@ export class GameRepositoryCreateService {

/**
* Builds child relationships which depend on the game being saved (e.g. alternative names, cover).
e.g. Relationships where Game is on the OneToMany or ManyToMany side.<br>
<strong> We assume the game is already persisted at this point, so we can use it as a parent.</strong>
* e.g. Relationships where Game is on the OneToMany or ManyToMany side.<br>
*
* <strong> We assume the game is already persisted at this point, so we can use it as a parent.</strong>
* @param game
*/
async buildChildRelationships(game: PartialGame) {
Expand Down
1 change: 0 additions & 1 deletion src/game/game-repository/game-repository.types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { DeepPartial } from "typeorm";
import { Game } from "./entities/game.entity";
import { PickType } from "@nestjs/swagger";

export type PartialGame = DeepPartial<Game> & {
id: number;
Expand Down
24 changes: 19 additions & 5 deletions src/notifications/notifications.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,20 @@ export class NotificationsService {
comparedNotification.category,
);

const comparableProperties: (keyof Notification)[] = [
const comparableSourceIds: (keyof Notification)[] = [
"reviewId",
"activityId",
"reviewCommentId",
"activityCommentId",
];

const isSameSource = comparableProperties.some(
const hasSameCategory =
notification.category === comparedNotification.category;
const hasSameSourceType =
notification.sourceType ===
comparedNotification.sourceType;

const hasSameSourceId = comparableSourceIds.some(
(property) => {
return (
comparedNotification[property] != undefined &&
Expand All @@ -129,7 +137,11 @@ export class NotificationsService {
);

const isSimilar =
!isAlreadyProcessed && hasValidCategory && isSameSource;
!isAlreadyProcessed &&
hasValidCategory &&
hasSameCategory &&
hasSameSourceType &&
hasSameSourceId;

if (isSimilar) {
processedEntities.set(
Expand All @@ -154,11 +166,13 @@ export class NotificationsService {
sourceId:
notification.reviewId! ||
notification.activityId! ||
notification.profileUserId! ||
notification.importerNotificationId! ||
notification.reportId! ||
notification.reviewCommentId! ||
notification.activityCommentId!,
notification.activityCommentId! ||
// profileUserId should be last, otherwise you will get weird issues.
notification.profileUserId!,

sourceType: notification.sourceType,
notifications: aggregationNotifications,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { StatisticsService } from "../statistics.types";
import { CommentStatisticsService } from "../comment-statistics.service";

@Processor(STATISTICS_QUEUE_NAME, {
concurrency: 300,
concurrency: 5,
})
export class StatisticsQueueProcessor extends WorkerHostProcessor {
logger = new Logger(StatisticsQueueProcessor.name);
Expand Down
12 changes: 11 additions & 1 deletion src/statistics/statistics.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,15 @@ export class StatisticsController {
return this.activityStatisticsService.findOne(
dto.sourceId as string,
);
case StatisticsSourceType.ACTIVITY_COMMENT:
return this.commentStatisticsService.findOne(
dto.sourceId as string,
StatisticsSourceType.ACTIVITY_COMMENT,
);
case StatisticsSourceType.REVIEW_COMMENT:
return this.commentStatisticsService.findOne(
dto.sourceId as string,
dto.sourceType,
StatisticsSourceType.REVIEW_COMMENT,
);
default:
throw new HttpException(
Expand Down Expand Up @@ -149,6 +154,11 @@ export class StatisticsController {
dto.statisticsId,
session?.getUserId(),
);
case StatisticsSourceType.ACTIVITY_COMMENT:
return this.commentStatisticsService.getStatus(
dto.statisticsId,
session?.getUserId(),
);
case StatisticsSourceType.REVIEW_COMMENT:
return this.commentStatisticsService.getStatus(
dto.statisticsId,
Expand Down
10 changes: 5 additions & 5 deletions src/sync/igdb/utils/game-conversor-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,17 @@ export const parseGameDates = (game: PartialGame) => {
"start_date",
"startDate",
];

for (const [key, value] of Object.entries(parsedGame)) {
if (dateFields.includes(key) && typeof value === "number") {
// IGDB Dates are always returned in seconds, even if they are
// unix timestamps.
let asDate: Date | undefined = new Date(value * 1000);

// Dates can't be invalid or in the future.
if (
asDate.toString() === "Invalid Date" ||
asDate.getTime() > Date.now()
) {
if (asDate.toString() === "Invalid Date") {
asDate = undefined;
}

parsedGame[key] = asDate;
}
}
Expand Down

0 comments on commit 1f26621

Please sign in to comment.