From ddff1c97fa43afefd261dfe91f74faaa54c61347 Mon Sep 17 00:00:00 2001 From: Lamarcke Date: Wed, 19 Jun 2024 00:47:39 -0300 Subject: [PATCH 1/7] - Report service now errors when a service is already closed - Fixed boolean parsing for query parameters in report request --- server_swagger.json | 2 +- src/report/dto/find-report-request.dto.ts | 8 ++++++-- src/report/report.controller.ts | 6 ++---- src/report/report.service.ts | 7 +++++++ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/server_swagger.json b/server_swagger.json index 8bc3e2b..7f10c5a 100644 --- a/server_swagger.json +++ b/server_swagger.json @@ -1 +1 @@ -{"openapi":"3.0.0","paths":{"/v1/auth/logout":{"get":{"operationId":"AuthController_logout","parameters":[],"responses":{"200":{"description":""}},"tags":["auth"]}},"/v1/libraries":{"get":{"operationId":"LibrariesController_findOwn","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Library"}}}}},"tags":["libraries"]}},"/v1/libraries/{id}":{"get":{"operationId":"LibrariesController_findOneByIdWithPermissions","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Library"}}}}},"tags":["libraries"]}},"/v1/collections/{id}":{"get":{"operationId":"CollectionsController_findOneByIdWithPermissions","summary":"","description":"Returns a collection which the user has access to\n\n(Either its own collection or a public one)","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Collection"}}}}},"tags":["collections"]},"patch":{"operationId":"CollectionsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCollectionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["collections"]},"delete":{"operationId":"CollectionsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["collections"]}},"/v1/collections/library/{userId}":{"get":{"operationId":"CollectionsController_findAllByUserIdWithPermissions","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}}}}}},"tags":["collections"]}},"/v1/collections":{"post":{"operationId":"CollectionsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCollectionDto"}}}},"responses":{"201":{"description":""}},"tags":["collections"]}},"/v1/reviews":{"post":{"operationId":"ReviewsController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviewDto"}}}},"responses":{"201":{"description":""}},"tags":["reviews"]},"get":{"operationId":"ReviewsController_findOneByUserIdAndGameId","parameters":[{"name":"id","required":true,"in":"query","schema":{"type":"string"}},{"name":"gameId","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}}},"tags":["reviews"]}},"/v1/reviews/all":{"post":{"operationId":"ReviewsController_findAllById","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllReviewsByIdDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Review"}}}}}},"tags":["reviews"]}},"/v1/reviews/score":{"get":{"operationId":"ReviewsController_getScoreForGameId","parameters":[{"name":"gameId","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewScoreResponseDto"}}}}},"tags":["reviews"]}},"/v1/reviews/profile/{userId}":{"get":{"operationId":"ReviewsController_findAllByUserId","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindReviewPaginatedDto"}}}}},"tags":["reviews"]}},"/v1/reviews/game/{id}":{"get":{"operationId":"ReviewsController_findAllByGameId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindReviewPaginatedDto"}}}}},"tags":["reviews"]}},"/v1/reviews/{id}":{"get":{"operationId":"ReviewsController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}}},"tags":["reviews"]},"delete":{"operationId":"ReviewsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reviews"]}},"/v1/profile":{"patch":{"operationId":"ProfileController_update","parameters":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UpdateProfileDto"}}}},"responses":{"200":{"description":""}},"tags":["profile"]},"get":{"operationId":"ProfileController_findOwn","summary":"","description":"Used to access own profile","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}}},"tags":["profile"]}},"/v1/profile/{id}":{"get":{"operationId":"ProfileController_findOneById","summary":"","description":"Used to access other users' profiles","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}}},"tags":["profile"]}},"/v1/activities":{"get":{"operationId":"ActivitiesRepositoryController_findLatest","parameters":[{"name":"userId","required":false,"in":"query","schema":{"minLength":36,"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesPaginatedResponseDto"}}}}},"tags":["activities"]}},"/v1/statistics/queue/like":{"post":{"operationId":"StatisticsQueueController_addLike","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"201":{"description":""}},"tags":["statistics-queue"]},"delete":{"operationId":"StatisticsQueueController_removeLike","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"200":{"description":""}},"tags":["statistics-queue"]}},"/v1/statistics/queue/view":{"post":{"operationId":"StatisticsQueueController_addView","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"201":{"description":""}},"tags":["statistics-queue"]}},"/v1/statistics":{"post":{"operationId":"StatisticsController_findOneBySourceIdAndType","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindOneStatisticsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/games":{"post":{"operationId":"StatisticsController_findTrendingGames","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingGamesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/reviews":{"post":{"operationId":"StatisticsController_findTrendingReviews","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingReviewsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/activities":{"post":{"operationId":"StatisticsController_findTrendingActivities","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingActivitiesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/status":{"get":{"operationId":"StatisticsController_getStatus","parameters":[{"name":"statisticsId","required":true,"in":"query","schema":{"type":"number"}},{"name":"sourceType","required":true,"in":"query","schema":{"enum":["game","review","activity","review_comment"],"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsStatus"}}}}},"tags":["statistics"]}},"/v1/notifications":{"get":{"operationId":"NotificationsController_findAllAndAggregate","parameters":[{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedNotificationAggregationDto"}}}}},"tags":["notifications"]}},"/v1/notifications/new":{"get":{"operationId":"NotificationsController_getNewNotifications","summary":"","description":"Finds new notifications that have been created after last checked time.
\nReturns an empty array on first connection.","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}}}}},"tags":["notifications"]}},"/v1/notifications/view":{"put":{"operationId":"NotificationsController_updateViewedStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationViewUpdateDto"}}}},"responses":{"200":{"description":""}},"tags":["notifications"]}},"/v1/game/repository/resource":{"get":{"operationId":"GameRepositoryController_getResource","parameters":[{"name":"resourceName","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}/platforms/icon":{"get":{"operationId":"GameRepositoryController_getIconNamesForPlatformAbbreviations","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}/external-stores":{"get":{"operationId":"GameRepositoryController_getExternalStoresForGameId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalStoreDto"}}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}":{"post":{"operationId":"GameRepositoryController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameRepositoryFindOneDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Game"}}}}},"tags":["game-repository"]}},"/v1/game/repository":{"post":{"operationId":"GameRepositoryController_findAllByIds","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameRepositoryFindAllDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}}}}},"tags":["game-repository"]}},"/v1/sync/hltb/{gameId}":{"get":{"operationId":"HltbController_findPlaytimeForGameId","parameters":[{"name":"gameId","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GamePlaytime"}}}}},"tags":["sync-hltb"]}},"/v1/achievements":{"get":{"operationId":"AchievementsController_getAchievements","parameters":[{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAchievementsResponseDto"}}}}},"tags":["achievements"]}},"/v1/achievements/obtained/{id}":{"get":{"operationId":"AchievementsController_getObtainedAchievement","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"targetUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObtainedAchievement"}}}}},"tags":["achievements"]}},"/v1/achievements/obtained":{"get":{"operationId":"AchievementsController_getAllObtainedAchievements","parameters":[{"name":"targetUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ObtainedAchievement"}}}}}},"tags":["achievements"]}},"/v1/achievements/obtained/{id}/featured":{"put":{"operationId":"AchievementsController_updateFeaturedObtainedAchievement","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFeaturedObtainedAchievementDto"}}}},"responses":{"200":{"description":""}},"tags":["achievements"]}},"/v1/level/{userId}":{"get":{"operationId":"LevelController_findOne","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLevel"}}}}},"tags":["level"]}},"/v1/collections-entries":{"post":{"operationId":"CollectionsEntriesController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateCollectionEntryDto"}}}},"responses":{"201":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/{id}":{"get":{"operationId":"CollectionsEntriesController_findEntryById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntry"}}}}},"tags":["collections-entries"]},"delete":{"operationId":"CollectionsEntriesController_deleteOwnEntry","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/game/{id}":{"get":{"operationId":"CollectionsEntriesController_findOwnEntryByGameId","summary":"","description":"Returns a specific collection entry based on game ID","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntry"}}}},"400":{"description":"Invalid query"}},"tags":["collections-entries"]}},"/v1/collections-entries/{id}/platforms/icons":{"get":{"operationId":"CollectionsEntriesController_getIconsForOwnedPlatforms","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/game/{id}/favorite":{"post":{"operationId":"CollectionsEntriesController_changeFavoriteStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFavoriteStatusCollectionEntryDto"}}}},"responses":{"204":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/library/{id}":{"get":{"operationId":"CollectionsEntriesController_findAllByLibraryId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/library/{id}/favorites":{"get":{"operationId":"CollectionsEntriesController_findFavoritesByLibraryId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/collection/{id}":{"post":{"operationId":"CollectionsEntriesController_findAllByCollectionId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindCollectionEntriesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/health":{"get":{"operationId":"HealthController_health","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["health"]}},"/v1/activities/feed":{"get":{"operationId":"ActivitiesFeedController_buildActivitiesFeed","parameters":[{"name":"criteria","required":true,"in":"query","schema":{"enum":["following","all"],"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesFeedPaginatedResponseDto"}}}}},"tags":["activities-feed"]}},"/v1/follow/status":{"get":{"operationId":"FollowController_getFollowerStatus","parameters":[{"name":"followerUserId","required":true,"in":"query","schema":{"type":"string"}},{"name":"followedUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowStatusDto"}}}}},"tags":["follow"]}},"/v1/follow/{id}":{"get":{"operationId":"FollowController_getUserFollowById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserFollow"}}}}},"tags":["follow"]}},"/v1/follow/info":{"post":{"operationId":"FollowController_getFollowInfo","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowInfoRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowInfoResponseDto"}}}}},"tags":["follow"]}},"/v1/follow":{"post":{"operationId":"FollowController_registerFollow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRegisterDto"}}}},"responses":{"201":{"description":""}},"tags":["follow"]},"delete":{"operationId":"FollowController_removeFollow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRemoveDto"}}}},"responses":{"200":{"description":""}},"tags":["follow"]}},"/v1/importer/watch/notification/{id}":{"get":{"operationId":"ImporterWatchController_findNotification","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterWatchNotification"}}}}},"tags":["importer-watch"]}},"/v1/importer/{source}":{"get":{"operationId":"ImporterController_findUnprocessedEntries","parameters":[{"name":"source","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterPaginatedResponseDto"}}}}},"tags":["importer"]}},"/v1/importer/status":{"post":{"operationId":"ImporterController_changeStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterStatusUpdateRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["importer"]}},"/v1/connections":{"get":{"operationId":"ConnectionsController_findAvailableConnections","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FindAvailableConnectionsResponseDto"}}}}}},"tags":["connections"]},"post":{"operationId":"ConnectionsController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionCreateDto"}}}},"responses":{"201":{"description":""}},"tags":["connections"]}},"/v1/connections/own":{"get":{"operationId":"ConnectionsController_findOwn","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserConnection"}}}}}},"tags":["connections"]}},"/v1/connections/own/{type}":{"get":{"operationId":"ConnectionsController_findOwnByType","parameters":[{"name":"type","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserConnection"}}}}},"tags":["connections"]}},"/v1/connections/{id}":{"delete":{"operationId":"ConnectionsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["connections"]}},"/v1/comment":{"post":{"operationId":"CommentController_findAll","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllCommentsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindCommentsPaginatedResponseDto"}}}}},"tags":["comment"]}},"/v1/comment/{sourceType}/{id}":{"get":{"operationId":"CommentController_findOneById","parameters":[{"name":"sourceType","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewComment"}}}}},"tags":["comment"]}},"/v1/comment/create":{"post":{"operationId":"CommentController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentDto"}}}},"responses":{"201":{"description":""}},"tags":["comment"]}},"/v1/comment/{id}":{"patch":{"operationId":"CommentController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCommentDto"}}}},"responses":{"204":{"description":""}},"tags":["comment"]},"delete":{"operationId":"CommentController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteCommentDto"}}}},"responses":{"200":{"description":""}},"tags":["comment"]}},"/v1/report":{"get":{"operationId":"ReportController_findAllByLatest","parameters":[{"name":"includeClosed","required":true,"in":"query","schema":{"default":false,"type":"boolean"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedReportResponseDto"}}}}},"tags":["report"]},"post":{"operationId":"ReportController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["report"]}},"/v1/report/{id}":{"get":{"operationId":"ReportController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}}}},"tags":["report"]}},"/v1/report/{id}/handle":{"post":{"operationId":"ReportController_handle","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandleReportRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["report"]}}},"info":{"title":"GameNode API","description":"API docs for the videogame catalog system GameNode.

Built with love by the GameNode team.","version":"1.0","contact":{}},"tags":[],"servers":[],"components":{"schemas":{"Library":{"type":"object","properties":{"userId":{"type":"string","description":"@description The primary key of the library entity.\nAlso used to share the library with other users.\n\nSame as SuperTokens' userId."},"collections":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["userId","collections","createdAt","updatedAt"]},"GameCover":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameCollection":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"checksum":{"type":"string"},"url":{"type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}},"required":["id","name","slug","createdAt","updatedAt","checksum","url","games"]},"GameAlternativeName":{"type":"object","properties":{"id":{"type":"number"},"comment":{"type":"string"},"name":{"type":"string"},"checksum":{"type":"string"},"game":{"$ref":"#/components/schemas/Game"}},"required":["id","game"]},"GameArtwork":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameScreenshot":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameLocalization":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameMode":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameGenre":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameTheme":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","createdAt","updatedAt"]},"GamePlayerPerspective":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameEngineLogo":{"type":"object","properties":{"engine":{"$ref":"#/components/schemas/GameEngine"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["engine","id"]},"GameCompanyLogo":{"type":"object","properties":{"company":{"$ref":"#/components/schemas/GameCompany"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["company","id"]},"GameCompany":{"type":"object","properties":{"id":{"type":"number"},"changeDate":{"format":"date-time","type":"string"},"changeDateCategory":{"type":"string"},"changedCompany":{"$ref":"#/components/schemas/GameCompany"},"checksum":{"type":"string"},"country":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"description":{"type":"string"},"logo":{"$ref":"#/components/schemas/GameCompanyLogo"},"name":{"type":"string"},"parent":{"$ref":"#/components/schemas/GameCompany"},"slug":{"type":"string"},"startDate":{"format":"date-time","type":"string"},"startDateCategory":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"url":{"type":"string"}},"required":["id","createdAt","name","slug","updatedAt"]},"GamePlatform":{"type":"object","properties":{"id":{"type":"number"},"abbreviation":{"type":"string"},"alternative_name":{"type":"string"},"category":{"type":"number","enum":[1,2,3,4,5,6]},"checksum":{"type":"string"},"generation":{"type":"number"},"name":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"collectionEntries":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}}},"required":["id","abbreviation","alternative_name","category","checksum","generation","name","createdAt","updatedAt","games","collectionEntries"]},"GameEngine":{"type":"object","properties":{"logo":{"$ref":"#/components/schemas/GameEngineLogo"},"companies":{"type":"array","items":{"$ref":"#/components/schemas/GameCompany"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["logo","companies","platforms","games","id","createdAt","updatedAt"]},"GameKeyword":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameFranchise":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameExternalGame":{"type":"object","properties":{"id":{"type":"number"},"uid":{"type":"string","description":"Corresponds to the game id on the target source (see GameExternalGameCategory).\nIt's called uid, not uuid."},"category":{"type":"number","enum":[1,5,10,11,13,14,15,20,22,23,26,28,29,30,31,32,36,37,54,55]},"media":{"type":"number","enum":[1,2]},"checksum":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"year":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"}},"required":["id","uid","createdAt","updatedAt","game","gameId"]},"GameInvolvedCompany":{"type":"object","properties":{"id":{"type":"number"},"checksum":{"type":"string"},"company":{"$ref":"#/components/schemas/GameCompany"},"companyId":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"developer":{"type":"boolean"},"porting":{"type":"boolean"},"publisher":{"type":"boolean"},"supporting":{"type":"boolean"},"updatedAt":{"format":"date-time","type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}},"required":["id","company","companyId","createdAt","developer","porting","publisher","supporting","updatedAt","games"]},"Game":{"type":"object","properties":{"id":{"type":"number","description":"Should be mapped to the IGDB ID of the game."},"name":{"type":"string"},"slug":{"type":"string"},"aggregatedRating":{"type":"number"},"aggregatedRatingCount":{"type":"number"},"category":{"enum":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14],"type":"number"},"status":{"enum":[0,2,3,4,5,6,7,8],"type":"number"},"summary":{"type":"string"},"storyline":{"type":"string"},"checksum":{"type":"string"},"url":{"type":"string"},"firstReleaseDate":{"format":"date-time","type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"dlcs":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"dlcOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expansions":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expansionOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expandedGames":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expandedGameOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"similarGames":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"similarGameOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remakes":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remakeOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remasters":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remasterOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"cover":{"$ref":"#/components/schemas/GameCover"},"collection":{"$ref":"#/components/schemas/GameCollection"},"alternativeNames":{"type":"array","items":{"$ref":"#/components/schemas/GameAlternativeName"}},"artworks":{"type":"array","items":{"$ref":"#/components/schemas/GameArtwork"}},"screenshots":{"type":"array","items":{"$ref":"#/components/schemas/GameScreenshot"}},"gameLocalizations":{"type":"array","items":{"$ref":"#/components/schemas/GameLocalization"}},"gameModes":{"type":"array","items":{"$ref":"#/components/schemas/GameMode"}},"genres":{"type":"array","items":{"$ref":"#/components/schemas/GameGenre"}},"themes":{"type":"array","items":{"$ref":"#/components/schemas/GameTheme"}},"playerPerspectives":{"type":"array","items":{"$ref":"#/components/schemas/GamePlayerPerspective"}},"gameEngines":{"type":"array","items":{"$ref":"#/components/schemas/GameEngine"}},"keywords":{"type":"array","items":{"$ref":"#/components/schemas/GameKeyword"}},"franchises":{"type":"array","items":{"$ref":"#/components/schemas/GameFranchise"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"externalGames":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}},"involvedCompanies":{"type":"array","items":{"$ref":"#/components/schemas/GameInvolvedCompany"}},"source":{"type":"string","description":"Oh dear maintainer, please forgive me for using transient fields.","default":"MYSQL","enum":["MYSQL","MANTICORE"]}},"required":["id","name","slug","category","status","summary","storyline","checksum","url","firstReleaseDate","createdAt","updatedAt","involvedCompanies","source"]},"ProfileAvatar":{"type":"object","properties":{"id":{"type":"number"},"mimetype":{"type":"string"},"extension":{"type":"string"},"size":{"type":"number"},"filename":{"type":"string"},"encoding":{"type":"string"},"profile":{"$ref":"#/components/schemas/Profile"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","mimetype","extension","size","filename","encoding","profile","createdAt","updatedAt"]},"Profile":{"type":"object","properties":{"userId":{"type":"string","description":"Shareable string ID\n\nSame as SuperTokens' userId."},"username":{"type":"string"},"bio":{"type":"string"},"avatar":{"$ref":"#/components/schemas/ProfileAvatar"},"usernameLastUpdatedAt":{"format":"date-time","type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["userId","username","bio","avatar","usernameLastUpdatedAt","createdAt","updatedAt"]},"Review":{"type":"object","properties":{"id":{"type":"string"},"content":{"type":"string","nullable":true},"rating":{"type":"number"},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"collectionEntry":{"$ref":"#/components/schemas/CollectionEntry"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","content","rating","game","gameId","profile","profileUserId","collectionEntry","createdAt","updatedAt"]},"CollectionEntry":{"type":"object","properties":{"id":{"type":"string"},"collections":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"ownedPlatforms":{"description":"The platforms on which the user owns the game.","type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"isFavorite":{"type":"boolean"},"finishedAt":{"format":"date-time","type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","collections","game","gameId","ownedPlatforms","review","isFavorite","finishedAt","createdAt","updatedAt"]},"Collection":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"isPublic":{"type":"boolean"},"library":{"$ref":"#/components/schemas/Library"},"libraryUserId":{"type":"string"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}},"isFeatured":{"type":"boolean"},"isFinished":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","name","description","isPublic","library","libraryUserId","entries","isFeatured","isFinished","createdAt","updatedAt"]},"CreateCollectionDto":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"isPublic":{"type":"boolean"},"isFeatured":{"type":"boolean"},"isFinished":{"type":"boolean"}},"required":["name","isPublic","isFeatured","isFinished"]},"UpdateCollectionDto":{"type":"object","properties":{}},"CreateReviewDto":{"type":"object","properties":{"gameId":{"type":"number"},"content":{"type":"string","minLength":20},"rating":{"type":"number","minimum":0,"maximum":5}},"required":["gameId","content","rating"]},"FindAllReviewsByIdDto":{"type":"object","properties":{"reviewsIds":{"type":"array","items":{"type":"string"}}},"required":["reviewsIds"]},"ReviewScoreDistribution":{"type":"object","properties":{"1":{"type":"number"},"2":{"type":"number"},"3":{"type":"number"},"4":{"type":"number"},"5":{"type":"number"},"total":{"type":"number","description":"Total number of reviews"}},"required":["1","2","3","4","5","total"]},"ReviewScoreResponseDto":{"type":"object","properties":{"median":{"type":"number"},"distribution":{"$ref":"#/components/schemas/ReviewScoreDistribution"}},"required":["median","distribution"]},"PaginationInfo":{"type":"object","properties":{"totalItems":{"type":"number","description":"Total number of items available for the current query"},"totalPages":{"type":"number","description":"Total number of pages available for the current query"},"hasNextPage":{"type":"boolean","description":"If this query allows for a next page"}},"required":["totalItems","totalPages","hasNextPage"]},"FindReviewPaginatedDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Review"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"UpdateProfileDto":{"type":"object","properties":{"username":{"type":"string","minLength":4,"maxLength":20},"avatar":{"type":"object"},"bio":{"type":"string","minLength":1,"maxLength":240}}},"UserFollow":{"type":"object","properties":{"id":{"type":"number"},"follower":{"$ref":"#/components/schemas/Profile"},"followerUserId":{"type":"string"},"followed":{"$ref":"#/components/schemas/Profile"},"followedUserId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","follower","followerUserId","followed","followedUserId","createdAt","updatedAt"]},"Activity":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["REVIEW","FOLLOW","COLLECTION_ENTRY"]},"profile":{"description":"The associated profile with this Activity (e.g. user who performed an action)","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string"},"collectionEntry":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CollectionEntry"}]},"collectionEntryId":{"type":"string","nullable":true},"collection":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Collection"}]},"collectionId":{"type":"string","nullable":true},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"reviewId":{"type":"string","nullable":true},"userFollow":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/UserFollow"}]},"userFollowId":{"type":"number","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","type","profile","profileUserId","collectionEntry","collectionEntryId","collection","collectionId","review","reviewId","userFollow","userFollowId","createdAt","updatedAt"]},"ActivitiesPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"StatisticsActionDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"targetUserId":{"type":"string","minLength":36},"sourceType":{"enum":["game","review","activity","review_comment"],"type":"string"}},"required":["sourceId","sourceType"]},"FindOneStatisticsDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"sourceType":{"type":"string","enum":["game","review","activity","review_comment"]}},"required":["sourceId","sourceType"]},"GameRepositoryFilterDto":{"type":"object","properties":{"ids":{"description":"If this is supplied, filtering will be done only for entities specified here.
\nUseful to filter data received from entities which hold game ids (like GameStatistics, Reviews, etc.)","type":"array","items":{"type":"number"}},"status":{"type":"number","enum":[0,2,3,4,5,6,7,8]},"category":{"type":"number","enum":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]},"themes":{"type":"array","items":{"type":"number"}},"gameModes":{"type":"array","items":{"type":"number"}},"platforms":{"type":"array","items":{"type":"number"}},"genres":{"type":"array","items":{"type":"number"}},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}}},"FindStatisticsTrendingGamesDto":{"type":"object","properties":{"criteria":{"$ref":"#/components/schemas/GameRepositoryFilterDto"},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"ActivityStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"activity":{"$ref":"#/components/schemas/Activity"},"activityId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","activity","activityId","id","viewsCount","likesCount"]},"ReviewComment":{"type":"object","properties":{"review":{"$ref":"#/components/schemas/Review"},"reviewId":{"type":"string"},"id":{"type":"string"},"content":{"type":"string","description":"HTML content of the user's comment."},"profile":{"description":"Author of this comment","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string","description":"User id of the author of this comment"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["review","reviewId","id","content","profile","profileUserId","createdAt","updatedAt"]},"CommentStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"reviewComment":{"$ref":"#/components/schemas/ReviewComment"},"reviewCommentId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","reviewComment","reviewCommentId","id","viewsCount","likesCount"]},"UserLike":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/GameStatistics"}]},"gameStatisticsId":{"type":"number","nullable":true},"reviewStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewStatistics"}]},"reviewStatisticsId":{"type":"number","nullable":true},"activityStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ActivityStatistics"}]},"activityStatisticsId":{"type":"number","nullable":true},"commentStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CommentStatistics"}]},"commentStatisticsId":{"type":"number","nullable":true}},"required":["id","profile","profileUserId","createdAt","updatedAt","gameStatistics","gameStatisticsId","reviewStatistics","reviewStatisticsId","activityStatistics","activityStatisticsId","commentStatistics","commentStatisticsId"]},"ReviewStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"review":{"$ref":"#/components/schemas/Review"},"reviewId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","review","reviewId","id","viewsCount","likesCount"]},"UserView":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/GameStatistics"}]},"reviewStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewStatistics"}]},"activityStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ActivityStatistics"}]},"commentStatistics":{"type":"object"}},"required":["id","profileUserId","createdAt","updatedAt","gameStatistics","reviewStatistics","activityStatistics","commentStatistics"]},"GameStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","game","gameId","id","viewsCount","likesCount"]},"GameStatisticsPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameStatistics"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindStatisticsTrendingReviewsDto":{"type":"object","properties":{"reviewId":{"type":"string","description":"Usually, this property should not be used unless a specific review needs to be retrieved, and it's easier to just\ncall the statistics controller."},"gameId":{"type":"number"},"userId":{"type":"string","minLength":36},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"ReviewStatisticsPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReviewStatistics"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindStatisticsTrendingActivitiesDto":{"type":"object","properties":{"activityId":{"type":"string","description":"Usually, this property should not be used unless a specific activity needs to be retrieved, and it's easier to just\ncall the statistics controller.","minLength":36},"userId":{"type":"string","minLength":36},"activityType":{"type":"string","enum":["REVIEW","FOLLOW","COLLECTION_ENTRY"]},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"StatisticsStatus":{"type":"object","properties":{"isLiked":{"type":"boolean"},"isViewed":{"type":"boolean"}},"required":["isLiked","isViewed"]},"ImporterWatchNotification":{"type":"object","properties":{"id":{"type":"number"},"library":{"$ref":"#/components/schemas/Library"},"libraryUserId":{"type":"string"},"source":{"type":"string","enum":["steam"]},"games":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}}},"required":["id","library","libraryUserId","source","games"]},"Notification":{"type":"object","properties":{"id":{"type":"number"},"sourceType":{"enum":["game","review","activity","profile","importer","report"],"type":"string"},"category":{"description":"What this notification's about. E.g.: a new like, a new follower, a game launch, etc.","enum":["follow","like","comment","watch","alert"],"type":"string"},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"reviewId":{"type":"string","nullable":true},"game":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Game"}]},"gameId":{"type":"number","nullable":true},"activity":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Activity"}]},"activityId":{"type":"string","nullable":true},"profile":{"nullable":true,"description":"User responsible for generating this notification (e.g. user that liked a review).","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string","nullable":true,"description":"User responsible for generating this notification (e.g. user that liked a review).\nWhen null/undefined, the notification was generated by the 'system'."},"importerNotification":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ImporterWatchNotification"}]},"importerNotificationId":{"type":"number"},"report":{"type":"object"},"reportId":{"type":"number","nullable":true},"isViewed":{"type":"boolean"},"targetProfile":{"nullable":true,"description":"User which is the target for this notification.
\nIf this is empty (null/undefined), the notification is targeted at all users.
\nNot to be confused with the 'profile' property.","allOf":[{"$ref":"#/components/schemas/Profile"}]},"targetProfileUserId":{"type":"string","nullable":true,"description":"User which is the target for this notification.
\nIf this is empty (null/undefined), the notification is targeted at all users.
\nNot to be confused with the 'profile' property."},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","sourceType","category","review","reviewId","game","gameId","activity","activityId","profile","profileUserId","importerNotification","importerNotificationId","report","reportId","isViewed","targetProfile","targetProfileUserId","createdAt","updatedAt"]},"NotificationAggregateDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"category":{"type":"string","enum":["follow","like","comment","watch","alert"]},"sourceType":{"type":"string","enum":["game","review","activity","profile","importer","report"]},"notifications":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}},"required":["sourceId","category","sourceType","notifications"]},"PaginatedNotificationAggregationDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NotificationAggregateDto"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"NotificationViewUpdateDto":{"type":"object","properties":{"isViewed":{"type":"boolean"},"notificationIds":{"type":"array","items":{"type":"number"}}},"required":["isViewed","notificationIds"]},"GameExternalStoreDto":{"type":"object","properties":{"icon":{"type":"string","nullable":true,"description":"Icon representing said store/service."},"storeName":{"type":"string","nullable":true},"id":{"type":"number"},"uid":{"type":"string","description":"Corresponds to the game id on the target source (see GameExternalGameCategory).\nIt's called uid, not uuid."},"category":{"type":"number","enum":[1,5,10,11,13,14,15,20,22,23,26,28,29,30,31,32,36,37,54,55]},"media":{"type":"number","enum":[1,2]},"checksum":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"year":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameId":{"type":"number"}},"required":["icon","storeName","id","uid","createdAt","updatedAt","gameId"]},"GameRepositoryFindOneDto":{"type":"object","properties":{"relations":{"type":"object"}}},"GameRepositoryFindAllDto":{"type":"object","properties":{"gameIds":{"type":"array","items":{"type":"number"}},"relations":{"type":"object"}},"required":["gameIds"]},"GamePlaytime":{"type":"object","properties":{"id":{"type":"number"},"gameId":{"type":"number"},"game":{"$ref":"#/components/schemas/Game"},"sourceId":{"type":"number"},"timeMain":{"type":"number","nullable":true},"timePlus":{"type":"number","nullable":true},"time100":{"type":"number","nullable":true},"timeAll":{"type":"number","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","gameId","game","sourceId","timeMain","timePlus","time100","timeAll","createdAt","updatedAt"]},"AchievementDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"expGainAmount":{"type":"number"},"category":{"type":"number","enum":[0,1,2,3]}},"required":["id","name","description","expGainAmount","category"]},"PaginatedAchievementsResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AchievementDto"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"ObtainedAchievement":{"type":"object","properties":{"id":{"type":"number"},"achievementId":{"type":"string","description":"Achievement id specified in entries for achievements.data.ts"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"isFeatured":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","achievementId","profile","profileUserId","isFeatured","createdAt","updatedAt"]},"UpdateFeaturedObtainedAchievementDto":{"type":"object","properties":{"isFeatured":{"type":"boolean"}},"required":["isFeatured"]},"UserLevel":{"type":"object","properties":{"userId":{"type":"string","description":"Should be the same as the profile's UserId"},"profile":{"$ref":"#/components/schemas/Profile"},"currentLevel":{"type":"number"},"currentLevelExp":{"type":"number","description":"XP in the current user-level"},"levelUpExpCost":{"type":"number","description":"Threshold XP to hit the next user-level"},"expMultiplier":{"type":"number","description":"The multiplier to apply to all exp gains"}},"required":["userId","profile","currentLevel","currentLevelExp","levelUpExpCost","expMultiplier"]},"CreateUpdateCollectionEntryDto":{"type":"object","properties":{"finishedAt":{"type":"date-time"},"collectionIds":{"type":"array","items":{"type":"string"}},"gameId":{"type":"number"},"platformIds":{"type":"array","items":{"type":"number"}},"isFavorite":{"type":"boolean","default":false}},"required":["collectionIds","gameId","platformIds","isFavorite"]},"CreateFavoriteStatusCollectionEntryDto":{"type":"object","properties":{"isFavorite":{"type":"boolean","default":false}},"required":["isFavorite"]},"CollectionEntriesPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindCollectionEntriesDto":{"type":"object","properties":{"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}}},"ActivitiesFeedPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FollowStatusDto":{"type":"object","properties":{"isFollowing":{"type":"boolean"}},"required":["isFollowing"]},"FollowInfoRequestDto":{"type":"object","properties":{"criteria":{"type":"string","enum":["followers","following"]},"targetUserId":{"type":"string","minLength":36},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}},"required":["criteria","targetUserId"]},"FollowInfoResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FollowRegisterDto":{"type":"object","properties":{"followedUserId":{"type":"string","minLength":36}},"required":["followedUserId"]},"FollowRemoveDto":{"type":"object","properties":{"followedUserId":{"type":"string","minLength":36}},"required":["followedUserId"]},"ImporterPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"ImporterStatusUpdateRequestDto":{"type":"object","properties":{"status":{"type":"string"},"externalGameId":{"type":"number"}},"required":["status","externalGameId"]},"FindAvailableConnectionsResponseDto":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["steam"]},"isImporterViable":{"type":"boolean"},"iconName":{"type":"string"}},"required":["name","type","isImporterViable","iconName"]},"UserConnection":{"type":"object","properties":{"id":{"type":"number"},"type":{"type":"string","enum":["steam"]},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"sourceUserId":{"type":"string"},"sourceUsername":{"type":"string"},"isImporterViable":{"type":"boolean","description":"If this connection can be used by the 'importer' system."},"isImporterEnabled":{"type":"boolean"}},"required":["id","type","profile","profileUserId","sourceUserId","sourceUsername","isImporterViable","isImporterEnabled"]},"ConnectionCreateDto":{"type":"object","properties":{"type":{"type":"string","enum":["steam"]},"userIdentifier":{"type":"string","description":"A string representing a username, user id or profile URL for the target connection
\ne.g. a Steam's profile URL","minLength":1},"isImporterEnabled":{"type":"boolean","default":false}},"required":["type","userIdentifier","isImporterEnabled"]},"FindAllCommentsDto":{"type":"object","properties":{"sourceId":{"type":"string","minLength":36},"sourceType":{"type":"string","enum":["review"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}},"required":["sourceId","sourceType"]},"FindCommentsPaginatedResponseDto":{"type":"object","properties":{"data":{"default":[],"type":"array","items":{"$ref":"#/components/schemas/ReviewComment"}},"pagination":{"default":{},"allOf":[{"$ref":"#/components/schemas/PaginationInfo"}]}},"required":["data","pagination"]},"CreateCommentDto":{"type":"object","properties":{"sourceId":{"type":"string","description":"UUID of the target entity. Comments can only be attributed to\nUUID based entities.","minLength":36},"sourceType":{"type":"string","enum":["review"]},"content":{"type":"string","minLength":1}},"required":["sourceId","sourceType","content"]},"UpdateCommentDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review"]},"content":{"type":"string","minLength":1}},"required":["sourceType","content"]},"DeleteCommentDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review"]}},"required":["sourceType"]},"Report":{"type":"object","properties":{"id":{"type":"number"},"sourceType":{"description":"Indexed to improve speed when filtering by type.","enum":["review","profile","review_comment"],"type":"string"},"category":{"enum":["spam","personal"],"type":"string"},"targetReview":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"targetReviewId":{"type":"string","nullable":true},"targetReviewComment":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewComment"}]},"targetReviewCommentId":{"type":"string","nullable":true},"targetProfile":{"description":"Profile that is being target of a report","allOf":[{"$ref":"#/components/schemas/Profile"}]},"targetProfileUserId":{"type":"string"},"reason":{"type":"string","nullable":true,"description":"User-submitted reason for report."},"profile":{"description":"User responsible for report.","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string"},"isClosed":{"type":"boolean"},"closeHandleAction":{"nullable":true,"description":"Action taken when closing this report","enum":["discard","alert","suspend","ban"],"type":"string"},"closeProfile":{"nullable":true,"description":"User responsible for closing this report","allOf":[{"$ref":"#/components/schemas/Profile"}]},"closeProfileUserId":{"type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","sourceType","category","targetReview","targetReviewId","targetReviewComment","targetReviewCommentId","targetProfile","targetProfileUserId","reason","profile","profileUserId","isClosed","closeHandleAction","closeProfile","closeProfileUserId","createdAt","updatedAt"]},"PaginatedReportResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Report"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"CreateReportRequestDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review","profile","review_comment"]},"sourceId":{"type":"string","minLength":36},"category":{"type":"string","enum":["spam","personal"]},"reason":{"type":"string"}},"required":["sourceType","sourceId","category"]},"HandleReportRequestDto":{"type":"object","properties":{"action":{"type":"string","enum":["discard","alert","suspend","ban"]},"deleteReportedContent":{"type":"boolean","default":true}},"required":["action","deleteReportedContent"]}}}} \ No newline at end of file +{"openapi":"3.0.0","paths":{"/v1/auth/logout":{"get":{"operationId":"AuthController_logout","parameters":[],"responses":{"200":{"description":""}},"tags":["auth"]}},"/v1/libraries":{"get":{"operationId":"LibrariesController_findOwn","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Library"}}}}},"tags":["libraries"]}},"/v1/libraries/{id}":{"get":{"operationId":"LibrariesController_findOneByIdWithPermissions","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Library"}}}}},"tags":["libraries"]}},"/v1/collections/{id}":{"get":{"operationId":"CollectionsController_findOneByIdWithPermissions","summary":"","description":"Returns a collection which the user has access to\n\n(Either its own collection or a public one)","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Collection"}}}}},"tags":["collections"]},"patch":{"operationId":"CollectionsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCollectionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["collections"]},"delete":{"operationId":"CollectionsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["collections"]}},"/v1/collections/library/{userId}":{"get":{"operationId":"CollectionsController_findAllByUserIdWithPermissions","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}}}}}},"tags":["collections"]}},"/v1/collections":{"post":{"operationId":"CollectionsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCollectionDto"}}}},"responses":{"201":{"description":""}},"tags":["collections"]}},"/v1/reviews":{"post":{"operationId":"ReviewsController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviewDto"}}}},"responses":{"201":{"description":""}},"tags":["reviews"]},"get":{"operationId":"ReviewsController_findOneByUserIdAndGameId","parameters":[{"name":"id","required":true,"in":"query","schema":{"type":"string"}},{"name":"gameId","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}}},"tags":["reviews"]}},"/v1/reviews/all":{"post":{"operationId":"ReviewsController_findAllById","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllReviewsByIdDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Review"}}}}}},"tags":["reviews"]}},"/v1/reviews/score":{"get":{"operationId":"ReviewsController_getScoreForGameId","parameters":[{"name":"gameId","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewScoreResponseDto"}}}}},"tags":["reviews"]}},"/v1/reviews/profile/{userId}":{"get":{"operationId":"ReviewsController_findAllByUserId","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindReviewPaginatedDto"}}}}},"tags":["reviews"]}},"/v1/reviews/game/{id}":{"get":{"operationId":"ReviewsController_findAllByGameId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindReviewPaginatedDto"}}}}},"tags":["reviews"]}},"/v1/reviews/{id}":{"get":{"operationId":"ReviewsController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}}},"tags":["reviews"]},"delete":{"operationId":"ReviewsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reviews"]}},"/v1/profile":{"patch":{"operationId":"ProfileController_update","parameters":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UpdateProfileDto"}}}},"responses":{"200":{"description":""}},"tags":["profile"]},"get":{"operationId":"ProfileController_findOwn","summary":"","description":"Used to access own profile","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}}},"tags":["profile"]}},"/v1/profile/{id}":{"get":{"operationId":"ProfileController_findOneById","summary":"","description":"Used to access other users' profiles","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}}},"tags":["profile"]}},"/v1/activities":{"get":{"operationId":"ActivitiesRepositoryController_findLatest","parameters":[{"name":"userId","required":false,"in":"query","schema":{"minLength":36,"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesPaginatedResponseDto"}}}}},"tags":["activities"]}},"/v1/statistics/queue/like":{"post":{"operationId":"StatisticsQueueController_addLike","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"201":{"description":""}},"tags":["statistics-queue"]},"delete":{"operationId":"StatisticsQueueController_removeLike","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"200":{"description":""}},"tags":["statistics-queue"]}},"/v1/statistics/queue/view":{"post":{"operationId":"StatisticsQueueController_addView","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"201":{"description":""}},"tags":["statistics-queue"]}},"/v1/statistics":{"post":{"operationId":"StatisticsController_findOneBySourceIdAndType","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindOneStatisticsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/games":{"post":{"operationId":"StatisticsController_findTrendingGames","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingGamesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/reviews":{"post":{"operationId":"StatisticsController_findTrendingReviews","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingReviewsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/activities":{"post":{"operationId":"StatisticsController_findTrendingActivities","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingActivitiesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/status":{"get":{"operationId":"StatisticsController_getStatus","parameters":[{"name":"statisticsId","required":true,"in":"query","schema":{"type":"number"}},{"name":"sourceType","required":true,"in":"query","schema":{"enum":["game","review","activity","review_comment"],"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsStatus"}}}}},"tags":["statistics"]}},"/v1/notifications":{"get":{"operationId":"NotificationsController_findAllAndAggregate","parameters":[{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedNotificationAggregationDto"}}}}},"tags":["notifications"]}},"/v1/notifications/new":{"get":{"operationId":"NotificationsController_getNewNotifications","summary":"","description":"Finds new notifications that have been created after last checked time.
\nReturns an empty array on first connection.","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}}}}},"tags":["notifications"]}},"/v1/notifications/view":{"put":{"operationId":"NotificationsController_updateViewedStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationViewUpdateDto"}}}},"responses":{"200":{"description":""}},"tags":["notifications"]}},"/v1/game/repository/resource":{"get":{"operationId":"GameRepositoryController_getResource","parameters":[{"name":"resourceName","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}/platforms/icon":{"get":{"operationId":"GameRepositoryController_getIconNamesForPlatformAbbreviations","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}/external-stores":{"get":{"operationId":"GameRepositoryController_getExternalStoresForGameId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalStoreDto"}}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}":{"post":{"operationId":"GameRepositoryController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameRepositoryFindOneDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Game"}}}}},"tags":["game-repository"]}},"/v1/game/repository":{"post":{"operationId":"GameRepositoryController_findAllByIds","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameRepositoryFindAllDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}}}}},"tags":["game-repository"]}},"/v1/sync/hltb/{gameId}":{"get":{"operationId":"HltbController_findPlaytimeForGameId","parameters":[{"name":"gameId","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GamePlaytime"}}}}},"tags":["sync-hltb"]}},"/v1/achievements":{"get":{"operationId":"AchievementsController_getAchievements","parameters":[{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAchievementsResponseDto"}}}}},"tags":["achievements"]}},"/v1/achievements/obtained/{id}":{"get":{"operationId":"AchievementsController_getObtainedAchievement","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"targetUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObtainedAchievement"}}}}},"tags":["achievements"]}},"/v1/achievements/obtained":{"get":{"operationId":"AchievementsController_getAllObtainedAchievements","parameters":[{"name":"targetUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ObtainedAchievement"}}}}}},"tags":["achievements"]}},"/v1/achievements/obtained/{id}/featured":{"put":{"operationId":"AchievementsController_updateFeaturedObtainedAchievement","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFeaturedObtainedAchievementDto"}}}},"responses":{"200":{"description":""}},"tags":["achievements"]}},"/v1/level/{userId}":{"get":{"operationId":"LevelController_findOne","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLevel"}}}}},"tags":["level"]}},"/v1/collections-entries":{"post":{"operationId":"CollectionsEntriesController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateCollectionEntryDto"}}}},"responses":{"201":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/{id}":{"get":{"operationId":"CollectionsEntriesController_findEntryById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntry"}}}}},"tags":["collections-entries"]},"delete":{"operationId":"CollectionsEntriesController_deleteOwnEntry","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/game/{id}":{"get":{"operationId":"CollectionsEntriesController_findOwnEntryByGameId","summary":"","description":"Returns a specific collection entry based on game ID","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntry"}}}},"400":{"description":"Invalid query"}},"tags":["collections-entries"]}},"/v1/collections-entries/{id}/platforms/icons":{"get":{"operationId":"CollectionsEntriesController_getIconsForOwnedPlatforms","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/game/{id}/favorite":{"post":{"operationId":"CollectionsEntriesController_changeFavoriteStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFavoriteStatusCollectionEntryDto"}}}},"responses":{"204":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/library/{id}":{"get":{"operationId":"CollectionsEntriesController_findAllByLibraryId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/library/{id}/favorites":{"get":{"operationId":"CollectionsEntriesController_findFavoritesByLibraryId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/collection/{id}":{"post":{"operationId":"CollectionsEntriesController_findAllByCollectionId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindCollectionEntriesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/health":{"get":{"operationId":"HealthController_health","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["health"]}},"/v1/activities/feed":{"get":{"operationId":"ActivitiesFeedController_buildActivitiesFeed","parameters":[{"name":"criteria","required":true,"in":"query","schema":{"enum":["following","all"],"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesFeedPaginatedResponseDto"}}}}},"tags":["activities-feed"]}},"/v1/follow/status":{"get":{"operationId":"FollowController_getFollowerStatus","parameters":[{"name":"followerUserId","required":true,"in":"query","schema":{"type":"string"}},{"name":"followedUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowStatusDto"}}}}},"tags":["follow"]}},"/v1/follow/{id}":{"get":{"operationId":"FollowController_getUserFollowById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserFollow"}}}}},"tags":["follow"]}},"/v1/follow/info":{"post":{"operationId":"FollowController_getFollowInfo","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowInfoRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowInfoResponseDto"}}}}},"tags":["follow"]}},"/v1/follow":{"post":{"operationId":"FollowController_registerFollow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRegisterDto"}}}},"responses":{"201":{"description":""}},"tags":["follow"]},"delete":{"operationId":"FollowController_removeFollow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRemoveDto"}}}},"responses":{"200":{"description":""}},"tags":["follow"]}},"/v1/importer/watch/notification/{id}":{"get":{"operationId":"ImporterWatchController_findNotification","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterWatchNotification"}}}}},"tags":["importer-watch"]}},"/v1/importer/{source}":{"get":{"operationId":"ImporterController_findUnprocessedEntries","parameters":[{"name":"source","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterPaginatedResponseDto"}}}}},"tags":["importer"]}},"/v1/importer/status":{"post":{"operationId":"ImporterController_changeStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterStatusUpdateRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["importer"]}},"/v1/connections":{"get":{"operationId":"ConnectionsController_findAvailableConnections","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FindAvailableConnectionsResponseDto"}}}}}},"tags":["connections"]},"post":{"operationId":"ConnectionsController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionCreateDto"}}}},"responses":{"201":{"description":""}},"tags":["connections"]}},"/v1/connections/own":{"get":{"operationId":"ConnectionsController_findOwn","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserConnection"}}}}}},"tags":["connections"]}},"/v1/connections/own/{type}":{"get":{"operationId":"ConnectionsController_findOwnByType","parameters":[{"name":"type","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserConnection"}}}}},"tags":["connections"]}},"/v1/connections/{id}":{"delete":{"operationId":"ConnectionsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["connections"]}},"/v1/comment":{"post":{"operationId":"CommentController_findAll","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllCommentsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindCommentsPaginatedResponseDto"}}}}},"tags":["comment"]}},"/v1/comment/{sourceType}/{id}":{"get":{"operationId":"CommentController_findOneById","parameters":[{"name":"sourceType","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewComment"}}}}},"tags":["comment"]}},"/v1/comment/create":{"post":{"operationId":"CommentController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentDto"}}}},"responses":{"201":{"description":""}},"tags":["comment"]}},"/v1/comment/{id}":{"patch":{"operationId":"CommentController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCommentDto"}}}},"responses":{"204":{"description":""}},"tags":["comment"]},"delete":{"operationId":"CommentController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteCommentDto"}}}},"responses":{"200":{"description":""}},"tags":["comment"]}},"/v1/report":{"get":{"operationId":"ReportController_findAllByLatest","parameters":[{"name":"includeClosed","required":false,"in":"query","schema":{"default":false,"type":"boolean"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedReportResponseDto"}}}}},"tags":["report"]},"post":{"operationId":"ReportController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["report"]}},"/v1/report/{id}":{"get":{"operationId":"ReportController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}}}},"tags":["report"]}},"/v1/report/{id}/handle":{"post":{"operationId":"ReportController_handle","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandleReportRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["report"]}}},"info":{"title":"GameNode API","description":"API docs for the videogame catalog system GameNode.

Built with love by the GameNode team.","version":"1.0","contact":{}},"tags":[],"servers":[],"components":{"schemas":{"Library":{"type":"object","properties":{"userId":{"type":"string","description":"@description The primary key of the library entity.\nAlso used to share the library with other users.\n\nSame as SuperTokens' userId."},"collections":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["userId","collections","createdAt","updatedAt"]},"GameCover":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameCollection":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"checksum":{"type":"string"},"url":{"type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}},"required":["id","name","slug","createdAt","updatedAt","checksum","url","games"]},"GameAlternativeName":{"type":"object","properties":{"id":{"type":"number"},"comment":{"type":"string"},"name":{"type":"string"},"checksum":{"type":"string"},"game":{"$ref":"#/components/schemas/Game"}},"required":["id","game"]},"GameArtwork":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameScreenshot":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameLocalization":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameMode":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameGenre":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameTheme":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","createdAt","updatedAt"]},"GamePlayerPerspective":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameEngineLogo":{"type":"object","properties":{"engine":{"$ref":"#/components/schemas/GameEngine"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["engine","id"]},"GameCompanyLogo":{"type":"object","properties":{"company":{"$ref":"#/components/schemas/GameCompany"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["company","id"]},"GameCompany":{"type":"object","properties":{"id":{"type":"number"},"changeDate":{"format":"date-time","type":"string"},"changeDateCategory":{"type":"string"},"changedCompany":{"$ref":"#/components/schemas/GameCompany"},"checksum":{"type":"string"},"country":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"description":{"type":"string"},"logo":{"$ref":"#/components/schemas/GameCompanyLogo"},"name":{"type":"string"},"parent":{"$ref":"#/components/schemas/GameCompany"},"slug":{"type":"string"},"startDate":{"format":"date-time","type":"string"},"startDateCategory":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"url":{"type":"string"}},"required":["id","createdAt","name","slug","updatedAt"]},"GamePlatform":{"type":"object","properties":{"id":{"type":"number"},"abbreviation":{"type":"string"},"alternative_name":{"type":"string"},"category":{"type":"number","enum":[1,2,3,4,5,6]},"checksum":{"type":"string"},"generation":{"type":"number"},"name":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"collectionEntries":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}}},"required":["id","abbreviation","alternative_name","category","checksum","generation","name","createdAt","updatedAt","games","collectionEntries"]},"GameEngine":{"type":"object","properties":{"logo":{"$ref":"#/components/schemas/GameEngineLogo"},"companies":{"type":"array","items":{"$ref":"#/components/schemas/GameCompany"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["logo","companies","platforms","games","id","createdAt","updatedAt"]},"GameKeyword":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameFranchise":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameExternalGame":{"type":"object","properties":{"id":{"type":"number"},"uid":{"type":"string","description":"Corresponds to the game id on the target source (see GameExternalGameCategory).\nIt's called uid, not uuid."},"category":{"type":"number","enum":[1,5,10,11,13,14,15,20,22,23,26,28,29,30,31,32,36,37,54,55]},"media":{"type":"number","enum":[1,2]},"checksum":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"year":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"}},"required":["id","uid","createdAt","updatedAt","game","gameId"]},"GameInvolvedCompany":{"type":"object","properties":{"id":{"type":"number"},"checksum":{"type":"string"},"company":{"$ref":"#/components/schemas/GameCompany"},"companyId":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"developer":{"type":"boolean"},"porting":{"type":"boolean"},"publisher":{"type":"boolean"},"supporting":{"type":"boolean"},"updatedAt":{"format":"date-time","type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}},"required":["id","company","companyId","createdAt","developer","porting","publisher","supporting","updatedAt","games"]},"Game":{"type":"object","properties":{"id":{"type":"number","description":"Should be mapped to the IGDB ID of the game."},"name":{"type":"string"},"slug":{"type":"string"},"aggregatedRating":{"type":"number"},"aggregatedRatingCount":{"type":"number"},"category":{"enum":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14],"type":"number"},"status":{"enum":[0,2,3,4,5,6,7,8],"type":"number"},"summary":{"type":"string"},"storyline":{"type":"string"},"checksum":{"type":"string"},"url":{"type":"string"},"firstReleaseDate":{"format":"date-time","type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"dlcs":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"dlcOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expansions":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expansionOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expandedGames":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expandedGameOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"similarGames":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"similarGameOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remakes":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remakeOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remasters":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remasterOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"cover":{"$ref":"#/components/schemas/GameCover"},"collection":{"$ref":"#/components/schemas/GameCollection"},"alternativeNames":{"type":"array","items":{"$ref":"#/components/schemas/GameAlternativeName"}},"artworks":{"type":"array","items":{"$ref":"#/components/schemas/GameArtwork"}},"screenshots":{"type":"array","items":{"$ref":"#/components/schemas/GameScreenshot"}},"gameLocalizations":{"type":"array","items":{"$ref":"#/components/schemas/GameLocalization"}},"gameModes":{"type":"array","items":{"$ref":"#/components/schemas/GameMode"}},"genres":{"type":"array","items":{"$ref":"#/components/schemas/GameGenre"}},"themes":{"type":"array","items":{"$ref":"#/components/schemas/GameTheme"}},"playerPerspectives":{"type":"array","items":{"$ref":"#/components/schemas/GamePlayerPerspective"}},"gameEngines":{"type":"array","items":{"$ref":"#/components/schemas/GameEngine"}},"keywords":{"type":"array","items":{"$ref":"#/components/schemas/GameKeyword"}},"franchises":{"type":"array","items":{"$ref":"#/components/schemas/GameFranchise"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"externalGames":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}},"involvedCompanies":{"type":"array","items":{"$ref":"#/components/schemas/GameInvolvedCompany"}},"source":{"type":"string","description":"Oh dear maintainer, please forgive me for using transient fields.","default":"MYSQL","enum":["MYSQL","MANTICORE"]}},"required":["id","name","slug","category","status","summary","storyline","checksum","url","firstReleaseDate","createdAt","updatedAt","involvedCompanies","source"]},"ProfileAvatar":{"type":"object","properties":{"id":{"type":"number"},"mimetype":{"type":"string"},"extension":{"type":"string"},"size":{"type":"number"},"filename":{"type":"string"},"encoding":{"type":"string"},"profile":{"$ref":"#/components/schemas/Profile"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","mimetype","extension","size","filename","encoding","profile","createdAt","updatedAt"]},"Profile":{"type":"object","properties":{"userId":{"type":"string","description":"Shareable string ID\n\nSame as SuperTokens' userId."},"username":{"type":"string"},"bio":{"type":"string"},"avatar":{"$ref":"#/components/schemas/ProfileAvatar"},"usernameLastUpdatedAt":{"format":"date-time","type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["userId","username","bio","avatar","usernameLastUpdatedAt","createdAt","updatedAt"]},"Review":{"type":"object","properties":{"id":{"type":"string"},"content":{"type":"string","nullable":true},"rating":{"type":"number"},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"collectionEntry":{"$ref":"#/components/schemas/CollectionEntry"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","content","rating","game","gameId","profile","profileUserId","collectionEntry","createdAt","updatedAt"]},"CollectionEntry":{"type":"object","properties":{"id":{"type":"string"},"collections":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"ownedPlatforms":{"description":"The platforms on which the user owns the game.","type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"isFavorite":{"type":"boolean"},"finishedAt":{"format":"date-time","type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","collections","game","gameId","ownedPlatforms","review","isFavorite","finishedAt","createdAt","updatedAt"]},"Collection":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"isPublic":{"type":"boolean"},"library":{"$ref":"#/components/schemas/Library"},"libraryUserId":{"type":"string"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}},"isFeatured":{"type":"boolean"},"isFinished":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","name","description","isPublic","library","libraryUserId","entries","isFeatured","isFinished","createdAt","updatedAt"]},"CreateCollectionDto":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"isPublic":{"type":"boolean"},"isFeatured":{"type":"boolean"},"isFinished":{"type":"boolean"}},"required":["name","isPublic","isFeatured","isFinished"]},"UpdateCollectionDto":{"type":"object","properties":{}},"CreateReviewDto":{"type":"object","properties":{"gameId":{"type":"number"},"content":{"type":"string","minLength":20},"rating":{"type":"number","minimum":0,"maximum":5}},"required":["gameId","content","rating"]},"FindAllReviewsByIdDto":{"type":"object","properties":{"reviewsIds":{"type":"array","items":{"type":"string"}}},"required":["reviewsIds"]},"ReviewScoreDistribution":{"type":"object","properties":{"1":{"type":"number"},"2":{"type":"number"},"3":{"type":"number"},"4":{"type":"number"},"5":{"type":"number"},"total":{"type":"number","description":"Total number of reviews"}},"required":["1","2","3","4","5","total"]},"ReviewScoreResponseDto":{"type":"object","properties":{"median":{"type":"number"},"distribution":{"$ref":"#/components/schemas/ReviewScoreDistribution"}},"required":["median","distribution"]},"PaginationInfo":{"type":"object","properties":{"totalItems":{"type":"number","description":"Total number of items available for the current query"},"totalPages":{"type":"number","description":"Total number of pages available for the current query"},"hasNextPage":{"type":"boolean","description":"If this query allows for a next page"}},"required":["totalItems","totalPages","hasNextPage"]},"FindReviewPaginatedDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Review"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"UpdateProfileDto":{"type":"object","properties":{"username":{"type":"string","minLength":4,"maxLength":20},"avatar":{"type":"object"},"bio":{"type":"string","minLength":1,"maxLength":240}}},"UserFollow":{"type":"object","properties":{"id":{"type":"number"},"follower":{"$ref":"#/components/schemas/Profile"},"followerUserId":{"type":"string"},"followed":{"$ref":"#/components/schemas/Profile"},"followedUserId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","follower","followerUserId","followed","followedUserId","createdAt","updatedAt"]},"Activity":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["REVIEW","FOLLOW","COLLECTION_ENTRY"]},"profile":{"description":"The associated profile with this Activity (e.g. user who performed an action)","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string"},"collectionEntry":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CollectionEntry"}]},"collectionEntryId":{"type":"string","nullable":true},"collection":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Collection"}]},"collectionId":{"type":"string","nullable":true},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"reviewId":{"type":"string","nullable":true},"userFollow":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/UserFollow"}]},"userFollowId":{"type":"number","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","type","profile","profileUserId","collectionEntry","collectionEntryId","collection","collectionId","review","reviewId","userFollow","userFollowId","createdAt","updatedAt"]},"ActivitiesPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"StatisticsActionDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"targetUserId":{"type":"string","minLength":36},"sourceType":{"enum":["game","review","activity","review_comment"],"type":"string"}},"required":["sourceId","sourceType"]},"FindOneStatisticsDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"sourceType":{"type":"string","enum":["game","review","activity","review_comment"]}},"required":["sourceId","sourceType"]},"GameRepositoryFilterDto":{"type":"object","properties":{"ids":{"description":"If this is supplied, filtering will be done only for entities specified here.
\nUseful to filter data received from entities which hold game ids (like GameStatistics, Reviews, etc.)","type":"array","items":{"type":"number"}},"status":{"type":"number","enum":[0,2,3,4,5,6,7,8]},"category":{"type":"number","enum":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]},"themes":{"type":"array","items":{"type":"number"}},"gameModes":{"type":"array","items":{"type":"number"}},"platforms":{"type":"array","items":{"type":"number"}},"genres":{"type":"array","items":{"type":"number"}},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}}},"FindStatisticsTrendingGamesDto":{"type":"object","properties":{"criteria":{"$ref":"#/components/schemas/GameRepositoryFilterDto"},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"ActivityStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"activity":{"$ref":"#/components/schemas/Activity"},"activityId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","activity","activityId","id","viewsCount","likesCount"]},"ReviewComment":{"type":"object","properties":{"review":{"$ref":"#/components/schemas/Review"},"reviewId":{"type":"string"},"id":{"type":"string"},"content":{"type":"string","description":"HTML content of the user's comment."},"profile":{"description":"Author of this comment","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string","description":"User id of the author of this comment"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["review","reviewId","id","content","profile","profileUserId","createdAt","updatedAt"]},"CommentStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"reviewComment":{"$ref":"#/components/schemas/ReviewComment"},"reviewCommentId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","reviewComment","reviewCommentId","id","viewsCount","likesCount"]},"UserLike":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/GameStatistics"}]},"gameStatisticsId":{"type":"number","nullable":true},"reviewStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewStatistics"}]},"reviewStatisticsId":{"type":"number","nullable":true},"activityStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ActivityStatistics"}]},"activityStatisticsId":{"type":"number","nullable":true},"commentStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CommentStatistics"}]},"commentStatisticsId":{"type":"number","nullable":true}},"required":["id","profile","profileUserId","createdAt","updatedAt","gameStatistics","gameStatisticsId","reviewStatistics","reviewStatisticsId","activityStatistics","activityStatisticsId","commentStatistics","commentStatisticsId"]},"ReviewStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"review":{"$ref":"#/components/schemas/Review"},"reviewId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","review","reviewId","id","viewsCount","likesCount"]},"UserView":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/GameStatistics"}]},"reviewStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewStatistics"}]},"activityStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ActivityStatistics"}]},"commentStatistics":{"type":"object"}},"required":["id","profileUserId","createdAt","updatedAt","gameStatistics","reviewStatistics","activityStatistics","commentStatistics"]},"GameStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","game","gameId","id","viewsCount","likesCount"]},"GameStatisticsPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameStatistics"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindStatisticsTrendingReviewsDto":{"type":"object","properties":{"reviewId":{"type":"string","description":"Usually, this property should not be used unless a specific review needs to be retrieved, and it's easier to just\ncall the statistics controller."},"gameId":{"type":"number"},"userId":{"type":"string","minLength":36},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"ReviewStatisticsPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReviewStatistics"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindStatisticsTrendingActivitiesDto":{"type":"object","properties":{"activityId":{"type":"string","description":"Usually, this property should not be used unless a specific activity needs to be retrieved, and it's easier to just\ncall the statistics controller.","minLength":36},"userId":{"type":"string","minLength":36},"activityType":{"type":"string","enum":["REVIEW","FOLLOW","COLLECTION_ENTRY"]},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"StatisticsStatus":{"type":"object","properties":{"isLiked":{"type":"boolean"},"isViewed":{"type":"boolean"}},"required":["isLiked","isViewed"]},"ImporterWatchNotification":{"type":"object","properties":{"id":{"type":"number"},"library":{"$ref":"#/components/schemas/Library"},"libraryUserId":{"type":"string"},"source":{"type":"string","enum":["steam"]},"games":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}}},"required":["id","library","libraryUserId","source","games"]},"Notification":{"type":"object","properties":{"id":{"type":"number"},"sourceType":{"enum":["game","review","activity","profile","importer","report"],"type":"string"},"category":{"description":"What this notification's about. E.g.: a new like, a new follower, a game launch, etc.","enum":["follow","like","comment","watch","alert"],"type":"string"},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"reviewId":{"type":"string","nullable":true},"game":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Game"}]},"gameId":{"type":"number","nullable":true},"activity":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Activity"}]},"activityId":{"type":"string","nullable":true},"profile":{"nullable":true,"description":"User responsible for generating this notification (e.g. user that liked a review).","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string","nullable":true,"description":"User responsible for generating this notification (e.g. user that liked a review).\nWhen null/undefined, the notification was generated by the 'system'."},"importerNotification":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ImporterWatchNotification"}]},"importerNotificationId":{"type":"number"},"report":{"type":"object"},"reportId":{"type":"number","nullable":true},"isViewed":{"type":"boolean"},"targetProfile":{"nullable":true,"description":"User which is the target for this notification.
\nIf this is empty (null/undefined), the notification is targeted at all users.
\nNot to be confused with the 'profile' property.","allOf":[{"$ref":"#/components/schemas/Profile"}]},"targetProfileUserId":{"type":"string","nullable":true,"description":"User which is the target for this notification.
\nIf this is empty (null/undefined), the notification is targeted at all users.
\nNot to be confused with the 'profile' property."},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","sourceType","category","review","reviewId","game","gameId","activity","activityId","profile","profileUserId","importerNotification","importerNotificationId","report","reportId","isViewed","targetProfile","targetProfileUserId","createdAt","updatedAt"]},"NotificationAggregateDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"category":{"type":"string","enum":["follow","like","comment","watch","alert"]},"sourceType":{"type":"string","enum":["game","review","activity","profile","importer","report"]},"notifications":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}},"required":["sourceId","category","sourceType","notifications"]},"PaginatedNotificationAggregationDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NotificationAggregateDto"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"NotificationViewUpdateDto":{"type":"object","properties":{"isViewed":{"type":"boolean"},"notificationIds":{"type":"array","items":{"type":"number"}}},"required":["isViewed","notificationIds"]},"GameExternalStoreDto":{"type":"object","properties":{"icon":{"type":"string","nullable":true,"description":"Icon representing said store/service."},"storeName":{"type":"string","nullable":true},"id":{"type":"number"},"uid":{"type":"string","description":"Corresponds to the game id on the target source (see GameExternalGameCategory).\nIt's called uid, not uuid."},"category":{"type":"number","enum":[1,5,10,11,13,14,15,20,22,23,26,28,29,30,31,32,36,37,54,55]},"media":{"type":"number","enum":[1,2]},"checksum":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"year":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameId":{"type":"number"}},"required":["icon","storeName","id","uid","createdAt","updatedAt","gameId"]},"GameRepositoryFindOneDto":{"type":"object","properties":{"relations":{"type":"object"}}},"GameRepositoryFindAllDto":{"type":"object","properties":{"gameIds":{"type":"array","items":{"type":"number"}},"relations":{"type":"object"}},"required":["gameIds"]},"GamePlaytime":{"type":"object","properties":{"id":{"type":"number"},"gameId":{"type":"number"},"game":{"$ref":"#/components/schemas/Game"},"sourceId":{"type":"number"},"timeMain":{"type":"number","nullable":true},"timePlus":{"type":"number","nullable":true},"time100":{"type":"number","nullable":true},"timeAll":{"type":"number","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","gameId","game","sourceId","timeMain","timePlus","time100","timeAll","createdAt","updatedAt"]},"AchievementDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"expGainAmount":{"type":"number"},"category":{"type":"number","enum":[0,1,2,3]}},"required":["id","name","description","expGainAmount","category"]},"PaginatedAchievementsResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AchievementDto"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"ObtainedAchievement":{"type":"object","properties":{"id":{"type":"number"},"achievementId":{"type":"string","description":"Achievement id specified in entries for achievements.data.ts"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"isFeatured":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","achievementId","profile","profileUserId","isFeatured","createdAt","updatedAt"]},"UpdateFeaturedObtainedAchievementDto":{"type":"object","properties":{"isFeatured":{"type":"boolean"}},"required":["isFeatured"]},"UserLevel":{"type":"object","properties":{"userId":{"type":"string","description":"Should be the same as the profile's UserId"},"profile":{"$ref":"#/components/schemas/Profile"},"currentLevel":{"type":"number"},"currentLevelExp":{"type":"number","description":"XP in the current user-level"},"levelUpExpCost":{"type":"number","description":"Threshold XP to hit the next user-level"},"expMultiplier":{"type":"number","description":"The multiplier to apply to all exp gains"}},"required":["userId","profile","currentLevel","currentLevelExp","levelUpExpCost","expMultiplier"]},"CreateUpdateCollectionEntryDto":{"type":"object","properties":{"finishedAt":{"type":"date-time"},"collectionIds":{"type":"array","items":{"type":"string"}},"gameId":{"type":"number"},"platformIds":{"type":"array","items":{"type":"number"}},"isFavorite":{"type":"boolean","default":false}},"required":["collectionIds","gameId","platformIds","isFavorite"]},"CreateFavoriteStatusCollectionEntryDto":{"type":"object","properties":{"isFavorite":{"type":"boolean","default":false}},"required":["isFavorite"]},"CollectionEntriesPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindCollectionEntriesDto":{"type":"object","properties":{"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}}},"ActivitiesFeedPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FollowStatusDto":{"type":"object","properties":{"isFollowing":{"type":"boolean"}},"required":["isFollowing"]},"FollowInfoRequestDto":{"type":"object","properties":{"criteria":{"type":"string","enum":["followers","following"]},"targetUserId":{"type":"string","minLength":36},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}},"required":["criteria","targetUserId"]},"FollowInfoResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FollowRegisterDto":{"type":"object","properties":{"followedUserId":{"type":"string","minLength":36}},"required":["followedUserId"]},"FollowRemoveDto":{"type":"object","properties":{"followedUserId":{"type":"string","minLength":36}},"required":["followedUserId"]},"ImporterPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"ImporterStatusUpdateRequestDto":{"type":"object","properties":{"status":{"type":"string"},"externalGameId":{"type":"number"}},"required":["status","externalGameId"]},"FindAvailableConnectionsResponseDto":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["steam"]},"isImporterViable":{"type":"boolean"},"iconName":{"type":"string"}},"required":["name","type","isImporterViable","iconName"]},"UserConnection":{"type":"object","properties":{"id":{"type":"number"},"type":{"type":"string","enum":["steam"]},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"sourceUserId":{"type":"string"},"sourceUsername":{"type":"string"},"isImporterViable":{"type":"boolean","description":"If this connection can be used by the 'importer' system."},"isImporterEnabled":{"type":"boolean"}},"required":["id","type","profile","profileUserId","sourceUserId","sourceUsername","isImporterViable","isImporterEnabled"]},"ConnectionCreateDto":{"type":"object","properties":{"type":{"type":"string","enum":["steam"]},"userIdentifier":{"type":"string","description":"A string representing a username, user id or profile URL for the target connection
\ne.g. a Steam's profile URL","minLength":1},"isImporterEnabled":{"type":"boolean","default":false}},"required":["type","userIdentifier","isImporterEnabled"]},"FindAllCommentsDto":{"type":"object","properties":{"sourceId":{"type":"string","minLength":36},"sourceType":{"type":"string","enum":["review"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}},"required":["sourceId","sourceType"]},"FindCommentsPaginatedResponseDto":{"type":"object","properties":{"data":{"default":[],"type":"array","items":{"$ref":"#/components/schemas/ReviewComment"}},"pagination":{"default":{},"allOf":[{"$ref":"#/components/schemas/PaginationInfo"}]}},"required":["data","pagination"]},"CreateCommentDto":{"type":"object","properties":{"sourceId":{"type":"string","description":"UUID of the target entity. Comments can only be attributed to\nUUID based entities.","minLength":36},"sourceType":{"type":"string","enum":["review"]},"content":{"type":"string","minLength":1}},"required":["sourceId","sourceType","content"]},"UpdateCommentDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review"]},"content":{"type":"string","minLength":1}},"required":["sourceType","content"]},"DeleteCommentDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review"]}},"required":["sourceType"]},"Report":{"type":"object","properties":{"id":{"type":"number"},"sourceType":{"description":"Indexed to improve speed when filtering by type.","enum":["review","profile","review_comment"],"type":"string"},"category":{"enum":["spam","personal"],"type":"string"},"targetReview":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"targetReviewId":{"type":"string","nullable":true},"targetReviewComment":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewComment"}]},"targetReviewCommentId":{"type":"string","nullable":true},"targetProfile":{"description":"Profile that is being target of a report","allOf":[{"$ref":"#/components/schemas/Profile"}]},"targetProfileUserId":{"type":"string"},"reason":{"type":"string","nullable":true,"description":"User-submitted reason for report."},"profile":{"description":"User responsible for report.","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string"},"isClosed":{"type":"boolean"},"closeHandleAction":{"nullable":true,"description":"Action taken when closing this report","enum":["discard","alert","suspend","ban"],"type":"string"},"closeProfile":{"nullable":true,"description":"User responsible for closing this report","allOf":[{"$ref":"#/components/schemas/Profile"}]},"closeProfileUserId":{"type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","sourceType","category","targetReview","targetReviewId","targetReviewComment","targetReviewCommentId","targetProfile","targetProfileUserId","reason","profile","profileUserId","isClosed","closeHandleAction","closeProfile","closeProfileUserId","createdAt","updatedAt"]},"PaginatedReportResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Report"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"CreateReportRequestDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review","profile","review_comment"]},"sourceId":{"type":"string","minLength":36},"category":{"type":"string","enum":["spam","personal"]},"reason":{"type":"string"}},"required":["sourceType","sourceId","category"]},"HandleReportRequestDto":{"type":"object","properties":{"action":{"type":"string","enum":["discard","alert","suspend","ban"]},"deleteReportedContent":{"type":"boolean","default":true}},"required":["action","deleteReportedContent"]}}}} \ No newline at end of file diff --git a/src/report/dto/find-report-request.dto.ts b/src/report/dto/find-report-request.dto.ts index 858efa9..5aeb5f5 100644 --- a/src/report/dto/find-report-request.dto.ts +++ b/src/report/dto/find-report-request.dto.ts @@ -2,12 +2,16 @@ import { BaseFindDto } from "../../utils/base-find.dto"; import { OmitType } from "@nestjs/swagger"; import { Report } from "../entity/report.entity"; import { IsBoolean, IsOptional } from "class-validator"; +import { Transform, Type } from "class-transformer"; export class FindLatestReportRequestDto extends OmitType(BaseFindDto, [ "search", "orderBy", ]) { @IsOptional() - @IsBoolean() - includeClosed: boolean = false; + @Type(() => String) + @Transform(({ value }) => { + return value === "true"; + }) + includeClosed?: boolean = false; } diff --git a/src/report/report.controller.ts b/src/report/report.controller.ts index 820540f..0df4d60 100644 --- a/src/report/report.controller.ts +++ b/src/report/report.controller.ts @@ -5,6 +5,7 @@ import { Param, Post, Query, + Req, UseGuards, UseInterceptors, } from "@nestjs/common"; @@ -33,10 +34,7 @@ export class ReportController { @ApiOkResponse({ type: PaginatedReportResponseDto, }) - async findAllByLatest( - @Session() session: SessionContainer, - @Query() dto: FindLatestReportRequestDto, - ) { + async findAllByLatest(@Query() dto: FindLatestReportRequestDto) { return this.reportService.findAllByLatest(dto); } diff --git a/src/report/report.service.ts b/src/report/report.service.ts index 8050b6d..9eb298a 100644 --- a/src/report/report.service.ts +++ b/src/report/report.service.ts @@ -120,6 +120,13 @@ export class ReportService { const report = await this.findOneByIdOrFail(reportId); const { action, deleteReportedContent } = dto; + if (report.isClosed) { + throw new HttpException( + "Report is already closed. No further action needed.", + HttpStatus.BAD_REQUEST, + ); + } + // In case more user-generated content is added in the future, just add more checks here. const isContentDeletable = report.targetReviewId != undefined; switch (action) { From 72ff23029418efe2e5c6d943d37d719c031bc13d Mon Sep 17 00:00:00 2001 From: Lamarcke Date: Mon, 8 Jul 2024 00:07:13 -0300 Subject: [PATCH 2/7] - update htlb-sync isEligibleForUpdate logic --- src/sync/hltb/hltb-sync.service.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sync/hltb/hltb-sync.service.ts b/src/sync/hltb/hltb-sync.service.ts index 45447da..d2e5fa5 100644 --- a/src/sync/hltb/hltb-sync.service.ts +++ b/src/sync/hltb/hltb-sync.service.ts @@ -52,7 +52,17 @@ export class HltbSyncService { public async isEligibleForUpdate(gameId: number) { const playtime = await this.findOneByGameId(gameId); const failedAttempt = await this.hasFailedAttempt(gameId); - return playtime != undefined || !failedAttempt; + + if (!playtime) { + return !failedAttempt; + } + + const now = new Date().getTime(); + + // How many MS since last update + const dateDifference = now - playtime.updatedAt.getTime(); + + return dateDifference > MINIMUM_UPDATE_INTERVAL_MS; } public async save(entity: DeepPartial) { From df242aca314935ab51a6407bf881ed2b5bd52a06 Mon Sep 17 00:00:00 2001 From: Lamarcke Date: Mon, 8 Jul 2024 00:36:51 -0300 Subject: [PATCH 3/7] - start of work on profile-statistics module --- server_swagger.json | 2 +- src/app.module.ts | 6 +- .../collections-entries.service.ts | 1 + .../entities/collection-entry.entity.ts | 3 +- src/collections/collections.service.ts | 2 +- .../game-repository/entities/game.entity.ts | 3 +- ...ile-statistics-distribution-request.dto.ts | 26 +++++ .../dto/profile-statistics-overview.dto.ts | 9 ++ .../profile-statistics.controller.ts | 37 +++++++ .../profile-statistics.module.ts | 18 ++++ .../profile-statistics.service.ts | 96 +++++++++++++++++++ src/statistics/statistics.module.ts | 1 + src/sync/hltb/hltb-sync.module.ts | 2 +- src/sync/hltb/hltb-sync.processor.ts | 3 +- src/sync/hltb/hltb-sync.service.ts | 10 +- 15 files changed, 209 insertions(+), 10 deletions(-) create mode 100644 src/statistics/profile-statistics/dto/profile-statistics-distribution-request.dto.ts create mode 100644 src/statistics/profile-statistics/dto/profile-statistics-overview.dto.ts create mode 100644 src/statistics/profile-statistics/profile-statistics.controller.ts create mode 100644 src/statistics/profile-statistics/profile-statistics.module.ts create mode 100644 src/statistics/profile-statistics/profile-statistics.service.ts diff --git a/server_swagger.json b/server_swagger.json index 7f10c5a..f20729a 100644 --- a/server_swagger.json +++ b/server_swagger.json @@ -1 +1 @@ -{"openapi":"3.0.0","paths":{"/v1/auth/logout":{"get":{"operationId":"AuthController_logout","parameters":[],"responses":{"200":{"description":""}},"tags":["auth"]}},"/v1/libraries":{"get":{"operationId":"LibrariesController_findOwn","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Library"}}}}},"tags":["libraries"]}},"/v1/libraries/{id}":{"get":{"operationId":"LibrariesController_findOneByIdWithPermissions","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Library"}}}}},"tags":["libraries"]}},"/v1/collections/{id}":{"get":{"operationId":"CollectionsController_findOneByIdWithPermissions","summary":"","description":"Returns a collection which the user has access to\n\n(Either its own collection or a public one)","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Collection"}}}}},"tags":["collections"]},"patch":{"operationId":"CollectionsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCollectionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["collections"]},"delete":{"operationId":"CollectionsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["collections"]}},"/v1/collections/library/{userId}":{"get":{"operationId":"CollectionsController_findAllByUserIdWithPermissions","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}}}}}},"tags":["collections"]}},"/v1/collections":{"post":{"operationId":"CollectionsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCollectionDto"}}}},"responses":{"201":{"description":""}},"tags":["collections"]}},"/v1/reviews":{"post":{"operationId":"ReviewsController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviewDto"}}}},"responses":{"201":{"description":""}},"tags":["reviews"]},"get":{"operationId":"ReviewsController_findOneByUserIdAndGameId","parameters":[{"name":"id","required":true,"in":"query","schema":{"type":"string"}},{"name":"gameId","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}}},"tags":["reviews"]}},"/v1/reviews/all":{"post":{"operationId":"ReviewsController_findAllById","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllReviewsByIdDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Review"}}}}}},"tags":["reviews"]}},"/v1/reviews/score":{"get":{"operationId":"ReviewsController_getScoreForGameId","parameters":[{"name":"gameId","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewScoreResponseDto"}}}}},"tags":["reviews"]}},"/v1/reviews/profile/{userId}":{"get":{"operationId":"ReviewsController_findAllByUserId","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindReviewPaginatedDto"}}}}},"tags":["reviews"]}},"/v1/reviews/game/{id}":{"get":{"operationId":"ReviewsController_findAllByGameId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindReviewPaginatedDto"}}}}},"tags":["reviews"]}},"/v1/reviews/{id}":{"get":{"operationId":"ReviewsController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}}},"tags":["reviews"]},"delete":{"operationId":"ReviewsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reviews"]}},"/v1/profile":{"patch":{"operationId":"ProfileController_update","parameters":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UpdateProfileDto"}}}},"responses":{"200":{"description":""}},"tags":["profile"]},"get":{"operationId":"ProfileController_findOwn","summary":"","description":"Used to access own profile","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}}},"tags":["profile"]}},"/v1/profile/{id}":{"get":{"operationId":"ProfileController_findOneById","summary":"","description":"Used to access other users' profiles","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}}},"tags":["profile"]}},"/v1/activities":{"get":{"operationId":"ActivitiesRepositoryController_findLatest","parameters":[{"name":"userId","required":false,"in":"query","schema":{"minLength":36,"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesPaginatedResponseDto"}}}}},"tags":["activities"]}},"/v1/statistics/queue/like":{"post":{"operationId":"StatisticsQueueController_addLike","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"201":{"description":""}},"tags":["statistics-queue"]},"delete":{"operationId":"StatisticsQueueController_removeLike","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"200":{"description":""}},"tags":["statistics-queue"]}},"/v1/statistics/queue/view":{"post":{"operationId":"StatisticsQueueController_addView","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"201":{"description":""}},"tags":["statistics-queue"]}},"/v1/statistics":{"post":{"operationId":"StatisticsController_findOneBySourceIdAndType","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindOneStatisticsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/games":{"post":{"operationId":"StatisticsController_findTrendingGames","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingGamesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/reviews":{"post":{"operationId":"StatisticsController_findTrendingReviews","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingReviewsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/activities":{"post":{"operationId":"StatisticsController_findTrendingActivities","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingActivitiesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/status":{"get":{"operationId":"StatisticsController_getStatus","parameters":[{"name":"statisticsId","required":true,"in":"query","schema":{"type":"number"}},{"name":"sourceType","required":true,"in":"query","schema":{"enum":["game","review","activity","review_comment"],"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsStatus"}}}}},"tags":["statistics"]}},"/v1/notifications":{"get":{"operationId":"NotificationsController_findAllAndAggregate","parameters":[{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedNotificationAggregationDto"}}}}},"tags":["notifications"]}},"/v1/notifications/new":{"get":{"operationId":"NotificationsController_getNewNotifications","summary":"","description":"Finds new notifications that have been created after last checked time.
\nReturns an empty array on first connection.","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}}}}},"tags":["notifications"]}},"/v1/notifications/view":{"put":{"operationId":"NotificationsController_updateViewedStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationViewUpdateDto"}}}},"responses":{"200":{"description":""}},"tags":["notifications"]}},"/v1/game/repository/resource":{"get":{"operationId":"GameRepositoryController_getResource","parameters":[{"name":"resourceName","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}/platforms/icon":{"get":{"operationId":"GameRepositoryController_getIconNamesForPlatformAbbreviations","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}/external-stores":{"get":{"operationId":"GameRepositoryController_getExternalStoresForGameId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalStoreDto"}}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}":{"post":{"operationId":"GameRepositoryController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameRepositoryFindOneDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Game"}}}}},"tags":["game-repository"]}},"/v1/game/repository":{"post":{"operationId":"GameRepositoryController_findAllByIds","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameRepositoryFindAllDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}}}}},"tags":["game-repository"]}},"/v1/sync/hltb/{gameId}":{"get":{"operationId":"HltbController_findPlaytimeForGameId","parameters":[{"name":"gameId","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GamePlaytime"}}}}},"tags":["sync-hltb"]}},"/v1/achievements":{"get":{"operationId":"AchievementsController_getAchievements","parameters":[{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAchievementsResponseDto"}}}}},"tags":["achievements"]}},"/v1/achievements/obtained/{id}":{"get":{"operationId":"AchievementsController_getObtainedAchievement","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"targetUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObtainedAchievement"}}}}},"tags":["achievements"]}},"/v1/achievements/obtained":{"get":{"operationId":"AchievementsController_getAllObtainedAchievements","parameters":[{"name":"targetUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ObtainedAchievement"}}}}}},"tags":["achievements"]}},"/v1/achievements/obtained/{id}/featured":{"put":{"operationId":"AchievementsController_updateFeaturedObtainedAchievement","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFeaturedObtainedAchievementDto"}}}},"responses":{"200":{"description":""}},"tags":["achievements"]}},"/v1/level/{userId}":{"get":{"operationId":"LevelController_findOne","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLevel"}}}}},"tags":["level"]}},"/v1/collections-entries":{"post":{"operationId":"CollectionsEntriesController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateCollectionEntryDto"}}}},"responses":{"201":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/{id}":{"get":{"operationId":"CollectionsEntriesController_findEntryById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntry"}}}}},"tags":["collections-entries"]},"delete":{"operationId":"CollectionsEntriesController_deleteOwnEntry","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/game/{id}":{"get":{"operationId":"CollectionsEntriesController_findOwnEntryByGameId","summary":"","description":"Returns a specific collection entry based on game ID","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntry"}}}},"400":{"description":"Invalid query"}},"tags":["collections-entries"]}},"/v1/collections-entries/{id}/platforms/icons":{"get":{"operationId":"CollectionsEntriesController_getIconsForOwnedPlatforms","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/game/{id}/favorite":{"post":{"operationId":"CollectionsEntriesController_changeFavoriteStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFavoriteStatusCollectionEntryDto"}}}},"responses":{"204":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/library/{id}":{"get":{"operationId":"CollectionsEntriesController_findAllByLibraryId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/library/{id}/favorites":{"get":{"operationId":"CollectionsEntriesController_findFavoritesByLibraryId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/collection/{id}":{"post":{"operationId":"CollectionsEntriesController_findAllByCollectionId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindCollectionEntriesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/health":{"get":{"operationId":"HealthController_health","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["health"]}},"/v1/activities/feed":{"get":{"operationId":"ActivitiesFeedController_buildActivitiesFeed","parameters":[{"name":"criteria","required":true,"in":"query","schema":{"enum":["following","all"],"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesFeedPaginatedResponseDto"}}}}},"tags":["activities-feed"]}},"/v1/follow/status":{"get":{"operationId":"FollowController_getFollowerStatus","parameters":[{"name":"followerUserId","required":true,"in":"query","schema":{"type":"string"}},{"name":"followedUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowStatusDto"}}}}},"tags":["follow"]}},"/v1/follow/{id}":{"get":{"operationId":"FollowController_getUserFollowById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserFollow"}}}}},"tags":["follow"]}},"/v1/follow/info":{"post":{"operationId":"FollowController_getFollowInfo","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowInfoRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowInfoResponseDto"}}}}},"tags":["follow"]}},"/v1/follow":{"post":{"operationId":"FollowController_registerFollow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRegisterDto"}}}},"responses":{"201":{"description":""}},"tags":["follow"]},"delete":{"operationId":"FollowController_removeFollow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRemoveDto"}}}},"responses":{"200":{"description":""}},"tags":["follow"]}},"/v1/importer/watch/notification/{id}":{"get":{"operationId":"ImporterWatchController_findNotification","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterWatchNotification"}}}}},"tags":["importer-watch"]}},"/v1/importer/{source}":{"get":{"operationId":"ImporterController_findUnprocessedEntries","parameters":[{"name":"source","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterPaginatedResponseDto"}}}}},"tags":["importer"]}},"/v1/importer/status":{"post":{"operationId":"ImporterController_changeStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterStatusUpdateRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["importer"]}},"/v1/connections":{"get":{"operationId":"ConnectionsController_findAvailableConnections","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FindAvailableConnectionsResponseDto"}}}}}},"tags":["connections"]},"post":{"operationId":"ConnectionsController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionCreateDto"}}}},"responses":{"201":{"description":""}},"tags":["connections"]}},"/v1/connections/own":{"get":{"operationId":"ConnectionsController_findOwn","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserConnection"}}}}}},"tags":["connections"]}},"/v1/connections/own/{type}":{"get":{"operationId":"ConnectionsController_findOwnByType","parameters":[{"name":"type","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserConnection"}}}}},"tags":["connections"]}},"/v1/connections/{id}":{"delete":{"operationId":"ConnectionsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["connections"]}},"/v1/comment":{"post":{"operationId":"CommentController_findAll","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllCommentsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindCommentsPaginatedResponseDto"}}}}},"tags":["comment"]}},"/v1/comment/{sourceType}/{id}":{"get":{"operationId":"CommentController_findOneById","parameters":[{"name":"sourceType","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewComment"}}}}},"tags":["comment"]}},"/v1/comment/create":{"post":{"operationId":"CommentController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentDto"}}}},"responses":{"201":{"description":""}},"tags":["comment"]}},"/v1/comment/{id}":{"patch":{"operationId":"CommentController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCommentDto"}}}},"responses":{"204":{"description":""}},"tags":["comment"]},"delete":{"operationId":"CommentController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteCommentDto"}}}},"responses":{"200":{"description":""}},"tags":["comment"]}},"/v1/report":{"get":{"operationId":"ReportController_findAllByLatest","parameters":[{"name":"includeClosed","required":false,"in":"query","schema":{"default":false,"type":"boolean"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedReportResponseDto"}}}}},"tags":["report"]},"post":{"operationId":"ReportController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["report"]}},"/v1/report/{id}":{"get":{"operationId":"ReportController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}}}},"tags":["report"]}},"/v1/report/{id}/handle":{"post":{"operationId":"ReportController_handle","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandleReportRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["report"]}}},"info":{"title":"GameNode API","description":"API docs for the videogame catalog system GameNode.

Built with love by the GameNode team.","version":"1.0","contact":{}},"tags":[],"servers":[],"components":{"schemas":{"Library":{"type":"object","properties":{"userId":{"type":"string","description":"@description The primary key of the library entity.\nAlso used to share the library with other users.\n\nSame as SuperTokens' userId."},"collections":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["userId","collections","createdAt","updatedAt"]},"GameCover":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameCollection":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"checksum":{"type":"string"},"url":{"type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}},"required":["id","name","slug","createdAt","updatedAt","checksum","url","games"]},"GameAlternativeName":{"type":"object","properties":{"id":{"type":"number"},"comment":{"type":"string"},"name":{"type":"string"},"checksum":{"type":"string"},"game":{"$ref":"#/components/schemas/Game"}},"required":["id","game"]},"GameArtwork":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameScreenshot":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameLocalization":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameMode":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameGenre":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameTheme":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","createdAt","updatedAt"]},"GamePlayerPerspective":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameEngineLogo":{"type":"object","properties":{"engine":{"$ref":"#/components/schemas/GameEngine"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["engine","id"]},"GameCompanyLogo":{"type":"object","properties":{"company":{"$ref":"#/components/schemas/GameCompany"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["company","id"]},"GameCompany":{"type":"object","properties":{"id":{"type":"number"},"changeDate":{"format":"date-time","type":"string"},"changeDateCategory":{"type":"string"},"changedCompany":{"$ref":"#/components/schemas/GameCompany"},"checksum":{"type":"string"},"country":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"description":{"type":"string"},"logo":{"$ref":"#/components/schemas/GameCompanyLogo"},"name":{"type":"string"},"parent":{"$ref":"#/components/schemas/GameCompany"},"slug":{"type":"string"},"startDate":{"format":"date-time","type":"string"},"startDateCategory":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"url":{"type":"string"}},"required":["id","createdAt","name","slug","updatedAt"]},"GamePlatform":{"type":"object","properties":{"id":{"type":"number"},"abbreviation":{"type":"string"},"alternative_name":{"type":"string"},"category":{"type":"number","enum":[1,2,3,4,5,6]},"checksum":{"type":"string"},"generation":{"type":"number"},"name":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"collectionEntries":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}}},"required":["id","abbreviation","alternative_name","category","checksum","generation","name","createdAt","updatedAt","games","collectionEntries"]},"GameEngine":{"type":"object","properties":{"logo":{"$ref":"#/components/schemas/GameEngineLogo"},"companies":{"type":"array","items":{"$ref":"#/components/schemas/GameCompany"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["logo","companies","platforms","games","id","createdAt","updatedAt"]},"GameKeyword":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameFranchise":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameExternalGame":{"type":"object","properties":{"id":{"type":"number"},"uid":{"type":"string","description":"Corresponds to the game id on the target source (see GameExternalGameCategory).\nIt's called uid, not uuid."},"category":{"type":"number","enum":[1,5,10,11,13,14,15,20,22,23,26,28,29,30,31,32,36,37,54,55]},"media":{"type":"number","enum":[1,2]},"checksum":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"year":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"}},"required":["id","uid","createdAt","updatedAt","game","gameId"]},"GameInvolvedCompany":{"type":"object","properties":{"id":{"type":"number"},"checksum":{"type":"string"},"company":{"$ref":"#/components/schemas/GameCompany"},"companyId":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"developer":{"type":"boolean"},"porting":{"type":"boolean"},"publisher":{"type":"boolean"},"supporting":{"type":"boolean"},"updatedAt":{"format":"date-time","type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}},"required":["id","company","companyId","createdAt","developer","porting","publisher","supporting","updatedAt","games"]},"Game":{"type":"object","properties":{"id":{"type":"number","description":"Should be mapped to the IGDB ID of the game."},"name":{"type":"string"},"slug":{"type":"string"},"aggregatedRating":{"type":"number"},"aggregatedRatingCount":{"type":"number"},"category":{"enum":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14],"type":"number"},"status":{"enum":[0,2,3,4,5,6,7,8],"type":"number"},"summary":{"type":"string"},"storyline":{"type":"string"},"checksum":{"type":"string"},"url":{"type":"string"},"firstReleaseDate":{"format":"date-time","type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"dlcs":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"dlcOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expansions":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expansionOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expandedGames":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expandedGameOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"similarGames":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"similarGameOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remakes":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remakeOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remasters":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remasterOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"cover":{"$ref":"#/components/schemas/GameCover"},"collection":{"$ref":"#/components/schemas/GameCollection"},"alternativeNames":{"type":"array","items":{"$ref":"#/components/schemas/GameAlternativeName"}},"artworks":{"type":"array","items":{"$ref":"#/components/schemas/GameArtwork"}},"screenshots":{"type":"array","items":{"$ref":"#/components/schemas/GameScreenshot"}},"gameLocalizations":{"type":"array","items":{"$ref":"#/components/schemas/GameLocalization"}},"gameModes":{"type":"array","items":{"$ref":"#/components/schemas/GameMode"}},"genres":{"type":"array","items":{"$ref":"#/components/schemas/GameGenre"}},"themes":{"type":"array","items":{"$ref":"#/components/schemas/GameTheme"}},"playerPerspectives":{"type":"array","items":{"$ref":"#/components/schemas/GamePlayerPerspective"}},"gameEngines":{"type":"array","items":{"$ref":"#/components/schemas/GameEngine"}},"keywords":{"type":"array","items":{"$ref":"#/components/schemas/GameKeyword"}},"franchises":{"type":"array","items":{"$ref":"#/components/schemas/GameFranchise"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"externalGames":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}},"involvedCompanies":{"type":"array","items":{"$ref":"#/components/schemas/GameInvolvedCompany"}},"source":{"type":"string","description":"Oh dear maintainer, please forgive me for using transient fields.","default":"MYSQL","enum":["MYSQL","MANTICORE"]}},"required":["id","name","slug","category","status","summary","storyline","checksum","url","firstReleaseDate","createdAt","updatedAt","involvedCompanies","source"]},"ProfileAvatar":{"type":"object","properties":{"id":{"type":"number"},"mimetype":{"type":"string"},"extension":{"type":"string"},"size":{"type":"number"},"filename":{"type":"string"},"encoding":{"type":"string"},"profile":{"$ref":"#/components/schemas/Profile"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","mimetype","extension","size","filename","encoding","profile","createdAt","updatedAt"]},"Profile":{"type":"object","properties":{"userId":{"type":"string","description":"Shareable string ID\n\nSame as SuperTokens' userId."},"username":{"type":"string"},"bio":{"type":"string"},"avatar":{"$ref":"#/components/schemas/ProfileAvatar"},"usernameLastUpdatedAt":{"format":"date-time","type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["userId","username","bio","avatar","usernameLastUpdatedAt","createdAt","updatedAt"]},"Review":{"type":"object","properties":{"id":{"type":"string"},"content":{"type":"string","nullable":true},"rating":{"type":"number"},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"collectionEntry":{"$ref":"#/components/schemas/CollectionEntry"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","content","rating","game","gameId","profile","profileUserId","collectionEntry","createdAt","updatedAt"]},"CollectionEntry":{"type":"object","properties":{"id":{"type":"string"},"collections":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"ownedPlatforms":{"description":"The platforms on which the user owns the game.","type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"isFavorite":{"type":"boolean"},"finishedAt":{"format":"date-time","type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","collections","game","gameId","ownedPlatforms","review","isFavorite","finishedAt","createdAt","updatedAt"]},"Collection":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"isPublic":{"type":"boolean"},"library":{"$ref":"#/components/schemas/Library"},"libraryUserId":{"type":"string"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}},"isFeatured":{"type":"boolean"},"isFinished":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","name","description","isPublic","library","libraryUserId","entries","isFeatured","isFinished","createdAt","updatedAt"]},"CreateCollectionDto":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"isPublic":{"type":"boolean"},"isFeatured":{"type":"boolean"},"isFinished":{"type":"boolean"}},"required":["name","isPublic","isFeatured","isFinished"]},"UpdateCollectionDto":{"type":"object","properties":{}},"CreateReviewDto":{"type":"object","properties":{"gameId":{"type":"number"},"content":{"type":"string","minLength":20},"rating":{"type":"number","minimum":0,"maximum":5}},"required":["gameId","content","rating"]},"FindAllReviewsByIdDto":{"type":"object","properties":{"reviewsIds":{"type":"array","items":{"type":"string"}}},"required":["reviewsIds"]},"ReviewScoreDistribution":{"type":"object","properties":{"1":{"type":"number"},"2":{"type":"number"},"3":{"type":"number"},"4":{"type":"number"},"5":{"type":"number"},"total":{"type":"number","description":"Total number of reviews"}},"required":["1","2","3","4","5","total"]},"ReviewScoreResponseDto":{"type":"object","properties":{"median":{"type":"number"},"distribution":{"$ref":"#/components/schemas/ReviewScoreDistribution"}},"required":["median","distribution"]},"PaginationInfo":{"type":"object","properties":{"totalItems":{"type":"number","description":"Total number of items available for the current query"},"totalPages":{"type":"number","description":"Total number of pages available for the current query"},"hasNextPage":{"type":"boolean","description":"If this query allows for a next page"}},"required":["totalItems","totalPages","hasNextPage"]},"FindReviewPaginatedDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Review"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"UpdateProfileDto":{"type":"object","properties":{"username":{"type":"string","minLength":4,"maxLength":20},"avatar":{"type":"object"},"bio":{"type":"string","minLength":1,"maxLength":240}}},"UserFollow":{"type":"object","properties":{"id":{"type":"number"},"follower":{"$ref":"#/components/schemas/Profile"},"followerUserId":{"type":"string"},"followed":{"$ref":"#/components/schemas/Profile"},"followedUserId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","follower","followerUserId","followed","followedUserId","createdAt","updatedAt"]},"Activity":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["REVIEW","FOLLOW","COLLECTION_ENTRY"]},"profile":{"description":"The associated profile with this Activity (e.g. user who performed an action)","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string"},"collectionEntry":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CollectionEntry"}]},"collectionEntryId":{"type":"string","nullable":true},"collection":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Collection"}]},"collectionId":{"type":"string","nullable":true},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"reviewId":{"type":"string","nullable":true},"userFollow":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/UserFollow"}]},"userFollowId":{"type":"number","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","type","profile","profileUserId","collectionEntry","collectionEntryId","collection","collectionId","review","reviewId","userFollow","userFollowId","createdAt","updatedAt"]},"ActivitiesPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"StatisticsActionDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"targetUserId":{"type":"string","minLength":36},"sourceType":{"enum":["game","review","activity","review_comment"],"type":"string"}},"required":["sourceId","sourceType"]},"FindOneStatisticsDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"sourceType":{"type":"string","enum":["game","review","activity","review_comment"]}},"required":["sourceId","sourceType"]},"GameRepositoryFilterDto":{"type":"object","properties":{"ids":{"description":"If this is supplied, filtering will be done only for entities specified here.
\nUseful to filter data received from entities which hold game ids (like GameStatistics, Reviews, etc.)","type":"array","items":{"type":"number"}},"status":{"type":"number","enum":[0,2,3,4,5,6,7,8]},"category":{"type":"number","enum":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]},"themes":{"type":"array","items":{"type":"number"}},"gameModes":{"type":"array","items":{"type":"number"}},"platforms":{"type":"array","items":{"type":"number"}},"genres":{"type":"array","items":{"type":"number"}},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}}},"FindStatisticsTrendingGamesDto":{"type":"object","properties":{"criteria":{"$ref":"#/components/schemas/GameRepositoryFilterDto"},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"ActivityStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"activity":{"$ref":"#/components/schemas/Activity"},"activityId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","activity","activityId","id","viewsCount","likesCount"]},"ReviewComment":{"type":"object","properties":{"review":{"$ref":"#/components/schemas/Review"},"reviewId":{"type":"string"},"id":{"type":"string"},"content":{"type":"string","description":"HTML content of the user's comment."},"profile":{"description":"Author of this comment","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string","description":"User id of the author of this comment"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["review","reviewId","id","content","profile","profileUserId","createdAt","updatedAt"]},"CommentStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"reviewComment":{"$ref":"#/components/schemas/ReviewComment"},"reviewCommentId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","reviewComment","reviewCommentId","id","viewsCount","likesCount"]},"UserLike":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/GameStatistics"}]},"gameStatisticsId":{"type":"number","nullable":true},"reviewStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewStatistics"}]},"reviewStatisticsId":{"type":"number","nullable":true},"activityStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ActivityStatistics"}]},"activityStatisticsId":{"type":"number","nullable":true},"commentStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CommentStatistics"}]},"commentStatisticsId":{"type":"number","nullable":true}},"required":["id","profile","profileUserId","createdAt","updatedAt","gameStatistics","gameStatisticsId","reviewStatistics","reviewStatisticsId","activityStatistics","activityStatisticsId","commentStatistics","commentStatisticsId"]},"ReviewStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"review":{"$ref":"#/components/schemas/Review"},"reviewId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","review","reviewId","id","viewsCount","likesCount"]},"UserView":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/GameStatistics"}]},"reviewStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewStatistics"}]},"activityStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ActivityStatistics"}]},"commentStatistics":{"type":"object"}},"required":["id","profileUserId","createdAt","updatedAt","gameStatistics","reviewStatistics","activityStatistics","commentStatistics"]},"GameStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","game","gameId","id","viewsCount","likesCount"]},"GameStatisticsPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameStatistics"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindStatisticsTrendingReviewsDto":{"type":"object","properties":{"reviewId":{"type":"string","description":"Usually, this property should not be used unless a specific review needs to be retrieved, and it's easier to just\ncall the statistics controller."},"gameId":{"type":"number"},"userId":{"type":"string","minLength":36},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"ReviewStatisticsPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReviewStatistics"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindStatisticsTrendingActivitiesDto":{"type":"object","properties":{"activityId":{"type":"string","description":"Usually, this property should not be used unless a specific activity needs to be retrieved, and it's easier to just\ncall the statistics controller.","minLength":36},"userId":{"type":"string","minLength":36},"activityType":{"type":"string","enum":["REVIEW","FOLLOW","COLLECTION_ENTRY"]},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"StatisticsStatus":{"type":"object","properties":{"isLiked":{"type":"boolean"},"isViewed":{"type":"boolean"}},"required":["isLiked","isViewed"]},"ImporterWatchNotification":{"type":"object","properties":{"id":{"type":"number"},"library":{"$ref":"#/components/schemas/Library"},"libraryUserId":{"type":"string"},"source":{"type":"string","enum":["steam"]},"games":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}}},"required":["id","library","libraryUserId","source","games"]},"Notification":{"type":"object","properties":{"id":{"type":"number"},"sourceType":{"enum":["game","review","activity","profile","importer","report"],"type":"string"},"category":{"description":"What this notification's about. E.g.: a new like, a new follower, a game launch, etc.","enum":["follow","like","comment","watch","alert"],"type":"string"},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"reviewId":{"type":"string","nullable":true},"game":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Game"}]},"gameId":{"type":"number","nullable":true},"activity":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Activity"}]},"activityId":{"type":"string","nullable":true},"profile":{"nullable":true,"description":"User responsible for generating this notification (e.g. user that liked a review).","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string","nullable":true,"description":"User responsible for generating this notification (e.g. user that liked a review).\nWhen null/undefined, the notification was generated by the 'system'."},"importerNotification":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ImporterWatchNotification"}]},"importerNotificationId":{"type":"number"},"report":{"type":"object"},"reportId":{"type":"number","nullable":true},"isViewed":{"type":"boolean"},"targetProfile":{"nullable":true,"description":"User which is the target for this notification.
\nIf this is empty (null/undefined), the notification is targeted at all users.
\nNot to be confused with the 'profile' property.","allOf":[{"$ref":"#/components/schemas/Profile"}]},"targetProfileUserId":{"type":"string","nullable":true,"description":"User which is the target for this notification.
\nIf this is empty (null/undefined), the notification is targeted at all users.
\nNot to be confused with the 'profile' property."},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","sourceType","category","review","reviewId","game","gameId","activity","activityId","profile","profileUserId","importerNotification","importerNotificationId","report","reportId","isViewed","targetProfile","targetProfileUserId","createdAt","updatedAt"]},"NotificationAggregateDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"category":{"type":"string","enum":["follow","like","comment","watch","alert"]},"sourceType":{"type":"string","enum":["game","review","activity","profile","importer","report"]},"notifications":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}},"required":["sourceId","category","sourceType","notifications"]},"PaginatedNotificationAggregationDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NotificationAggregateDto"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"NotificationViewUpdateDto":{"type":"object","properties":{"isViewed":{"type":"boolean"},"notificationIds":{"type":"array","items":{"type":"number"}}},"required":["isViewed","notificationIds"]},"GameExternalStoreDto":{"type":"object","properties":{"icon":{"type":"string","nullable":true,"description":"Icon representing said store/service."},"storeName":{"type":"string","nullable":true},"id":{"type":"number"},"uid":{"type":"string","description":"Corresponds to the game id on the target source (see GameExternalGameCategory).\nIt's called uid, not uuid."},"category":{"type":"number","enum":[1,5,10,11,13,14,15,20,22,23,26,28,29,30,31,32,36,37,54,55]},"media":{"type":"number","enum":[1,2]},"checksum":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"year":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameId":{"type":"number"}},"required":["icon","storeName","id","uid","createdAt","updatedAt","gameId"]},"GameRepositoryFindOneDto":{"type":"object","properties":{"relations":{"type":"object"}}},"GameRepositoryFindAllDto":{"type":"object","properties":{"gameIds":{"type":"array","items":{"type":"number"}},"relations":{"type":"object"}},"required":["gameIds"]},"GamePlaytime":{"type":"object","properties":{"id":{"type":"number"},"gameId":{"type":"number"},"game":{"$ref":"#/components/schemas/Game"},"sourceId":{"type":"number"},"timeMain":{"type":"number","nullable":true},"timePlus":{"type":"number","nullable":true},"time100":{"type":"number","nullable":true},"timeAll":{"type":"number","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","gameId","game","sourceId","timeMain","timePlus","time100","timeAll","createdAt","updatedAt"]},"AchievementDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"expGainAmount":{"type":"number"},"category":{"type":"number","enum":[0,1,2,3]}},"required":["id","name","description","expGainAmount","category"]},"PaginatedAchievementsResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AchievementDto"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"ObtainedAchievement":{"type":"object","properties":{"id":{"type":"number"},"achievementId":{"type":"string","description":"Achievement id specified in entries for achievements.data.ts"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"isFeatured":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","achievementId","profile","profileUserId","isFeatured","createdAt","updatedAt"]},"UpdateFeaturedObtainedAchievementDto":{"type":"object","properties":{"isFeatured":{"type":"boolean"}},"required":["isFeatured"]},"UserLevel":{"type":"object","properties":{"userId":{"type":"string","description":"Should be the same as the profile's UserId"},"profile":{"$ref":"#/components/schemas/Profile"},"currentLevel":{"type":"number"},"currentLevelExp":{"type":"number","description":"XP in the current user-level"},"levelUpExpCost":{"type":"number","description":"Threshold XP to hit the next user-level"},"expMultiplier":{"type":"number","description":"The multiplier to apply to all exp gains"}},"required":["userId","profile","currentLevel","currentLevelExp","levelUpExpCost","expMultiplier"]},"CreateUpdateCollectionEntryDto":{"type":"object","properties":{"finishedAt":{"type":"date-time"},"collectionIds":{"type":"array","items":{"type":"string"}},"gameId":{"type":"number"},"platformIds":{"type":"array","items":{"type":"number"}},"isFavorite":{"type":"boolean","default":false}},"required":["collectionIds","gameId","platformIds","isFavorite"]},"CreateFavoriteStatusCollectionEntryDto":{"type":"object","properties":{"isFavorite":{"type":"boolean","default":false}},"required":["isFavorite"]},"CollectionEntriesPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindCollectionEntriesDto":{"type":"object","properties":{"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}}},"ActivitiesFeedPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FollowStatusDto":{"type":"object","properties":{"isFollowing":{"type":"boolean"}},"required":["isFollowing"]},"FollowInfoRequestDto":{"type":"object","properties":{"criteria":{"type":"string","enum":["followers","following"]},"targetUserId":{"type":"string","minLength":36},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}},"required":["criteria","targetUserId"]},"FollowInfoResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FollowRegisterDto":{"type":"object","properties":{"followedUserId":{"type":"string","minLength":36}},"required":["followedUserId"]},"FollowRemoveDto":{"type":"object","properties":{"followedUserId":{"type":"string","minLength":36}},"required":["followedUserId"]},"ImporterPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"ImporterStatusUpdateRequestDto":{"type":"object","properties":{"status":{"type":"string"},"externalGameId":{"type":"number"}},"required":["status","externalGameId"]},"FindAvailableConnectionsResponseDto":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["steam"]},"isImporterViable":{"type":"boolean"},"iconName":{"type":"string"}},"required":["name","type","isImporterViable","iconName"]},"UserConnection":{"type":"object","properties":{"id":{"type":"number"},"type":{"type":"string","enum":["steam"]},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"sourceUserId":{"type":"string"},"sourceUsername":{"type":"string"},"isImporterViable":{"type":"boolean","description":"If this connection can be used by the 'importer' system."},"isImporterEnabled":{"type":"boolean"}},"required":["id","type","profile","profileUserId","sourceUserId","sourceUsername","isImporterViable","isImporterEnabled"]},"ConnectionCreateDto":{"type":"object","properties":{"type":{"type":"string","enum":["steam"]},"userIdentifier":{"type":"string","description":"A string representing a username, user id or profile URL for the target connection
\ne.g. a Steam's profile URL","minLength":1},"isImporterEnabled":{"type":"boolean","default":false}},"required":["type","userIdentifier","isImporterEnabled"]},"FindAllCommentsDto":{"type":"object","properties":{"sourceId":{"type":"string","minLength":36},"sourceType":{"type":"string","enum":["review"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}},"required":["sourceId","sourceType"]},"FindCommentsPaginatedResponseDto":{"type":"object","properties":{"data":{"default":[],"type":"array","items":{"$ref":"#/components/schemas/ReviewComment"}},"pagination":{"default":{},"allOf":[{"$ref":"#/components/schemas/PaginationInfo"}]}},"required":["data","pagination"]},"CreateCommentDto":{"type":"object","properties":{"sourceId":{"type":"string","description":"UUID of the target entity. Comments can only be attributed to\nUUID based entities.","minLength":36},"sourceType":{"type":"string","enum":["review"]},"content":{"type":"string","minLength":1}},"required":["sourceId","sourceType","content"]},"UpdateCommentDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review"]},"content":{"type":"string","minLength":1}},"required":["sourceType","content"]},"DeleteCommentDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review"]}},"required":["sourceType"]},"Report":{"type":"object","properties":{"id":{"type":"number"},"sourceType":{"description":"Indexed to improve speed when filtering by type.","enum":["review","profile","review_comment"],"type":"string"},"category":{"enum":["spam","personal"],"type":"string"},"targetReview":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"targetReviewId":{"type":"string","nullable":true},"targetReviewComment":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewComment"}]},"targetReviewCommentId":{"type":"string","nullable":true},"targetProfile":{"description":"Profile that is being target of a report","allOf":[{"$ref":"#/components/schemas/Profile"}]},"targetProfileUserId":{"type":"string"},"reason":{"type":"string","nullable":true,"description":"User-submitted reason for report."},"profile":{"description":"User responsible for report.","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string"},"isClosed":{"type":"boolean"},"closeHandleAction":{"nullable":true,"description":"Action taken when closing this report","enum":["discard","alert","suspend","ban"],"type":"string"},"closeProfile":{"nullable":true,"description":"User responsible for closing this report","allOf":[{"$ref":"#/components/schemas/Profile"}]},"closeProfileUserId":{"type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","sourceType","category","targetReview","targetReviewId","targetReviewComment","targetReviewCommentId","targetProfile","targetProfileUserId","reason","profile","profileUserId","isClosed","closeHandleAction","closeProfile","closeProfileUserId","createdAt","updatedAt"]},"PaginatedReportResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Report"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"CreateReportRequestDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review","profile","review_comment"]},"sourceId":{"type":"string","minLength":36},"category":{"type":"string","enum":["spam","personal"]},"reason":{"type":"string"}},"required":["sourceType","sourceId","category"]},"HandleReportRequestDto":{"type":"object","properties":{"action":{"type":"string","enum":["discard","alert","suspend","ban"]},"deleteReportedContent":{"type":"boolean","default":true}},"required":["action","deleteReportedContent"]}}}} \ No newline at end of file +{"openapi":"3.0.0","paths":{"/v1/auth/logout":{"get":{"operationId":"AuthController_logout","parameters":[],"responses":{"200":{"description":""}},"tags":["auth"]}},"/v1/libraries":{"get":{"operationId":"LibrariesController_findOwn","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Library"}}}}},"tags":["libraries"]}},"/v1/libraries/{id}":{"get":{"operationId":"LibrariesController_findOneByIdWithPermissions","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Library"}}}}},"tags":["libraries"]}},"/v1/collections/{id}":{"get":{"operationId":"CollectionsController_findOneByIdWithPermissions","summary":"","description":"Returns a collection which the user has access to\n\n(Either its own collection or a public one)","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Collection"}}}}},"tags":["collections"]},"patch":{"operationId":"CollectionsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCollectionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["collections"]},"delete":{"operationId":"CollectionsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["collections"]}},"/v1/collections/library/{userId}":{"get":{"operationId":"CollectionsController_findAllByUserIdWithPermissions","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}}}}}},"tags":["collections"]}},"/v1/collections":{"post":{"operationId":"CollectionsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCollectionDto"}}}},"responses":{"201":{"description":""}},"tags":["collections"]}},"/v1/reviews":{"post":{"operationId":"ReviewsController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviewDto"}}}},"responses":{"201":{"description":""}},"tags":["reviews"]},"get":{"operationId":"ReviewsController_findOneByUserIdAndGameId","parameters":[{"name":"id","required":true,"in":"query","schema":{"type":"string"}},{"name":"gameId","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}}},"tags":["reviews"]}},"/v1/reviews/all":{"post":{"operationId":"ReviewsController_findAllById","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllReviewsByIdDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Review"}}}}}},"tags":["reviews"]}},"/v1/reviews/score":{"get":{"operationId":"ReviewsController_getScoreForGameId","parameters":[{"name":"gameId","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewScoreResponseDto"}}}}},"tags":["reviews"]}},"/v1/reviews/profile/{userId}":{"get":{"operationId":"ReviewsController_findAllByUserId","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindReviewPaginatedDto"}}}}},"tags":["reviews"]}},"/v1/reviews/game/{id}":{"get":{"operationId":"ReviewsController_findAllByGameId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindReviewPaginatedDto"}}}}},"tags":["reviews"]}},"/v1/reviews/{id}":{"get":{"operationId":"ReviewsController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}}},"tags":["reviews"]},"delete":{"operationId":"ReviewsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reviews"]}},"/v1/profile":{"patch":{"operationId":"ProfileController_update","parameters":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UpdateProfileDto"}}}},"responses":{"200":{"description":""}},"tags":["profile"]},"get":{"operationId":"ProfileController_findOwn","summary":"","description":"Used to access own profile","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}}},"tags":["profile"]}},"/v1/profile/{id}":{"get":{"operationId":"ProfileController_findOneById","summary":"","description":"Used to access other users' profiles","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}}},"tags":["profile"]}},"/v1/activities":{"get":{"operationId":"ActivitiesRepositoryController_findLatest","parameters":[{"name":"userId","required":false,"in":"query","schema":{"minLength":36,"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesPaginatedResponseDto"}}}}},"tags":["activities"]}},"/v1/statistics/queue/like":{"post":{"operationId":"StatisticsQueueController_addLike","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"201":{"description":""}},"tags":["statistics-queue"]},"delete":{"operationId":"StatisticsQueueController_removeLike","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"200":{"description":""}},"tags":["statistics-queue"]}},"/v1/statistics/queue/view":{"post":{"operationId":"StatisticsQueueController_addView","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"201":{"description":""}},"tags":["statistics-queue"]}},"/v1/statistics":{"post":{"operationId":"StatisticsController_findOneBySourceIdAndType","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindOneStatisticsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/games":{"post":{"operationId":"StatisticsController_findTrendingGames","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingGamesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/reviews":{"post":{"operationId":"StatisticsController_findTrendingReviews","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingReviewsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/activities":{"post":{"operationId":"StatisticsController_findTrendingActivities","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingActivitiesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/status":{"get":{"operationId":"StatisticsController_getStatus","parameters":[{"name":"statisticsId","required":true,"in":"query","schema":{"type":"number"}},{"name":"sourceType","required":true,"in":"query","schema":{"enum":["game","review","activity","review_comment"],"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsStatus"}}}}},"tags":["statistics"]}},"/v1/notifications":{"get":{"operationId":"NotificationsController_findAllAndAggregate","parameters":[{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedNotificationAggregationDto"}}}}},"tags":["notifications"]}},"/v1/notifications/new":{"get":{"operationId":"NotificationsController_getNewNotifications","summary":"","description":"Finds new notifications that have been created after last checked time.
\nReturns an empty array on first connection.","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}}}}},"tags":["notifications"]}},"/v1/notifications/view":{"put":{"operationId":"NotificationsController_updateViewedStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationViewUpdateDto"}}}},"responses":{"200":{"description":""}},"tags":["notifications"]}},"/v1/game/repository/resource":{"get":{"operationId":"GameRepositoryController_getResource","parameters":[{"name":"resourceName","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}/platforms/icon":{"get":{"operationId":"GameRepositoryController_getIconNamesForPlatformAbbreviations","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}/external-stores":{"get":{"operationId":"GameRepositoryController_getExternalStoresForGameId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalStoreDto"}}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}":{"post":{"operationId":"GameRepositoryController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameRepositoryFindOneDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Game"}}}}},"tags":["game-repository"]}},"/v1/game/repository":{"post":{"operationId":"GameRepositoryController_findAllByIds","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameRepositoryFindAllDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}}}}},"tags":["game-repository"]}},"/v1/sync/hltb/{gameId}":{"get":{"operationId":"HltbController_findPlaytimeForGameId","parameters":[{"name":"gameId","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GamePlaytime"}}}}},"tags":["sync-hltb"]}},"/v1/achievements":{"get":{"operationId":"AchievementsController_getAchievements","parameters":[{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAchievementsResponseDto"}}}}},"tags":["achievements"]}},"/v1/achievements/obtained/{id}":{"get":{"operationId":"AchievementsController_getObtainedAchievement","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"targetUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObtainedAchievement"}}}}},"tags":["achievements"]}},"/v1/achievements/obtained":{"get":{"operationId":"AchievementsController_getAllObtainedAchievements","parameters":[{"name":"targetUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ObtainedAchievement"}}}}}},"tags":["achievements"]}},"/v1/achievements/obtained/{id}/featured":{"put":{"operationId":"AchievementsController_updateFeaturedObtainedAchievement","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFeaturedObtainedAchievementDto"}}}},"responses":{"200":{"description":""}},"tags":["achievements"]}},"/v1/level/{userId}":{"get":{"operationId":"LevelController_findOne","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLevel"}}}}},"tags":["level"]}},"/v1/collections-entries":{"post":{"operationId":"CollectionsEntriesController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateCollectionEntryDto"}}}},"responses":{"201":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/{id}":{"get":{"operationId":"CollectionsEntriesController_findEntryById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntry"}}}}},"tags":["collections-entries"]},"delete":{"operationId":"CollectionsEntriesController_deleteOwnEntry","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/game/{id}":{"get":{"operationId":"CollectionsEntriesController_findOwnEntryByGameId","summary":"","description":"Returns a specific collection entry based on game ID","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntry"}}}},"400":{"description":"Invalid query"}},"tags":["collections-entries"]}},"/v1/collections-entries/{id}/platforms/icons":{"get":{"operationId":"CollectionsEntriesController_getIconsForOwnedPlatforms","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/game/{id}/favorite":{"post":{"operationId":"CollectionsEntriesController_changeFavoriteStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFavoriteStatusCollectionEntryDto"}}}},"responses":{"204":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/library/{id}":{"get":{"operationId":"CollectionsEntriesController_findAllByLibraryId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/library/{id}/favorites":{"get":{"operationId":"CollectionsEntriesController_findFavoritesByLibraryId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/collection/{id}":{"post":{"operationId":"CollectionsEntriesController_findAllByCollectionId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindCollectionEntriesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/health":{"get":{"operationId":"HealthController_health","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["health"]}},"/v1/activities/feed":{"get":{"operationId":"ActivitiesFeedController_buildActivitiesFeed","parameters":[{"name":"criteria","required":true,"in":"query","schema":{"enum":["following","all"],"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesFeedPaginatedResponseDto"}}}}},"tags":["activities-feed"]}},"/v1/follow/status":{"get":{"operationId":"FollowController_getFollowerStatus","parameters":[{"name":"followerUserId","required":true,"in":"query","schema":{"type":"string"}},{"name":"followedUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowStatusDto"}}}}},"tags":["follow"]}},"/v1/follow/{id}":{"get":{"operationId":"FollowController_getUserFollowById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserFollow"}}}}},"tags":["follow"]}},"/v1/follow/info":{"post":{"operationId":"FollowController_getFollowInfo","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowInfoRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowInfoResponseDto"}}}}},"tags":["follow"]}},"/v1/follow":{"post":{"operationId":"FollowController_registerFollow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRegisterDto"}}}},"responses":{"201":{"description":""}},"tags":["follow"]},"delete":{"operationId":"FollowController_removeFollow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRemoveDto"}}}},"responses":{"200":{"description":""}},"tags":["follow"]}},"/v1/profile/statistics/overview/{userId}":{"get":{"operationId":"ProfileStatisticsController_getStatsOverview","summary":"","description":"Retrieves basic stats for a user profile","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileStatisticsOverviewDto"}}}}},"tags":["profile-statistics"]}},"/v1/importer/watch/notification/{id}":{"get":{"operationId":"ImporterWatchController_findNotification","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterWatchNotification"}}}}},"tags":["importer-watch"]}},"/v1/importer/{source}":{"get":{"operationId":"ImporterController_findUnprocessedEntries","parameters":[{"name":"source","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterPaginatedResponseDto"}}}}},"tags":["importer"]}},"/v1/importer/status":{"post":{"operationId":"ImporterController_changeStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterStatusUpdateRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["importer"]}},"/v1/connections":{"get":{"operationId":"ConnectionsController_findAvailableConnections","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FindAvailableConnectionsResponseDto"}}}}}},"tags":["connections"]},"post":{"operationId":"ConnectionsController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionCreateDto"}}}},"responses":{"201":{"description":""}},"tags":["connections"]}},"/v1/connections/own":{"get":{"operationId":"ConnectionsController_findOwn","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserConnection"}}}}}},"tags":["connections"]}},"/v1/connections/own/{type}":{"get":{"operationId":"ConnectionsController_findOwnByType","parameters":[{"name":"type","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserConnection"}}}}},"tags":["connections"]}},"/v1/connections/{id}":{"delete":{"operationId":"ConnectionsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["connections"]}},"/v1/comment":{"post":{"operationId":"CommentController_findAll","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllCommentsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindCommentsPaginatedResponseDto"}}}}},"tags":["comment"]}},"/v1/comment/{sourceType}/{id}":{"get":{"operationId":"CommentController_findOneById","parameters":[{"name":"sourceType","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewComment"}}}}},"tags":["comment"]}},"/v1/comment/create":{"post":{"operationId":"CommentController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentDto"}}}},"responses":{"201":{"description":""}},"tags":["comment"]}},"/v1/comment/{id}":{"patch":{"operationId":"CommentController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCommentDto"}}}},"responses":{"204":{"description":""}},"tags":["comment"]},"delete":{"operationId":"CommentController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteCommentDto"}}}},"responses":{"200":{"description":""}},"tags":["comment"]}},"/v1/report":{"get":{"operationId":"ReportController_findAllByLatest","parameters":[{"name":"includeClosed","required":false,"in":"query","schema":{"default":false,"type":"boolean"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedReportResponseDto"}}}}},"tags":["report"]},"post":{"operationId":"ReportController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["report"]}},"/v1/report/{id}":{"get":{"operationId":"ReportController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}}}},"tags":["report"]}},"/v1/report/{id}/handle":{"post":{"operationId":"ReportController_handle","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandleReportRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["report"]}}},"info":{"title":"GameNode API","description":"API docs for the videogame catalog system GameNode.

Built with love by the GameNode team.","version":"1.0","contact":{}},"tags":[],"servers":[],"components":{"schemas":{"Library":{"type":"object","properties":{"userId":{"type":"string","description":"@description The primary key of the library entity.\nAlso used to share the library with other users.\n\nSame as SuperTokens' userId."},"collections":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["userId","collections","createdAt","updatedAt"]},"GameCover":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameCollection":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"checksum":{"type":"string"},"url":{"type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}},"required":["id","name","slug","createdAt","updatedAt","checksum","url","games"]},"GameAlternativeName":{"type":"object","properties":{"id":{"type":"number"},"comment":{"type":"string"},"name":{"type":"string"},"checksum":{"type":"string"},"game":{"$ref":"#/components/schemas/Game"}},"required":["id","game"]},"GameArtwork":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameScreenshot":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameLocalization":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameMode":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameGenre":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameTheme":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","createdAt","updatedAt"]},"GamePlayerPerspective":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameEngineLogo":{"type":"object","properties":{"engine":{"$ref":"#/components/schemas/GameEngine"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["engine","id"]},"GameCompanyLogo":{"type":"object","properties":{"company":{"$ref":"#/components/schemas/GameCompany"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["company","id"]},"GameCompany":{"type":"object","properties":{"id":{"type":"number"},"changeDate":{"format":"date-time","type":"string"},"changeDateCategory":{"type":"string"},"changedCompany":{"$ref":"#/components/schemas/GameCompany"},"checksum":{"type":"string"},"country":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"description":{"type":"string"},"logo":{"$ref":"#/components/schemas/GameCompanyLogo"},"name":{"type":"string"},"parent":{"$ref":"#/components/schemas/GameCompany"},"slug":{"type":"string"},"startDate":{"format":"date-time","type":"string"},"startDateCategory":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"url":{"type":"string"}},"required":["id","createdAt","name","slug","updatedAt"]},"GamePlatform":{"type":"object","properties":{"id":{"type":"number"},"abbreviation":{"type":"string"},"alternative_name":{"type":"string"},"category":{"type":"number","enum":[1,2,3,4,5,6]},"checksum":{"type":"string"},"generation":{"type":"number"},"name":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"collectionEntries":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}}},"required":["id","abbreviation","alternative_name","category","checksum","generation","name","createdAt","updatedAt","games","collectionEntries"]},"GameEngine":{"type":"object","properties":{"logo":{"$ref":"#/components/schemas/GameEngineLogo"},"companies":{"type":"array","items":{"$ref":"#/components/schemas/GameCompany"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["logo","companies","platforms","games","id","createdAt","updatedAt"]},"GameKeyword":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameFranchise":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameExternalGame":{"type":"object","properties":{"id":{"type":"number"},"uid":{"type":"string","description":"Corresponds to the game id on the target source (see GameExternalGameCategory).\nIt's called uid, not uuid."},"category":{"type":"number","enum":[1,5,10,11,13,14,15,20,22,23,26,28,29,30,31,32,36,37,54,55]},"media":{"type":"number","enum":[1,2]},"checksum":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"year":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"}},"required":["id","uid","createdAt","updatedAt","game","gameId"]},"GameInvolvedCompany":{"type":"object","properties":{"id":{"type":"number"},"checksum":{"type":"string"},"company":{"$ref":"#/components/schemas/GameCompany"},"companyId":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"developer":{"type":"boolean"},"porting":{"type":"boolean"},"publisher":{"type":"boolean"},"supporting":{"type":"boolean"},"updatedAt":{"format":"date-time","type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}},"required":["id","company","companyId","createdAt","developer","porting","publisher","supporting","updatedAt","games"]},"Game":{"type":"object","properties":{"id":{"type":"number","description":"Should be mapped to the IGDB ID of the game."},"name":{"type":"string"},"slug":{"type":"string"},"aggregatedRating":{"type":"number"},"aggregatedRatingCount":{"type":"number"},"category":{"enum":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14],"type":"number"},"status":{"enum":[0,2,3,4,5,6,7,8],"type":"number"},"summary":{"type":"string"},"storyline":{"type":"string"},"checksum":{"type":"string"},"url":{"type":"string"},"firstReleaseDate":{"format":"date-time","type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"dlcs":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"dlcOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expansions":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expansionOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expandedGames":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expandedGameOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"similarGames":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"similarGameOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remakes":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remakeOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remasters":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remasterOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"cover":{"$ref":"#/components/schemas/GameCover"},"collection":{"$ref":"#/components/schemas/GameCollection"},"alternativeNames":{"type":"array","items":{"$ref":"#/components/schemas/GameAlternativeName"}},"artworks":{"type":"array","items":{"$ref":"#/components/schemas/GameArtwork"}},"screenshots":{"type":"array","items":{"$ref":"#/components/schemas/GameScreenshot"}},"gameLocalizations":{"type":"array","items":{"$ref":"#/components/schemas/GameLocalization"}},"gameModes":{"type":"array","items":{"$ref":"#/components/schemas/GameMode"}},"genres":{"type":"array","items":{"$ref":"#/components/schemas/GameGenre"}},"themes":{"type":"array","items":{"$ref":"#/components/schemas/GameTheme"}},"playerPerspectives":{"type":"array","items":{"$ref":"#/components/schemas/GamePlayerPerspective"}},"gameEngines":{"type":"array","items":{"$ref":"#/components/schemas/GameEngine"}},"keywords":{"type":"array","items":{"$ref":"#/components/schemas/GameKeyword"}},"franchises":{"type":"array","items":{"$ref":"#/components/schemas/GameFranchise"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"externalGames":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}},"involvedCompanies":{"type":"array","items":{"$ref":"#/components/schemas/GameInvolvedCompany"}},"source":{"type":"string","description":"Oh dear maintainer, please forgive me for using transient fields.","default":"MYSQL","enum":["MYSQL","MANTICORE"]}},"required":["id","name","slug","category","status","summary","storyline","checksum","url","firstReleaseDate","createdAt","updatedAt","involvedCompanies","source"]},"ProfileAvatar":{"type":"object","properties":{"id":{"type":"number"},"mimetype":{"type":"string"},"extension":{"type":"string"},"size":{"type":"number"},"filename":{"type":"string"},"encoding":{"type":"string"},"profile":{"$ref":"#/components/schemas/Profile"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","mimetype","extension","size","filename","encoding","profile","createdAt","updatedAt"]},"Profile":{"type":"object","properties":{"userId":{"type":"string","description":"Shareable string ID\n\nSame as SuperTokens' userId."},"username":{"type":"string"},"bio":{"type":"string"},"avatar":{"$ref":"#/components/schemas/ProfileAvatar"},"usernameLastUpdatedAt":{"format":"date-time","type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["userId","username","bio","avatar","usernameLastUpdatedAt","createdAt","updatedAt"]},"Review":{"type":"object","properties":{"id":{"type":"string"},"content":{"type":"string","nullable":true},"rating":{"type":"number"},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"collectionEntry":{"$ref":"#/components/schemas/CollectionEntry"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","content","rating","game","gameId","profile","profileUserId","collectionEntry","createdAt","updatedAt"]},"CollectionEntry":{"type":"object","properties":{"id":{"type":"string"},"collections":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"ownedPlatforms":{"description":"The platforms on which the user owns the game.","type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"isFavorite":{"type":"boolean"},"finishedAt":{"format":"date-time","type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","collections","game","gameId","ownedPlatforms","review","isFavorite","finishedAt","createdAt","updatedAt"]},"Collection":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"isPublic":{"type":"boolean"},"library":{"$ref":"#/components/schemas/Library"},"libraryUserId":{"type":"string"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}},"isFeatured":{"type":"boolean"},"isFinished":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","name","description","isPublic","library","libraryUserId","entries","isFeatured","isFinished","createdAt","updatedAt"]},"CreateCollectionDto":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"isPublic":{"type":"boolean"},"isFeatured":{"type":"boolean"},"isFinished":{"type":"boolean"}},"required":["name","isPublic","isFeatured","isFinished"]},"UpdateCollectionDto":{"type":"object","properties":{}},"CreateReviewDto":{"type":"object","properties":{"gameId":{"type":"number"},"content":{"type":"string","minLength":20},"rating":{"type":"number","minimum":0,"maximum":5}},"required":["gameId","content","rating"]},"FindAllReviewsByIdDto":{"type":"object","properties":{"reviewsIds":{"type":"array","items":{"type":"string"}}},"required":["reviewsIds"]},"ReviewScoreDistribution":{"type":"object","properties":{"1":{"type":"number"},"2":{"type":"number"},"3":{"type":"number"},"4":{"type":"number"},"5":{"type":"number"},"total":{"type":"number","description":"Total number of reviews"}},"required":["1","2","3","4","5","total"]},"ReviewScoreResponseDto":{"type":"object","properties":{"median":{"type":"number"},"distribution":{"$ref":"#/components/schemas/ReviewScoreDistribution"}},"required":["median","distribution"]},"PaginationInfo":{"type":"object","properties":{"totalItems":{"type":"number","description":"Total number of items available for the current query"},"totalPages":{"type":"number","description":"Total number of pages available for the current query"},"hasNextPage":{"type":"boolean","description":"If this query allows for a next page"}},"required":["totalItems","totalPages","hasNextPage"]},"FindReviewPaginatedDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Review"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"UpdateProfileDto":{"type":"object","properties":{"username":{"type":"string","minLength":4,"maxLength":20},"avatar":{"type":"object"},"bio":{"type":"string","minLength":1,"maxLength":240}}},"UserFollow":{"type":"object","properties":{"id":{"type":"number"},"follower":{"$ref":"#/components/schemas/Profile"},"followerUserId":{"type":"string"},"followed":{"$ref":"#/components/schemas/Profile"},"followedUserId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","follower","followerUserId","followed","followedUserId","createdAt","updatedAt"]},"Activity":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["REVIEW","FOLLOW","COLLECTION_ENTRY"]},"profile":{"description":"The associated profile with this Activity (e.g. user who performed an action)","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string"},"collectionEntry":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CollectionEntry"}]},"collectionEntryId":{"type":"string","nullable":true},"collection":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Collection"}]},"collectionId":{"type":"string","nullable":true},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"reviewId":{"type":"string","nullable":true},"userFollow":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/UserFollow"}]},"userFollowId":{"type":"number","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","type","profile","profileUserId","collectionEntry","collectionEntryId","collection","collectionId","review","reviewId","userFollow","userFollowId","createdAt","updatedAt"]},"ActivitiesPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"StatisticsActionDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"targetUserId":{"type":"string","minLength":36},"sourceType":{"enum":["game","review","activity","review_comment"],"type":"string"}},"required":["sourceId","sourceType"]},"FindOneStatisticsDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"sourceType":{"type":"string","enum":["game","review","activity","review_comment"]}},"required":["sourceId","sourceType"]},"GameRepositoryFilterDto":{"type":"object","properties":{"ids":{"description":"If this is supplied, filtering will be done only for entities specified here.
\nUseful to filter data received from entities which hold game ids (like GameStatistics, Reviews, etc.)","type":"array","items":{"type":"number"}},"status":{"type":"number","enum":[0,2,3,4,5,6,7,8]},"category":{"type":"number","enum":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]},"themes":{"type":"array","items":{"type":"number"}},"gameModes":{"type":"array","items":{"type":"number"}},"platforms":{"type":"array","items":{"type":"number"}},"genres":{"type":"array","items":{"type":"number"}},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}}},"FindStatisticsTrendingGamesDto":{"type":"object","properties":{"criteria":{"$ref":"#/components/schemas/GameRepositoryFilterDto"},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"ActivityStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"activity":{"$ref":"#/components/schemas/Activity"},"activityId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","activity","activityId","id","viewsCount","likesCount"]},"ReviewComment":{"type":"object","properties":{"review":{"$ref":"#/components/schemas/Review"},"reviewId":{"type":"string"},"id":{"type":"string"},"content":{"type":"string","description":"HTML content of the user's comment."},"profile":{"description":"Author of this comment","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string","description":"User id of the author of this comment"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["review","reviewId","id","content","profile","profileUserId","createdAt","updatedAt"]},"CommentStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"reviewComment":{"$ref":"#/components/schemas/ReviewComment"},"reviewCommentId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","reviewComment","reviewCommentId","id","viewsCount","likesCount"]},"UserLike":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/GameStatistics"}]},"gameStatisticsId":{"type":"number","nullable":true},"reviewStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewStatistics"}]},"reviewStatisticsId":{"type":"number","nullable":true},"activityStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ActivityStatistics"}]},"activityStatisticsId":{"type":"number","nullable":true},"commentStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CommentStatistics"}]},"commentStatisticsId":{"type":"number","nullable":true}},"required":["id","profile","profileUserId","createdAt","updatedAt","gameStatistics","gameStatisticsId","reviewStatistics","reviewStatisticsId","activityStatistics","activityStatisticsId","commentStatistics","commentStatisticsId"]},"ReviewStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"review":{"$ref":"#/components/schemas/Review"},"reviewId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","review","reviewId","id","viewsCount","likesCount"]},"UserView":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/GameStatistics"}]},"reviewStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewStatistics"}]},"activityStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ActivityStatistics"}]},"commentStatistics":{"type":"object"}},"required":["id","profileUserId","createdAt","updatedAt","gameStatistics","reviewStatistics","activityStatistics","commentStatistics"]},"GameStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","game","gameId","id","viewsCount","likesCount"]},"GameStatisticsPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameStatistics"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindStatisticsTrendingReviewsDto":{"type":"object","properties":{"reviewId":{"type":"string","description":"Usually, this property should not be used unless a specific review needs to be retrieved, and it's easier to just\ncall the statistics controller."},"gameId":{"type":"number"},"userId":{"type":"string","minLength":36},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"ReviewStatisticsPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReviewStatistics"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindStatisticsTrendingActivitiesDto":{"type":"object","properties":{"activityId":{"type":"string","description":"Usually, this property should not be used unless a specific activity needs to be retrieved, and it's easier to just\ncall the statistics controller.","minLength":36},"userId":{"type":"string","minLength":36},"activityType":{"type":"string","enum":["REVIEW","FOLLOW","COLLECTION_ENTRY"]},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"StatisticsStatus":{"type":"object","properties":{"isLiked":{"type":"boolean"},"isViewed":{"type":"boolean"}},"required":["isLiked","isViewed"]},"ImporterWatchNotification":{"type":"object","properties":{"id":{"type":"number"},"library":{"$ref":"#/components/schemas/Library"},"libraryUserId":{"type":"string"},"source":{"type":"string","enum":["steam"]},"games":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}}},"required":["id","library","libraryUserId","source","games"]},"Notification":{"type":"object","properties":{"id":{"type":"number"},"sourceType":{"enum":["game","review","activity","profile","importer","report"],"type":"string"},"category":{"description":"What this notification's about. E.g.: a new like, a new follower, a game launch, etc.","enum":["follow","like","comment","watch","alert"],"type":"string"},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"reviewId":{"type":"string","nullable":true},"game":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Game"}]},"gameId":{"type":"number","nullable":true},"activity":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Activity"}]},"activityId":{"type":"string","nullable":true},"profile":{"nullable":true,"description":"User responsible for generating this notification (e.g. user that liked a review).","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string","nullable":true,"description":"User responsible for generating this notification (e.g. user that liked a review).\nWhen null/undefined, the notification was generated by the 'system'."},"importerNotification":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ImporterWatchNotification"}]},"importerNotificationId":{"type":"number"},"report":{"type":"object"},"reportId":{"type":"number","nullable":true},"isViewed":{"type":"boolean"},"targetProfile":{"nullable":true,"description":"User which is the target for this notification.
\nIf this is empty (null/undefined), the notification is targeted at all users.
\nNot to be confused with the 'profile' property.","allOf":[{"$ref":"#/components/schemas/Profile"}]},"targetProfileUserId":{"type":"string","nullable":true,"description":"User which is the target for this notification.
\nIf this is empty (null/undefined), the notification is targeted at all users.
\nNot to be confused with the 'profile' property."},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","sourceType","category","review","reviewId","game","gameId","activity","activityId","profile","profileUserId","importerNotification","importerNotificationId","report","reportId","isViewed","targetProfile","targetProfileUserId","createdAt","updatedAt"]},"NotificationAggregateDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"category":{"type":"string","enum":["follow","like","comment","watch","alert"]},"sourceType":{"type":"string","enum":["game","review","activity","profile","importer","report"]},"notifications":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}},"required":["sourceId","category","sourceType","notifications"]},"PaginatedNotificationAggregationDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NotificationAggregateDto"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"NotificationViewUpdateDto":{"type":"object","properties":{"isViewed":{"type":"boolean"},"notificationIds":{"type":"array","items":{"type":"number"}}},"required":["isViewed","notificationIds"]},"GameExternalStoreDto":{"type":"object","properties":{"icon":{"type":"string","nullable":true,"description":"Icon representing said store/service."},"storeName":{"type":"string","nullable":true},"id":{"type":"number"},"uid":{"type":"string","description":"Corresponds to the game id on the target source (see GameExternalGameCategory).\nIt's called uid, not uuid."},"category":{"type":"number","enum":[1,5,10,11,13,14,15,20,22,23,26,28,29,30,31,32,36,37,54,55]},"media":{"type":"number","enum":[1,2]},"checksum":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"year":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameId":{"type":"number"}},"required":["icon","storeName","id","uid","createdAt","updatedAt","gameId"]},"GameRepositoryFindOneDto":{"type":"object","properties":{"relations":{"type":"object"}}},"GameRepositoryFindAllDto":{"type":"object","properties":{"gameIds":{"type":"array","items":{"type":"number"}},"relations":{"type":"object"}},"required":["gameIds"]},"GamePlaytime":{"type":"object","properties":{"id":{"type":"number"},"gameId":{"type":"number"},"game":{"$ref":"#/components/schemas/Game"},"sourceId":{"type":"number"},"timeMain":{"type":"number","nullable":true},"timePlus":{"type":"number","nullable":true},"time100":{"type":"number","nullable":true},"timeAll":{"type":"number","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","gameId","game","sourceId","timeMain","timePlus","time100","timeAll","createdAt","updatedAt"]},"AchievementDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"expGainAmount":{"type":"number"},"category":{"type":"number","enum":[0,1,2,3]}},"required":["id","name","description","expGainAmount","category"]},"PaginatedAchievementsResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AchievementDto"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"ObtainedAchievement":{"type":"object","properties":{"id":{"type":"number"},"achievementId":{"type":"string","description":"Achievement id specified in entries for achievements.data.ts"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"isFeatured":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","achievementId","profile","profileUserId","isFeatured","createdAt","updatedAt"]},"UpdateFeaturedObtainedAchievementDto":{"type":"object","properties":{"isFeatured":{"type":"boolean"}},"required":["isFeatured"]},"UserLevel":{"type":"object","properties":{"userId":{"type":"string","description":"Should be the same as the profile's UserId"},"profile":{"$ref":"#/components/schemas/Profile"},"currentLevel":{"type":"number"},"currentLevelExp":{"type":"number","description":"XP in the current user-level"},"levelUpExpCost":{"type":"number","description":"Threshold XP to hit the next user-level"},"expMultiplier":{"type":"number","description":"The multiplier to apply to all exp gains"}},"required":["userId","profile","currentLevel","currentLevelExp","levelUpExpCost","expMultiplier"]},"CreateUpdateCollectionEntryDto":{"type":"object","properties":{"finishedAt":{"type":"date-time"},"collectionIds":{"type":"array","items":{"type":"string"}},"gameId":{"type":"number"},"platformIds":{"type":"array","items":{"type":"number"}},"isFavorite":{"type":"boolean","default":false}},"required":["collectionIds","gameId","platformIds","isFavorite"]},"CreateFavoriteStatusCollectionEntryDto":{"type":"object","properties":{"isFavorite":{"type":"boolean","default":false}},"required":["isFavorite"]},"CollectionEntriesPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindCollectionEntriesDto":{"type":"object","properties":{"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}}},"ActivitiesFeedPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FollowStatusDto":{"type":"object","properties":{"isFollowing":{"type":"boolean"}},"required":["isFollowing"]},"FollowInfoRequestDto":{"type":"object","properties":{"criteria":{"type":"string","enum":["followers","following"]},"targetUserId":{"type":"string","minLength":36},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}},"required":["criteria","targetUserId"]},"FollowInfoResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FollowRegisterDto":{"type":"object","properties":{"followedUserId":{"type":"string","minLength":36}},"required":["followedUserId"]},"FollowRemoveDto":{"type":"object","properties":{"followedUserId":{"type":"string","minLength":36}},"required":["followedUserId"]},"ProfileStatisticsOverviewDto":{"type":"object","properties":{"totalGames":{"type":"number"},"totalCollections":{"type":"number"},"totalFinishedGames":{"type":"number"},"totalEstimatedPlaytime":{"type":"number","description":"Total playtime spent on finished games, based on available data and HLTB's 'main' profile."}},"required":["totalGames","totalCollections","totalFinishedGames","totalEstimatedPlaytime"]},"ImporterPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"ImporterStatusUpdateRequestDto":{"type":"object","properties":{"status":{"type":"string"},"externalGameId":{"type":"number"}},"required":["status","externalGameId"]},"FindAvailableConnectionsResponseDto":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["steam"]},"isImporterViable":{"type":"boolean"},"iconName":{"type":"string"}},"required":["name","type","isImporterViable","iconName"]},"UserConnection":{"type":"object","properties":{"id":{"type":"number"},"type":{"type":"string","enum":["steam"]},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"sourceUserId":{"type":"string"},"sourceUsername":{"type":"string"},"isImporterViable":{"type":"boolean","description":"If this connection can be used by the 'importer' system."},"isImporterEnabled":{"type":"boolean"}},"required":["id","type","profile","profileUserId","sourceUserId","sourceUsername","isImporterViable","isImporterEnabled"]},"ConnectionCreateDto":{"type":"object","properties":{"type":{"type":"string","enum":["steam"]},"userIdentifier":{"type":"string","description":"A string representing a username, user id or profile URL for the target connection
\ne.g. a Steam's profile URL","minLength":1},"isImporterEnabled":{"type":"boolean","default":false}},"required":["type","userIdentifier","isImporterEnabled"]},"FindAllCommentsDto":{"type":"object","properties":{"sourceId":{"type":"string","minLength":36},"sourceType":{"type":"string","enum":["review"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}},"required":["sourceId","sourceType"]},"FindCommentsPaginatedResponseDto":{"type":"object","properties":{"data":{"default":[],"type":"array","items":{"$ref":"#/components/schemas/ReviewComment"}},"pagination":{"default":{},"allOf":[{"$ref":"#/components/schemas/PaginationInfo"}]}},"required":["data","pagination"]},"CreateCommentDto":{"type":"object","properties":{"sourceId":{"type":"string","description":"UUID of the target entity. Comments can only be attributed to\nUUID based entities.","minLength":36},"sourceType":{"type":"string","enum":["review"]},"content":{"type":"string","minLength":1}},"required":["sourceId","sourceType","content"]},"UpdateCommentDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review"]},"content":{"type":"string","minLength":1}},"required":["sourceType","content"]},"DeleteCommentDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review"]}},"required":["sourceType"]},"Report":{"type":"object","properties":{"id":{"type":"number"},"sourceType":{"description":"Indexed to improve speed when filtering by type.","enum":["review","profile","review_comment"],"type":"string"},"category":{"enum":["spam","personal"],"type":"string"},"targetReview":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"targetReviewId":{"type":"string","nullable":true},"targetReviewComment":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewComment"}]},"targetReviewCommentId":{"type":"string","nullable":true},"targetProfile":{"description":"Profile that is being target of a report","allOf":[{"$ref":"#/components/schemas/Profile"}]},"targetProfileUserId":{"type":"string"},"reason":{"type":"string","nullable":true,"description":"User-submitted reason for report."},"profile":{"description":"User responsible for report.","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string"},"isClosed":{"type":"boolean"},"closeHandleAction":{"nullable":true,"description":"Action taken when closing this report","enum":["discard","alert","suspend","ban"],"type":"string"},"closeProfile":{"nullable":true,"description":"User responsible for closing this report","allOf":[{"$ref":"#/components/schemas/Profile"}]},"closeProfileUserId":{"type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","sourceType","category","targetReview","targetReviewId","targetReviewComment","targetReviewCommentId","targetProfile","targetProfileUserId","reason","profile","profileUserId","isClosed","closeHandleAction","closeProfile","closeProfileUserId","createdAt","updatedAt"]},"PaginatedReportResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Report"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"CreateReportRequestDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review","profile","review_comment"]},"sourceId":{"type":"string","minLength":36},"category":{"type":"string","enum":["spam","personal"]},"reason":{"type":"string"}},"required":["sourceType","sourceId","category"]},"HandleReportRequestDto":{"type":"object","properties":{"action":{"type":"string","enum":["discard","alert","suspend","ban"]},"deleteReportedContent":{"type":"boolean","default":true}},"required":["action","deleteReportedContent"]}}}} \ No newline at end of file diff --git a/src/app.module.ts b/src/app.module.ts index f265ddb..4a0367c 100755 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -29,8 +29,9 @@ import { ImporterModule } from "./importer/importer.module"; import { ConnectionsModule } from "./connections/connections.module"; import { CommentModule } from "./comment/comment.module"; import { ImporterWatchModule } from "./importer/importer-watch/importer-watch.module"; -import { ReportModule } from './report/report.module'; -import { SuspensionModule } from './suspension/suspension.module'; +import { ReportModule } from "./report/report.module"; +import { SuspensionModule } from "./suspension/suspension.module"; +import { ProfileStatisticsModule } from "./statistics/profile-statistics/profile-statistics.module"; /** * Should only be called after 'ConfigModule' is loaded (e.g. in useFactory) @@ -159,6 +160,7 @@ function getRedisConfig() { CollectionsModule, StatisticsModule, StatisticsQueueModule, + ProfileStatisticsModule, LevelModule, HealthModule, AchievementsModule, diff --git a/src/collections/collections-entries/collections-entries.service.ts b/src/collections/collections-entries/collections-entries.service.ts index 87f830e..730e556 100755 --- a/src/collections/collections-entries/collections-entries.service.ts +++ b/src/collections/collections-entries/collections-entries.service.ts @@ -131,6 +131,7 @@ export class CollectionsEntriesService { ) { const isOwnQuery = userId === targetUserId; const findOptions = buildBaseFindOptions(dto); + if (isOwnQuery) { return await this.collectionEntriesRepository.findAndCount({ ...findOptions, diff --git a/src/collections/collections-entries/entities/collection-entry.entity.ts b/src/collections/collections-entries/entities/collection-entry.entity.ts index 7f62941..3ea3ae4 100755 --- a/src/collections/collections-entries/entities/collection-entry.entity.ts +++ b/src/collections/collections-entries/entities/collection-entry.entity.ts @@ -16,7 +16,8 @@ import { Review } from "../../../reviews/entities/review.entity"; @Entity() /** - * Represents an entry in a collection. + * Represents an entry in a collection.
+ * Each CollectionEntry corresponds to a single game. * @class CollectionEntry */ export class CollectionEntry { diff --git a/src/collections/collections.service.ts b/src/collections/collections.service.ts index ac94eff..83cc1be 100755 --- a/src/collections/collections.service.ts +++ b/src/collections/collections.service.ts @@ -205,7 +205,7 @@ export class CollectionsService { } /** - * Removes a collection and it's models. + * Removes a collection. * @param userId * @param collectionId */ diff --git a/src/game/game-repository/entities/game.entity.ts b/src/game/game-repository/entities/game.entity.ts index 3c6d81a..f1a6152 100644 --- a/src/game/game-repository/entities/game.entity.ts +++ b/src/game/game-repository/entities/game.entity.ts @@ -2,7 +2,6 @@ import { Column, CreateDateColumn, Entity, - JoinColumn, JoinTable, ManyToMany, ManyToOne, @@ -121,7 +120,7 @@ export class Game { @ManyToMany(() => Game, (game) => game.expansionOf, { nullable: true, }) - @JoinColumn() + @JoinTable() expansions?: Game[]; @ManyToMany(() => Game, (game) => game.expansions, { nullable: true, diff --git a/src/statistics/profile-statistics/dto/profile-statistics-distribution-request.dto.ts b/src/statistics/profile-statistics/dto/profile-statistics-distribution-request.dto.ts new file mode 100644 index 0000000..513168e --- /dev/null +++ b/src/statistics/profile-statistics/dto/profile-statistics-distribution-request.dto.ts @@ -0,0 +1,26 @@ +import { IsEnum, IsNotEmpty } from "class-validator"; + +export enum ProfileStatisticsDistribution { + RELEASE_YEAR = "release_year", + FINISH_YEAR = "finish_year", +} + +export class ProfileStatisticsDistributionRequestDto { + @IsNotEmpty() + @IsEnum(ProfileStatisticsDistribution) + by: ProfileStatisticsDistribution; +} + +/** + * Relation between a year (presented as string) and data for said period. + */ +export interface ProfileStatisticsDistributionYearToData { + [p: string]: { + count: number; + totalEstimatedPlaytime: number; + }; +} + +export class ProfileStatisticsDistributionResponseDto { + distribution: ProfileStatisticsDistributionYearToData; +} diff --git a/src/statistics/profile-statistics/dto/profile-statistics-overview.dto.ts b/src/statistics/profile-statistics/dto/profile-statistics-overview.dto.ts new file mode 100644 index 0000000..07c6677 --- /dev/null +++ b/src/statistics/profile-statistics/dto/profile-statistics-overview.dto.ts @@ -0,0 +1,9 @@ +export class ProfileStatisticsOverviewDto { + totalGames: number; + totalCollections: number; + totalFinishedGames: number; + /** + * Total playtime spent on finished games, based on available data and HLTB's 'main' profile. + */ + totalEstimatedPlaytime: number; +} diff --git a/src/statistics/profile-statistics/profile-statistics.controller.ts b/src/statistics/profile-statistics/profile-statistics.controller.ts new file mode 100644 index 0000000..c075888 --- /dev/null +++ b/src/statistics/profile-statistics/profile-statistics.controller.ts @@ -0,0 +1,37 @@ +import { Controller, Get, Param, UseGuards } from "@nestjs/common"; +import { ApiOkResponse, ApiTags } from "@nestjs/swagger"; +import { ProfileStatisticsService } from "./profile-statistics.service"; +import { ProfileStatisticsOverviewDto } from "./dto/profile-statistics-overview.dto"; +import { AuthGuard } from "../../auth/auth.guard"; +import { Public } from "../../auth/public.decorator"; +import { ProfileStatisticsDistributionResponseDto } from "./dto/profile-statistics-distribution-request.dto"; + +@Controller("profile/statistics") +@ApiTags("profile-statistics") +@UseGuards(AuthGuard) +export class ProfileStatisticsController { + constructor( + private readonly profileStatisticsService: ProfileStatisticsService, + ) {} + + /** + * Retrieves basic stats for a user profile + * @see + */ + @Get("overview/:userId") + @ApiOkResponse({ + type: ProfileStatisticsOverviewDto, + }) + @Public() + async getStatsOverview(@Param("userId") userId: string) { + return this.profileStatisticsService.getStatsOverview(userId); + } + + @Get("distribution/:userId") + @ApiOkResponse({ + type: ProfileStatisticsDistributionResponseDto, + }) + async getStatsDistribution(@Param("userId") userId: string) { + return this.profileStatisticsService.getDistribution(userId); + } +} diff --git a/src/statistics/profile-statistics/profile-statistics.module.ts b/src/statistics/profile-statistics/profile-statistics.module.ts new file mode 100644 index 0000000..41772f3 --- /dev/null +++ b/src/statistics/profile-statistics/profile-statistics.module.ts @@ -0,0 +1,18 @@ +import { Module } from "@nestjs/common"; +import { ProfileStatisticsController } from "./profile-statistics.controller"; +import { ProfileStatisticsService } from "./profile-statistics.service"; +import { CollectionsEntriesModule } from "../../collections/collections-entries/collections-entries.module"; +import { CollectionsModule } from "../../collections/collections.module"; +import { HltbSyncModule } from "../../sync/hltb/hltb-sync.module"; + +/** + * Module responsible for providing profile's stats' data.
+ * This module is quite different from other modules with the same statistics prefix, because it doesn't + * resolve around user likes and views. + */ +@Module({ + imports: [CollectionsModule, CollectionsEntriesModule, HltbSyncModule], + controllers: [ProfileStatisticsController], + providers: [ProfileStatisticsService], +}) +export class ProfileStatisticsModule {} diff --git a/src/statistics/profile-statistics/profile-statistics.service.ts b/src/statistics/profile-statistics/profile-statistics.service.ts new file mode 100644 index 0000000..646f904 --- /dev/null +++ b/src/statistics/profile-statistics/profile-statistics.service.ts @@ -0,0 +1,96 @@ +import { Injectable, UseGuards } from "@nestjs/common"; +import { AuthGuard } from "../../auth/auth.guard"; +import { CollectionsService } from "../../collections/collections.service"; +import { CollectionsEntriesService } from "../../collections/collections-entries/collections-entries.service"; +import { ProfileStatisticsOverviewDto } from "./dto/profile-statistics-overview.dto"; +import { HltbSyncService } from "../../sync/hltb/hltb-sync.service"; +import { + ProfileStatisticsDistribution, + ProfileStatisticsDistributionRequestDto, +} from "./dto/profile-statistics-distribution-request.dto"; + +@Injectable() +export class ProfileStatisticsService { + constructor( + private readonly collectionsService: CollectionsService, + private readonly collectionsEntriesService: CollectionsEntriesService, + private readonly htlbService: HltbSyncService, + ) {} + + /** + * Returns an estimate total playtime for games based on the HLTB 'main' profile. + * @param gameIds + * @private + */ + private async getTotalPlaytimeForGames(gameIds: number[]) { + const playtimes = await this.htlbService.findAllByGameIds(gameIds); + return playtimes.reduce((prev, curr) => { + if (!curr.timeMain) return prev; + + return prev + curr.timeMain; + }, 0); + } + + async getStatsOverview( + userId: string, + ): Promise { + const collections = + await this.collectionsService.findAllByUserIdWithPermissions( + undefined, + userId, + ); + const [collectionEntries] = + await this.collectionsEntriesService.findAllByUserIdWithPermissions( + undefined, + userId, + { + limit: undefined, + offset: 0, + }, + ); + + const finishedCollectionEntries = collectionEntries.filter((entry) => { + return entry.finishedAt != undefined; + }); + + const finishedGamesIds = finishedCollectionEntries.map( + (entry) => entry.gameId, + ); + + const estimatedPlaytime = + await this.getTotalPlaytimeForGames(finishedGamesIds); + + return { + totalCollections: collections.length, + totalFinishedGames: finishedCollectionEntries.length, + totalGames: collectionEntries.length, + totalEstimatedPlaytime: estimatedPlaytime, + }; + } + + async getDistribution( + userId: string, + dto: ProfileStatisticsDistributionRequestDto, + ) { + const [collectionEntries] = + await this.collectionsEntriesService.findAllByUserIdWithPermissions( + undefined, + userId, + { + limit: undefined, + offset: 0, + }, + ); + + switch (dto.by) { + case ProfileStatisticsDistribution.FINISH_YEAR: { + const finishedGames = collectionEntries.filter( + (entry) => entry.finishedAt != undefined, + ); + break; + } + case ProfileStatisticsDistribution.RELEASE_YEAR: + break; + } + } +} diff --git a/src/statistics/statistics.module.ts b/src/statistics/statistics.module.ts index 9b922e7..1630ff8 100644 --- a/src/statistics/statistics.module.ts +++ b/src/statistics/statistics.module.ts @@ -13,6 +13,7 @@ import { ActivityStatisticsService } from "./activity-statistics.service"; import { ActivityStatistics } from "./entity/activity-statistics.entity"; import { CommentStatisticsService } from "./comment-statistics.service"; import { CommentStatistics } from "./entity/comment-statistics.entity"; +import { ProfileStatisticsModule } from "./profile-statistics/profile-statistics.module"; @Module({ imports: [ diff --git a/src/sync/hltb/hltb-sync.module.ts b/src/sync/hltb/hltb-sync.module.ts index 535864c..91cfce6 100644 --- a/src/sync/hltb/hltb-sync.module.ts +++ b/src/sync/hltb/hltb-sync.module.ts @@ -23,6 +23,6 @@ import { HltbSyncProcessor } from "./hltb-sync.processor"; HltbSyncProcessor, ], controllers: [HltbController], - exports: [HltbSyncQueueService], + exports: [HltbSyncQueueService, HltbSyncService], }) export class HltbSyncModule {} diff --git a/src/sync/hltb/hltb-sync.processor.ts b/src/sync/hltb/hltb-sync.processor.ts index 02372ce..ff9fdc2 100644 --- a/src/sync/hltb/hltb-sync.processor.ts +++ b/src/sync/hltb/hltb-sync.processor.ts @@ -30,7 +30,8 @@ function parseResponse( } /** - * Attempt to improve the chances of succesfully finding a game by removing non-essential words (e.g. 'Complete Edition'). + * Attempt to improve the chances of successfully finding a game by removing + * non-essential words (e.g. 'Complete Edition'). * @param gameName */ function parseGameName(gameName: string) { diff --git a/src/sync/hltb/hltb-sync.service.ts b/src/sync/hltb/hltb-sync.service.ts index d2e5fa5..5db6648 100644 --- a/src/sync/hltb/hltb-sync.service.ts +++ b/src/sync/hltb/hltb-sync.service.ts @@ -7,7 +7,7 @@ import { } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { GamePlaytime } from "./entity/game-playtime.entity"; -import { DeepPartial, Repository } from "typeorm"; +import { DeepPartial, In, Repository } from "typeorm"; import { CACHE_MANAGER, Cache } from "@nestjs/cache-manager"; import { days } from "@nestjs/throttler"; @@ -42,6 +42,14 @@ export class HltbSyncService { return entity; } + public async findAllByGameIds(gameIds: number[]) { + return this.gamePlaytimeRepository.find({ + where: { + gameId: In(gameIds), + }, + }); + } + private async hasFailedAttempt(gameId: number) { const attempt = await this.cacheManager.get( `hltb-failed-attempt-${gameId}`, From bd61430ad48fe0fd36f12cd57c24d17d65f4ed86 Mon Sep 17 00:00:00 2001 From: Lamarcke Date: Mon, 8 Jul 2024 21:20:47 -0300 Subject: [PATCH 4/7] - start of work on profile-statistics module --- .../profile-statistics.controller.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/statistics/profile-statistics/profile-statistics.controller.ts b/src/statistics/profile-statistics/profile-statistics.controller.ts index c075888..86d0422 100644 --- a/src/statistics/profile-statistics/profile-statistics.controller.ts +++ b/src/statistics/profile-statistics/profile-statistics.controller.ts @@ -1,10 +1,13 @@ -import { Controller, Get, Param, UseGuards } from "@nestjs/common"; +import { Controller, Get, Param, Query, UseGuards } from "@nestjs/common"; import { ApiOkResponse, ApiTags } from "@nestjs/swagger"; import { ProfileStatisticsService } from "./profile-statistics.service"; import { ProfileStatisticsOverviewDto } from "./dto/profile-statistics-overview.dto"; import { AuthGuard } from "../../auth/auth.guard"; import { Public } from "../../auth/public.decorator"; -import { ProfileStatisticsDistributionResponseDto } from "./dto/profile-statistics-distribution-request.dto"; +import { + ProfileStatisticsDistributionRequestDto, + ProfileStatisticsDistributionResponseDto, +} from "./dto/profile-statistics-distribution-request.dto"; @Controller("profile/statistics") @ApiTags("profile-statistics") @@ -31,7 +34,10 @@ export class ProfileStatisticsController { @ApiOkResponse({ type: ProfileStatisticsDistributionResponseDto, }) - async getStatsDistribution(@Param("userId") userId: string) { - return this.profileStatisticsService.getDistribution(userId); + async getStatsDistribution( + @Param("userId") userId: string, + @Query() dto: ProfileStatisticsDistributionRequestDto, + ) { + return this.profileStatisticsService.getDistribution(userId, dto); } } From 62ba212ff714b78772f86fadaa1ab699340a74a5 Mon Sep 17 00:00:00 2001 From: Lamarcke Date: Wed, 10 Jul 2024 01:10:02 -0300 Subject: [PATCH 5/7] - Profile v3 MVP --- server_swagger.json | 2 +- src/achievements/achievements.controller.ts | 6 + src/achievements/achievements.service.ts | 7 + src/profile/dto/create-profile.dto.ts | 1 - src/profile/dto/update-profile-image.dto.ts | 14 ++ src/profile/entities/profile-avatar.entity.ts | 14 +- src/profile/entities/profile-banner.entity.ts | 21 +++ src/profile/entities/profile.entity.ts | 13 +- src/profile/profile.controller.ts | 30 ++-- src/profile/profile.module.ts | 5 +- src/profile/profile.service.ts | 139 +++++++++++++----- src/utils/persisted-image-details.entity.ts | 18 +++ 12 files changed, 205 insertions(+), 65 deletions(-) create mode 100644 src/profile/dto/update-profile-image.dto.ts create mode 100644 src/profile/entities/profile-banner.entity.ts create mode 100644 src/utils/persisted-image-details.entity.ts diff --git a/server_swagger.json b/server_swagger.json index f20729a..920b8cf 100644 --- a/server_swagger.json +++ b/server_swagger.json @@ -1 +1 @@ -{"openapi":"3.0.0","paths":{"/v1/auth/logout":{"get":{"operationId":"AuthController_logout","parameters":[],"responses":{"200":{"description":""}},"tags":["auth"]}},"/v1/libraries":{"get":{"operationId":"LibrariesController_findOwn","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Library"}}}}},"tags":["libraries"]}},"/v1/libraries/{id}":{"get":{"operationId":"LibrariesController_findOneByIdWithPermissions","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Library"}}}}},"tags":["libraries"]}},"/v1/collections/{id}":{"get":{"operationId":"CollectionsController_findOneByIdWithPermissions","summary":"","description":"Returns a collection which the user has access to\n\n(Either its own collection or a public one)","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Collection"}}}}},"tags":["collections"]},"patch":{"operationId":"CollectionsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCollectionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["collections"]},"delete":{"operationId":"CollectionsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["collections"]}},"/v1/collections/library/{userId}":{"get":{"operationId":"CollectionsController_findAllByUserIdWithPermissions","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}}}}}},"tags":["collections"]}},"/v1/collections":{"post":{"operationId":"CollectionsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCollectionDto"}}}},"responses":{"201":{"description":""}},"tags":["collections"]}},"/v1/reviews":{"post":{"operationId":"ReviewsController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviewDto"}}}},"responses":{"201":{"description":""}},"tags":["reviews"]},"get":{"operationId":"ReviewsController_findOneByUserIdAndGameId","parameters":[{"name":"id","required":true,"in":"query","schema":{"type":"string"}},{"name":"gameId","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}}},"tags":["reviews"]}},"/v1/reviews/all":{"post":{"operationId":"ReviewsController_findAllById","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllReviewsByIdDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Review"}}}}}},"tags":["reviews"]}},"/v1/reviews/score":{"get":{"operationId":"ReviewsController_getScoreForGameId","parameters":[{"name":"gameId","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewScoreResponseDto"}}}}},"tags":["reviews"]}},"/v1/reviews/profile/{userId}":{"get":{"operationId":"ReviewsController_findAllByUserId","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindReviewPaginatedDto"}}}}},"tags":["reviews"]}},"/v1/reviews/game/{id}":{"get":{"operationId":"ReviewsController_findAllByGameId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindReviewPaginatedDto"}}}}},"tags":["reviews"]}},"/v1/reviews/{id}":{"get":{"operationId":"ReviewsController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}}},"tags":["reviews"]},"delete":{"operationId":"ReviewsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reviews"]}},"/v1/profile":{"patch":{"operationId":"ProfileController_update","parameters":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UpdateProfileDto"}}}},"responses":{"200":{"description":""}},"tags":["profile"]},"get":{"operationId":"ProfileController_findOwn","summary":"","description":"Used to access own profile","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}}},"tags":["profile"]}},"/v1/profile/{id}":{"get":{"operationId":"ProfileController_findOneById","summary":"","description":"Used to access other users' profiles","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}}},"tags":["profile"]}},"/v1/activities":{"get":{"operationId":"ActivitiesRepositoryController_findLatest","parameters":[{"name":"userId","required":false,"in":"query","schema":{"minLength":36,"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesPaginatedResponseDto"}}}}},"tags":["activities"]}},"/v1/statistics/queue/like":{"post":{"operationId":"StatisticsQueueController_addLike","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"201":{"description":""}},"tags":["statistics-queue"]},"delete":{"operationId":"StatisticsQueueController_removeLike","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"200":{"description":""}},"tags":["statistics-queue"]}},"/v1/statistics/queue/view":{"post":{"operationId":"StatisticsQueueController_addView","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"201":{"description":""}},"tags":["statistics-queue"]}},"/v1/statistics":{"post":{"operationId":"StatisticsController_findOneBySourceIdAndType","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindOneStatisticsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/games":{"post":{"operationId":"StatisticsController_findTrendingGames","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingGamesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/reviews":{"post":{"operationId":"StatisticsController_findTrendingReviews","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingReviewsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/activities":{"post":{"operationId":"StatisticsController_findTrendingActivities","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingActivitiesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/status":{"get":{"operationId":"StatisticsController_getStatus","parameters":[{"name":"statisticsId","required":true,"in":"query","schema":{"type":"number"}},{"name":"sourceType","required":true,"in":"query","schema":{"enum":["game","review","activity","review_comment"],"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsStatus"}}}}},"tags":["statistics"]}},"/v1/notifications":{"get":{"operationId":"NotificationsController_findAllAndAggregate","parameters":[{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedNotificationAggregationDto"}}}}},"tags":["notifications"]}},"/v1/notifications/new":{"get":{"operationId":"NotificationsController_getNewNotifications","summary":"","description":"Finds new notifications that have been created after last checked time.
\nReturns an empty array on first connection.","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}}}}},"tags":["notifications"]}},"/v1/notifications/view":{"put":{"operationId":"NotificationsController_updateViewedStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationViewUpdateDto"}}}},"responses":{"200":{"description":""}},"tags":["notifications"]}},"/v1/game/repository/resource":{"get":{"operationId":"GameRepositoryController_getResource","parameters":[{"name":"resourceName","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}/platforms/icon":{"get":{"operationId":"GameRepositoryController_getIconNamesForPlatformAbbreviations","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}/external-stores":{"get":{"operationId":"GameRepositoryController_getExternalStoresForGameId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalStoreDto"}}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}":{"post":{"operationId":"GameRepositoryController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameRepositoryFindOneDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Game"}}}}},"tags":["game-repository"]}},"/v1/game/repository":{"post":{"operationId":"GameRepositoryController_findAllByIds","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameRepositoryFindAllDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}}}}},"tags":["game-repository"]}},"/v1/sync/hltb/{gameId}":{"get":{"operationId":"HltbController_findPlaytimeForGameId","parameters":[{"name":"gameId","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GamePlaytime"}}}}},"tags":["sync-hltb"]}},"/v1/achievements":{"get":{"operationId":"AchievementsController_getAchievements","parameters":[{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAchievementsResponseDto"}}}}},"tags":["achievements"]}},"/v1/achievements/obtained/{id}":{"get":{"operationId":"AchievementsController_getObtainedAchievement","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"targetUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObtainedAchievement"}}}}},"tags":["achievements"]}},"/v1/achievements/obtained":{"get":{"operationId":"AchievementsController_getAllObtainedAchievements","parameters":[{"name":"targetUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ObtainedAchievement"}}}}}},"tags":["achievements"]}},"/v1/achievements/obtained/{id}/featured":{"put":{"operationId":"AchievementsController_updateFeaturedObtainedAchievement","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFeaturedObtainedAchievementDto"}}}},"responses":{"200":{"description":""}},"tags":["achievements"]}},"/v1/level/{userId}":{"get":{"operationId":"LevelController_findOne","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLevel"}}}}},"tags":["level"]}},"/v1/collections-entries":{"post":{"operationId":"CollectionsEntriesController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateCollectionEntryDto"}}}},"responses":{"201":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/{id}":{"get":{"operationId":"CollectionsEntriesController_findEntryById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntry"}}}}},"tags":["collections-entries"]},"delete":{"operationId":"CollectionsEntriesController_deleteOwnEntry","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/game/{id}":{"get":{"operationId":"CollectionsEntriesController_findOwnEntryByGameId","summary":"","description":"Returns a specific collection entry based on game ID","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntry"}}}},"400":{"description":"Invalid query"}},"tags":["collections-entries"]}},"/v1/collections-entries/{id}/platforms/icons":{"get":{"operationId":"CollectionsEntriesController_getIconsForOwnedPlatforms","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/game/{id}/favorite":{"post":{"operationId":"CollectionsEntriesController_changeFavoriteStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFavoriteStatusCollectionEntryDto"}}}},"responses":{"204":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/library/{id}":{"get":{"operationId":"CollectionsEntriesController_findAllByLibraryId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/library/{id}/favorites":{"get":{"operationId":"CollectionsEntriesController_findFavoritesByLibraryId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/collection/{id}":{"post":{"operationId":"CollectionsEntriesController_findAllByCollectionId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindCollectionEntriesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/health":{"get":{"operationId":"HealthController_health","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["health"]}},"/v1/activities/feed":{"get":{"operationId":"ActivitiesFeedController_buildActivitiesFeed","parameters":[{"name":"criteria","required":true,"in":"query","schema":{"enum":["following","all"],"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesFeedPaginatedResponseDto"}}}}},"tags":["activities-feed"]}},"/v1/follow/status":{"get":{"operationId":"FollowController_getFollowerStatus","parameters":[{"name":"followerUserId","required":true,"in":"query","schema":{"type":"string"}},{"name":"followedUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowStatusDto"}}}}},"tags":["follow"]}},"/v1/follow/{id}":{"get":{"operationId":"FollowController_getUserFollowById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserFollow"}}}}},"tags":["follow"]}},"/v1/follow/info":{"post":{"operationId":"FollowController_getFollowInfo","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowInfoRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowInfoResponseDto"}}}}},"tags":["follow"]}},"/v1/follow":{"post":{"operationId":"FollowController_registerFollow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRegisterDto"}}}},"responses":{"201":{"description":""}},"tags":["follow"]},"delete":{"operationId":"FollowController_removeFollow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRemoveDto"}}}},"responses":{"200":{"description":""}},"tags":["follow"]}},"/v1/profile/statistics/overview/{userId}":{"get":{"operationId":"ProfileStatisticsController_getStatsOverview","summary":"","description":"Retrieves basic stats for a user profile","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileStatisticsOverviewDto"}}}}},"tags":["profile-statistics"]}},"/v1/importer/watch/notification/{id}":{"get":{"operationId":"ImporterWatchController_findNotification","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterWatchNotification"}}}}},"tags":["importer-watch"]}},"/v1/importer/{source}":{"get":{"operationId":"ImporterController_findUnprocessedEntries","parameters":[{"name":"source","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterPaginatedResponseDto"}}}}},"tags":["importer"]}},"/v1/importer/status":{"post":{"operationId":"ImporterController_changeStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterStatusUpdateRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["importer"]}},"/v1/connections":{"get":{"operationId":"ConnectionsController_findAvailableConnections","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FindAvailableConnectionsResponseDto"}}}}}},"tags":["connections"]},"post":{"operationId":"ConnectionsController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionCreateDto"}}}},"responses":{"201":{"description":""}},"tags":["connections"]}},"/v1/connections/own":{"get":{"operationId":"ConnectionsController_findOwn","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserConnection"}}}}}},"tags":["connections"]}},"/v1/connections/own/{type}":{"get":{"operationId":"ConnectionsController_findOwnByType","parameters":[{"name":"type","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserConnection"}}}}},"tags":["connections"]}},"/v1/connections/{id}":{"delete":{"operationId":"ConnectionsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["connections"]}},"/v1/comment":{"post":{"operationId":"CommentController_findAll","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllCommentsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindCommentsPaginatedResponseDto"}}}}},"tags":["comment"]}},"/v1/comment/{sourceType}/{id}":{"get":{"operationId":"CommentController_findOneById","parameters":[{"name":"sourceType","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewComment"}}}}},"tags":["comment"]}},"/v1/comment/create":{"post":{"operationId":"CommentController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentDto"}}}},"responses":{"201":{"description":""}},"tags":["comment"]}},"/v1/comment/{id}":{"patch":{"operationId":"CommentController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCommentDto"}}}},"responses":{"204":{"description":""}},"tags":["comment"]},"delete":{"operationId":"CommentController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteCommentDto"}}}},"responses":{"200":{"description":""}},"tags":["comment"]}},"/v1/report":{"get":{"operationId":"ReportController_findAllByLatest","parameters":[{"name":"includeClosed","required":false,"in":"query","schema":{"default":false,"type":"boolean"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedReportResponseDto"}}}}},"tags":["report"]},"post":{"operationId":"ReportController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["report"]}},"/v1/report/{id}":{"get":{"operationId":"ReportController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}}}},"tags":["report"]}},"/v1/report/{id}/handle":{"post":{"operationId":"ReportController_handle","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandleReportRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["report"]}}},"info":{"title":"GameNode API","description":"API docs for the videogame catalog system GameNode.

Built with love by the GameNode team.","version":"1.0","contact":{}},"tags":[],"servers":[],"components":{"schemas":{"Library":{"type":"object","properties":{"userId":{"type":"string","description":"@description The primary key of the library entity.\nAlso used to share the library with other users.\n\nSame as SuperTokens' userId."},"collections":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["userId","collections","createdAt","updatedAt"]},"GameCover":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameCollection":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"checksum":{"type":"string"},"url":{"type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}},"required":["id","name","slug","createdAt","updatedAt","checksum","url","games"]},"GameAlternativeName":{"type":"object","properties":{"id":{"type":"number"},"comment":{"type":"string"},"name":{"type":"string"},"checksum":{"type":"string"},"game":{"$ref":"#/components/schemas/Game"}},"required":["id","game"]},"GameArtwork":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameScreenshot":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameLocalization":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameMode":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameGenre":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameTheme":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","createdAt","updatedAt"]},"GamePlayerPerspective":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameEngineLogo":{"type":"object","properties":{"engine":{"$ref":"#/components/schemas/GameEngine"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["engine","id"]},"GameCompanyLogo":{"type":"object","properties":{"company":{"$ref":"#/components/schemas/GameCompany"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["company","id"]},"GameCompany":{"type":"object","properties":{"id":{"type":"number"},"changeDate":{"format":"date-time","type":"string"},"changeDateCategory":{"type":"string"},"changedCompany":{"$ref":"#/components/schemas/GameCompany"},"checksum":{"type":"string"},"country":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"description":{"type":"string"},"logo":{"$ref":"#/components/schemas/GameCompanyLogo"},"name":{"type":"string"},"parent":{"$ref":"#/components/schemas/GameCompany"},"slug":{"type":"string"},"startDate":{"format":"date-time","type":"string"},"startDateCategory":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"url":{"type":"string"}},"required":["id","createdAt","name","slug","updatedAt"]},"GamePlatform":{"type":"object","properties":{"id":{"type":"number"},"abbreviation":{"type":"string"},"alternative_name":{"type":"string"},"category":{"type":"number","enum":[1,2,3,4,5,6]},"checksum":{"type":"string"},"generation":{"type":"number"},"name":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"collectionEntries":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}}},"required":["id","abbreviation","alternative_name","category","checksum","generation","name","createdAt","updatedAt","games","collectionEntries"]},"GameEngine":{"type":"object","properties":{"logo":{"$ref":"#/components/schemas/GameEngineLogo"},"companies":{"type":"array","items":{"$ref":"#/components/schemas/GameCompany"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["logo","companies","platforms","games","id","createdAt","updatedAt"]},"GameKeyword":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameFranchise":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameExternalGame":{"type":"object","properties":{"id":{"type":"number"},"uid":{"type":"string","description":"Corresponds to the game id on the target source (see GameExternalGameCategory).\nIt's called uid, not uuid."},"category":{"type":"number","enum":[1,5,10,11,13,14,15,20,22,23,26,28,29,30,31,32,36,37,54,55]},"media":{"type":"number","enum":[1,2]},"checksum":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"year":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"}},"required":["id","uid","createdAt","updatedAt","game","gameId"]},"GameInvolvedCompany":{"type":"object","properties":{"id":{"type":"number"},"checksum":{"type":"string"},"company":{"$ref":"#/components/schemas/GameCompany"},"companyId":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"developer":{"type":"boolean"},"porting":{"type":"boolean"},"publisher":{"type":"boolean"},"supporting":{"type":"boolean"},"updatedAt":{"format":"date-time","type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}},"required":["id","company","companyId","createdAt","developer","porting","publisher","supporting","updatedAt","games"]},"Game":{"type":"object","properties":{"id":{"type":"number","description":"Should be mapped to the IGDB ID of the game."},"name":{"type":"string"},"slug":{"type":"string"},"aggregatedRating":{"type":"number"},"aggregatedRatingCount":{"type":"number"},"category":{"enum":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14],"type":"number"},"status":{"enum":[0,2,3,4,5,6,7,8],"type":"number"},"summary":{"type":"string"},"storyline":{"type":"string"},"checksum":{"type":"string"},"url":{"type":"string"},"firstReleaseDate":{"format":"date-time","type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"dlcs":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"dlcOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expansions":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expansionOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expandedGames":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expandedGameOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"similarGames":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"similarGameOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remakes":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remakeOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remasters":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remasterOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"cover":{"$ref":"#/components/schemas/GameCover"},"collection":{"$ref":"#/components/schemas/GameCollection"},"alternativeNames":{"type":"array","items":{"$ref":"#/components/schemas/GameAlternativeName"}},"artworks":{"type":"array","items":{"$ref":"#/components/schemas/GameArtwork"}},"screenshots":{"type":"array","items":{"$ref":"#/components/schemas/GameScreenshot"}},"gameLocalizations":{"type":"array","items":{"$ref":"#/components/schemas/GameLocalization"}},"gameModes":{"type":"array","items":{"$ref":"#/components/schemas/GameMode"}},"genres":{"type":"array","items":{"$ref":"#/components/schemas/GameGenre"}},"themes":{"type":"array","items":{"$ref":"#/components/schemas/GameTheme"}},"playerPerspectives":{"type":"array","items":{"$ref":"#/components/schemas/GamePlayerPerspective"}},"gameEngines":{"type":"array","items":{"$ref":"#/components/schemas/GameEngine"}},"keywords":{"type":"array","items":{"$ref":"#/components/schemas/GameKeyword"}},"franchises":{"type":"array","items":{"$ref":"#/components/schemas/GameFranchise"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"externalGames":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}},"involvedCompanies":{"type":"array","items":{"$ref":"#/components/schemas/GameInvolvedCompany"}},"source":{"type":"string","description":"Oh dear maintainer, please forgive me for using transient fields.","default":"MYSQL","enum":["MYSQL","MANTICORE"]}},"required":["id","name","slug","category","status","summary","storyline","checksum","url","firstReleaseDate","createdAt","updatedAt","involvedCompanies","source"]},"ProfileAvatar":{"type":"object","properties":{"id":{"type":"number"},"mimetype":{"type":"string"},"extension":{"type":"string"},"size":{"type":"number"},"filename":{"type":"string"},"encoding":{"type":"string"},"profile":{"$ref":"#/components/schemas/Profile"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","mimetype","extension","size","filename","encoding","profile","createdAt","updatedAt"]},"Profile":{"type":"object","properties":{"userId":{"type":"string","description":"Shareable string ID\n\nSame as SuperTokens' userId."},"username":{"type":"string"},"bio":{"type":"string"},"avatar":{"$ref":"#/components/schemas/ProfileAvatar"},"usernameLastUpdatedAt":{"format":"date-time","type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["userId","username","bio","avatar","usernameLastUpdatedAt","createdAt","updatedAt"]},"Review":{"type":"object","properties":{"id":{"type":"string"},"content":{"type":"string","nullable":true},"rating":{"type":"number"},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"collectionEntry":{"$ref":"#/components/schemas/CollectionEntry"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","content","rating","game","gameId","profile","profileUserId","collectionEntry","createdAt","updatedAt"]},"CollectionEntry":{"type":"object","properties":{"id":{"type":"string"},"collections":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"ownedPlatforms":{"description":"The platforms on which the user owns the game.","type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"isFavorite":{"type":"boolean"},"finishedAt":{"format":"date-time","type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","collections","game","gameId","ownedPlatforms","review","isFavorite","finishedAt","createdAt","updatedAt"]},"Collection":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"isPublic":{"type":"boolean"},"library":{"$ref":"#/components/schemas/Library"},"libraryUserId":{"type":"string"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}},"isFeatured":{"type":"boolean"},"isFinished":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","name","description","isPublic","library","libraryUserId","entries","isFeatured","isFinished","createdAt","updatedAt"]},"CreateCollectionDto":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"isPublic":{"type":"boolean"},"isFeatured":{"type":"boolean"},"isFinished":{"type":"boolean"}},"required":["name","isPublic","isFeatured","isFinished"]},"UpdateCollectionDto":{"type":"object","properties":{}},"CreateReviewDto":{"type":"object","properties":{"gameId":{"type":"number"},"content":{"type":"string","minLength":20},"rating":{"type":"number","minimum":0,"maximum":5}},"required":["gameId","content","rating"]},"FindAllReviewsByIdDto":{"type":"object","properties":{"reviewsIds":{"type":"array","items":{"type":"string"}}},"required":["reviewsIds"]},"ReviewScoreDistribution":{"type":"object","properties":{"1":{"type":"number"},"2":{"type":"number"},"3":{"type":"number"},"4":{"type":"number"},"5":{"type":"number"},"total":{"type":"number","description":"Total number of reviews"}},"required":["1","2","3","4","5","total"]},"ReviewScoreResponseDto":{"type":"object","properties":{"median":{"type":"number"},"distribution":{"$ref":"#/components/schemas/ReviewScoreDistribution"}},"required":["median","distribution"]},"PaginationInfo":{"type":"object","properties":{"totalItems":{"type":"number","description":"Total number of items available for the current query"},"totalPages":{"type":"number","description":"Total number of pages available for the current query"},"hasNextPage":{"type":"boolean","description":"If this query allows for a next page"}},"required":["totalItems","totalPages","hasNextPage"]},"FindReviewPaginatedDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Review"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"UpdateProfileDto":{"type":"object","properties":{"username":{"type":"string","minLength":4,"maxLength":20},"avatar":{"type":"object"},"bio":{"type":"string","minLength":1,"maxLength":240}}},"UserFollow":{"type":"object","properties":{"id":{"type":"number"},"follower":{"$ref":"#/components/schemas/Profile"},"followerUserId":{"type":"string"},"followed":{"$ref":"#/components/schemas/Profile"},"followedUserId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","follower","followerUserId","followed","followedUserId","createdAt","updatedAt"]},"Activity":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["REVIEW","FOLLOW","COLLECTION_ENTRY"]},"profile":{"description":"The associated profile with this Activity (e.g. user who performed an action)","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string"},"collectionEntry":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CollectionEntry"}]},"collectionEntryId":{"type":"string","nullable":true},"collection":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Collection"}]},"collectionId":{"type":"string","nullable":true},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"reviewId":{"type":"string","nullable":true},"userFollow":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/UserFollow"}]},"userFollowId":{"type":"number","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","type","profile","profileUserId","collectionEntry","collectionEntryId","collection","collectionId","review","reviewId","userFollow","userFollowId","createdAt","updatedAt"]},"ActivitiesPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"StatisticsActionDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"targetUserId":{"type":"string","minLength":36},"sourceType":{"enum":["game","review","activity","review_comment"],"type":"string"}},"required":["sourceId","sourceType"]},"FindOneStatisticsDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"sourceType":{"type":"string","enum":["game","review","activity","review_comment"]}},"required":["sourceId","sourceType"]},"GameRepositoryFilterDto":{"type":"object","properties":{"ids":{"description":"If this is supplied, filtering will be done only for entities specified here.
\nUseful to filter data received from entities which hold game ids (like GameStatistics, Reviews, etc.)","type":"array","items":{"type":"number"}},"status":{"type":"number","enum":[0,2,3,4,5,6,7,8]},"category":{"type":"number","enum":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]},"themes":{"type":"array","items":{"type":"number"}},"gameModes":{"type":"array","items":{"type":"number"}},"platforms":{"type":"array","items":{"type":"number"}},"genres":{"type":"array","items":{"type":"number"}},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}}},"FindStatisticsTrendingGamesDto":{"type":"object","properties":{"criteria":{"$ref":"#/components/schemas/GameRepositoryFilterDto"},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"ActivityStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"activity":{"$ref":"#/components/schemas/Activity"},"activityId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","activity","activityId","id","viewsCount","likesCount"]},"ReviewComment":{"type":"object","properties":{"review":{"$ref":"#/components/schemas/Review"},"reviewId":{"type":"string"},"id":{"type":"string"},"content":{"type":"string","description":"HTML content of the user's comment."},"profile":{"description":"Author of this comment","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string","description":"User id of the author of this comment"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["review","reviewId","id","content","profile","profileUserId","createdAt","updatedAt"]},"CommentStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"reviewComment":{"$ref":"#/components/schemas/ReviewComment"},"reviewCommentId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","reviewComment","reviewCommentId","id","viewsCount","likesCount"]},"UserLike":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/GameStatistics"}]},"gameStatisticsId":{"type":"number","nullable":true},"reviewStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewStatistics"}]},"reviewStatisticsId":{"type":"number","nullable":true},"activityStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ActivityStatistics"}]},"activityStatisticsId":{"type":"number","nullable":true},"commentStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CommentStatistics"}]},"commentStatisticsId":{"type":"number","nullable":true}},"required":["id","profile","profileUserId","createdAt","updatedAt","gameStatistics","gameStatisticsId","reviewStatistics","reviewStatisticsId","activityStatistics","activityStatisticsId","commentStatistics","commentStatisticsId"]},"ReviewStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"review":{"$ref":"#/components/schemas/Review"},"reviewId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","review","reviewId","id","viewsCount","likesCount"]},"UserView":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/GameStatistics"}]},"reviewStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewStatistics"}]},"activityStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ActivityStatistics"}]},"commentStatistics":{"type":"object"}},"required":["id","profileUserId","createdAt","updatedAt","gameStatistics","reviewStatistics","activityStatistics","commentStatistics"]},"GameStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","game","gameId","id","viewsCount","likesCount"]},"GameStatisticsPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameStatistics"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindStatisticsTrendingReviewsDto":{"type":"object","properties":{"reviewId":{"type":"string","description":"Usually, this property should not be used unless a specific review needs to be retrieved, and it's easier to just\ncall the statistics controller."},"gameId":{"type":"number"},"userId":{"type":"string","minLength":36},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"ReviewStatisticsPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReviewStatistics"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindStatisticsTrendingActivitiesDto":{"type":"object","properties":{"activityId":{"type":"string","description":"Usually, this property should not be used unless a specific activity needs to be retrieved, and it's easier to just\ncall the statistics controller.","minLength":36},"userId":{"type":"string","minLength":36},"activityType":{"type":"string","enum":["REVIEW","FOLLOW","COLLECTION_ENTRY"]},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"StatisticsStatus":{"type":"object","properties":{"isLiked":{"type":"boolean"},"isViewed":{"type":"boolean"}},"required":["isLiked","isViewed"]},"ImporterWatchNotification":{"type":"object","properties":{"id":{"type":"number"},"library":{"$ref":"#/components/schemas/Library"},"libraryUserId":{"type":"string"},"source":{"type":"string","enum":["steam"]},"games":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}}},"required":["id","library","libraryUserId","source","games"]},"Notification":{"type":"object","properties":{"id":{"type":"number"},"sourceType":{"enum":["game","review","activity","profile","importer","report"],"type":"string"},"category":{"description":"What this notification's about. E.g.: a new like, a new follower, a game launch, etc.","enum":["follow","like","comment","watch","alert"],"type":"string"},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"reviewId":{"type":"string","nullable":true},"game":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Game"}]},"gameId":{"type":"number","nullable":true},"activity":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Activity"}]},"activityId":{"type":"string","nullable":true},"profile":{"nullable":true,"description":"User responsible for generating this notification (e.g. user that liked a review).","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string","nullable":true,"description":"User responsible for generating this notification (e.g. user that liked a review).\nWhen null/undefined, the notification was generated by the 'system'."},"importerNotification":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ImporterWatchNotification"}]},"importerNotificationId":{"type":"number"},"report":{"type":"object"},"reportId":{"type":"number","nullable":true},"isViewed":{"type":"boolean"},"targetProfile":{"nullable":true,"description":"User which is the target for this notification.
\nIf this is empty (null/undefined), the notification is targeted at all users.
\nNot to be confused with the 'profile' property.","allOf":[{"$ref":"#/components/schemas/Profile"}]},"targetProfileUserId":{"type":"string","nullable":true,"description":"User which is the target for this notification.
\nIf this is empty (null/undefined), the notification is targeted at all users.
\nNot to be confused with the 'profile' property."},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","sourceType","category","review","reviewId","game","gameId","activity","activityId","profile","profileUserId","importerNotification","importerNotificationId","report","reportId","isViewed","targetProfile","targetProfileUserId","createdAt","updatedAt"]},"NotificationAggregateDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"category":{"type":"string","enum":["follow","like","comment","watch","alert"]},"sourceType":{"type":"string","enum":["game","review","activity","profile","importer","report"]},"notifications":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}},"required":["sourceId","category","sourceType","notifications"]},"PaginatedNotificationAggregationDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NotificationAggregateDto"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"NotificationViewUpdateDto":{"type":"object","properties":{"isViewed":{"type":"boolean"},"notificationIds":{"type":"array","items":{"type":"number"}}},"required":["isViewed","notificationIds"]},"GameExternalStoreDto":{"type":"object","properties":{"icon":{"type":"string","nullable":true,"description":"Icon representing said store/service."},"storeName":{"type":"string","nullable":true},"id":{"type":"number"},"uid":{"type":"string","description":"Corresponds to the game id on the target source (see GameExternalGameCategory).\nIt's called uid, not uuid."},"category":{"type":"number","enum":[1,5,10,11,13,14,15,20,22,23,26,28,29,30,31,32,36,37,54,55]},"media":{"type":"number","enum":[1,2]},"checksum":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"year":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameId":{"type":"number"}},"required":["icon","storeName","id","uid","createdAt","updatedAt","gameId"]},"GameRepositoryFindOneDto":{"type":"object","properties":{"relations":{"type":"object"}}},"GameRepositoryFindAllDto":{"type":"object","properties":{"gameIds":{"type":"array","items":{"type":"number"}},"relations":{"type":"object"}},"required":["gameIds"]},"GamePlaytime":{"type":"object","properties":{"id":{"type":"number"},"gameId":{"type":"number"},"game":{"$ref":"#/components/schemas/Game"},"sourceId":{"type":"number"},"timeMain":{"type":"number","nullable":true},"timePlus":{"type":"number","nullable":true},"time100":{"type":"number","nullable":true},"timeAll":{"type":"number","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","gameId","game","sourceId","timeMain","timePlus","time100","timeAll","createdAt","updatedAt"]},"AchievementDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"expGainAmount":{"type":"number"},"category":{"type":"number","enum":[0,1,2,3]}},"required":["id","name","description","expGainAmount","category"]},"PaginatedAchievementsResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AchievementDto"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"ObtainedAchievement":{"type":"object","properties":{"id":{"type":"number"},"achievementId":{"type":"string","description":"Achievement id specified in entries for achievements.data.ts"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"isFeatured":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","achievementId","profile","profileUserId","isFeatured","createdAt","updatedAt"]},"UpdateFeaturedObtainedAchievementDto":{"type":"object","properties":{"isFeatured":{"type":"boolean"}},"required":["isFeatured"]},"UserLevel":{"type":"object","properties":{"userId":{"type":"string","description":"Should be the same as the profile's UserId"},"profile":{"$ref":"#/components/schemas/Profile"},"currentLevel":{"type":"number"},"currentLevelExp":{"type":"number","description":"XP in the current user-level"},"levelUpExpCost":{"type":"number","description":"Threshold XP to hit the next user-level"},"expMultiplier":{"type":"number","description":"The multiplier to apply to all exp gains"}},"required":["userId","profile","currentLevel","currentLevelExp","levelUpExpCost","expMultiplier"]},"CreateUpdateCollectionEntryDto":{"type":"object","properties":{"finishedAt":{"type":"date-time"},"collectionIds":{"type":"array","items":{"type":"string"}},"gameId":{"type":"number"},"platformIds":{"type":"array","items":{"type":"number"}},"isFavorite":{"type":"boolean","default":false}},"required":["collectionIds","gameId","platformIds","isFavorite"]},"CreateFavoriteStatusCollectionEntryDto":{"type":"object","properties":{"isFavorite":{"type":"boolean","default":false}},"required":["isFavorite"]},"CollectionEntriesPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindCollectionEntriesDto":{"type":"object","properties":{"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}}},"ActivitiesFeedPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FollowStatusDto":{"type":"object","properties":{"isFollowing":{"type":"boolean"}},"required":["isFollowing"]},"FollowInfoRequestDto":{"type":"object","properties":{"criteria":{"type":"string","enum":["followers","following"]},"targetUserId":{"type":"string","minLength":36},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}},"required":["criteria","targetUserId"]},"FollowInfoResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FollowRegisterDto":{"type":"object","properties":{"followedUserId":{"type":"string","minLength":36}},"required":["followedUserId"]},"FollowRemoveDto":{"type":"object","properties":{"followedUserId":{"type":"string","minLength":36}},"required":["followedUserId"]},"ProfileStatisticsOverviewDto":{"type":"object","properties":{"totalGames":{"type":"number"},"totalCollections":{"type":"number"},"totalFinishedGames":{"type":"number"},"totalEstimatedPlaytime":{"type":"number","description":"Total playtime spent on finished games, based on available data and HLTB's 'main' profile."}},"required":["totalGames","totalCollections","totalFinishedGames","totalEstimatedPlaytime"]},"ImporterPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"ImporterStatusUpdateRequestDto":{"type":"object","properties":{"status":{"type":"string"},"externalGameId":{"type":"number"}},"required":["status","externalGameId"]},"FindAvailableConnectionsResponseDto":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["steam"]},"isImporterViable":{"type":"boolean"},"iconName":{"type":"string"}},"required":["name","type","isImporterViable","iconName"]},"UserConnection":{"type":"object","properties":{"id":{"type":"number"},"type":{"type":"string","enum":["steam"]},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"sourceUserId":{"type":"string"},"sourceUsername":{"type":"string"},"isImporterViable":{"type":"boolean","description":"If this connection can be used by the 'importer' system."},"isImporterEnabled":{"type":"boolean"}},"required":["id","type","profile","profileUserId","sourceUserId","sourceUsername","isImporterViable","isImporterEnabled"]},"ConnectionCreateDto":{"type":"object","properties":{"type":{"type":"string","enum":["steam"]},"userIdentifier":{"type":"string","description":"A string representing a username, user id or profile URL for the target connection
\ne.g. a Steam's profile URL","minLength":1},"isImporterEnabled":{"type":"boolean","default":false}},"required":["type","userIdentifier","isImporterEnabled"]},"FindAllCommentsDto":{"type":"object","properties":{"sourceId":{"type":"string","minLength":36},"sourceType":{"type":"string","enum":["review"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}},"required":["sourceId","sourceType"]},"FindCommentsPaginatedResponseDto":{"type":"object","properties":{"data":{"default":[],"type":"array","items":{"$ref":"#/components/schemas/ReviewComment"}},"pagination":{"default":{},"allOf":[{"$ref":"#/components/schemas/PaginationInfo"}]}},"required":["data","pagination"]},"CreateCommentDto":{"type":"object","properties":{"sourceId":{"type":"string","description":"UUID of the target entity. Comments can only be attributed to\nUUID based entities.","minLength":36},"sourceType":{"type":"string","enum":["review"]},"content":{"type":"string","minLength":1}},"required":["sourceId","sourceType","content"]},"UpdateCommentDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review"]},"content":{"type":"string","minLength":1}},"required":["sourceType","content"]},"DeleteCommentDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review"]}},"required":["sourceType"]},"Report":{"type":"object","properties":{"id":{"type":"number"},"sourceType":{"description":"Indexed to improve speed when filtering by type.","enum":["review","profile","review_comment"],"type":"string"},"category":{"enum":["spam","personal"],"type":"string"},"targetReview":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"targetReviewId":{"type":"string","nullable":true},"targetReviewComment":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewComment"}]},"targetReviewCommentId":{"type":"string","nullable":true},"targetProfile":{"description":"Profile that is being target of a report","allOf":[{"$ref":"#/components/schemas/Profile"}]},"targetProfileUserId":{"type":"string"},"reason":{"type":"string","nullable":true,"description":"User-submitted reason for report."},"profile":{"description":"User responsible for report.","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string"},"isClosed":{"type":"boolean"},"closeHandleAction":{"nullable":true,"description":"Action taken when closing this report","enum":["discard","alert","suspend","ban"],"type":"string"},"closeProfile":{"nullable":true,"description":"User responsible for closing this report","allOf":[{"$ref":"#/components/schemas/Profile"}]},"closeProfileUserId":{"type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","sourceType","category","targetReview","targetReviewId","targetReviewComment","targetReviewCommentId","targetProfile","targetProfileUserId","reason","profile","profileUserId","isClosed","closeHandleAction","closeProfile","closeProfileUserId","createdAt","updatedAt"]},"PaginatedReportResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Report"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"CreateReportRequestDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review","profile","review_comment"]},"sourceId":{"type":"string","minLength":36},"category":{"type":"string","enum":["spam","personal"]},"reason":{"type":"string"}},"required":["sourceType","sourceId","category"]},"HandleReportRequestDto":{"type":"object","properties":{"action":{"type":"string","enum":["discard","alert","suspend","ban"]},"deleteReportedContent":{"type":"boolean","default":true}},"required":["action","deleteReportedContent"]}}}} \ No newline at end of file +{"openapi":"3.0.0","paths":{"/v1/auth/logout":{"get":{"operationId":"AuthController_logout","parameters":[],"responses":{"200":{"description":""}},"tags":["auth"]}},"/v1/libraries":{"get":{"operationId":"LibrariesController_findOwn","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Library"}}}}},"tags":["libraries"]}},"/v1/libraries/{id}":{"get":{"operationId":"LibrariesController_findOneByIdWithPermissions","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Library"}}}}},"tags":["libraries"]}},"/v1/collections/{id}":{"get":{"operationId":"CollectionsController_findOneByIdWithPermissions","summary":"","description":"Returns a collection which the user has access to\n\n(Either its own collection or a public one)","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Collection"}}}}},"tags":["collections"]},"patch":{"operationId":"CollectionsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCollectionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["collections"]},"delete":{"operationId":"CollectionsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["collections"]}},"/v1/collections/library/{userId}":{"get":{"operationId":"CollectionsController_findAllByUserIdWithPermissions","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}}}}}},"tags":["collections"]}},"/v1/collections":{"post":{"operationId":"CollectionsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCollectionDto"}}}},"responses":{"201":{"description":""}},"tags":["collections"]}},"/v1/reviews":{"post":{"operationId":"ReviewsController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviewDto"}}}},"responses":{"201":{"description":""}},"tags":["reviews"]},"get":{"operationId":"ReviewsController_findOneByUserIdAndGameId","parameters":[{"name":"id","required":true,"in":"query","schema":{"type":"string"}},{"name":"gameId","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}}},"tags":["reviews"]}},"/v1/reviews/all":{"post":{"operationId":"ReviewsController_findAllById","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllReviewsByIdDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Review"}}}}}},"tags":["reviews"]}},"/v1/reviews/score":{"get":{"operationId":"ReviewsController_getScoreForGameId","parameters":[{"name":"gameId","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewScoreResponseDto"}}}}},"tags":["reviews"]}},"/v1/reviews/profile/{userId}":{"get":{"operationId":"ReviewsController_findAllByUserId","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindReviewPaginatedDto"}}}}},"tags":["reviews"]}},"/v1/reviews/game/{id}":{"get":{"operationId":"ReviewsController_findAllByGameId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindReviewPaginatedDto"}}}}},"tags":["reviews"]}},"/v1/reviews/{id}":{"get":{"operationId":"ReviewsController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}}}},"tags":["reviews"]},"delete":{"operationId":"ReviewsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reviews"]}},"/v1/profile":{"patch":{"operationId":"ProfileController_update","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProfileDto"}}}},"responses":{"200":{"description":""}},"tags":["profile"]},"get":{"operationId":"ProfileController_findOwn","summary":"","description":"Used to access own profile","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}}},"tags":["profile"]}},"/v1/profile/image":{"put":{"operationId":"ProfileController_updateImage","parameters":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UpdateProfileImageDto"}}}},"responses":{"200":{"description":""}},"tags":["profile"]}},"/v1/profile/{id}":{"get":{"operationId":"ProfileController_findOneById","summary":"","description":"Used to access other users' profiles","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}}},"tags":["profile"]}},"/v1/activities":{"get":{"operationId":"ActivitiesRepositoryController_findLatest","parameters":[{"name":"userId","required":false,"in":"query","schema":{"minLength":36,"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesPaginatedResponseDto"}}}}},"tags":["activities"]}},"/v1/statistics/queue/like":{"post":{"operationId":"StatisticsQueueController_addLike","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"201":{"description":""}},"tags":["statistics-queue"]},"delete":{"operationId":"StatisticsQueueController_removeLike","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"200":{"description":""}},"tags":["statistics-queue"]}},"/v1/statistics/queue/view":{"post":{"operationId":"StatisticsQueueController_addView","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsActionDto"}}}},"responses":{"201":{"description":""}},"tags":["statistics-queue"]}},"/v1/statistics":{"post":{"operationId":"StatisticsController_findOneBySourceIdAndType","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindOneStatisticsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/games":{"post":{"operationId":"StatisticsController_findTrendingGames","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingGamesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/reviews":{"post":{"operationId":"StatisticsController_findTrendingReviews","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingReviewsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/trending/activities":{"post":{"operationId":"StatisticsController_findTrendingActivities","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindStatisticsTrendingActivitiesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStatisticsPaginatedResponseDto"}}}}},"tags":["statistics"]}},"/v1/statistics/status":{"get":{"operationId":"StatisticsController_getStatus","parameters":[{"name":"statisticsId","required":true,"in":"query","schema":{"type":"number"}},{"name":"sourceType","required":true,"in":"query","schema":{"enum":["game","review","activity","review_comment"],"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatisticsStatus"}}}}},"tags":["statistics"]}},"/v1/notifications":{"get":{"operationId":"NotificationsController_findAllAndAggregate","parameters":[{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedNotificationAggregationDto"}}}}},"tags":["notifications"]}},"/v1/notifications/new":{"get":{"operationId":"NotificationsController_getNewNotifications","summary":"","description":"Finds new notifications that have been created after last checked time.
\nReturns an empty array on first connection.","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}}}}},"tags":["notifications"]}},"/v1/notifications/view":{"put":{"operationId":"NotificationsController_updateViewedStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationViewUpdateDto"}}}},"responses":{"200":{"description":""}},"tags":["notifications"]}},"/v1/game/repository/resource":{"get":{"operationId":"GameRepositoryController_getResource","parameters":[{"name":"resourceName","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}/platforms/icon":{"get":{"operationId":"GameRepositoryController_getIconNamesForPlatformAbbreviations","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}/external-stores":{"get":{"operationId":"GameRepositoryController_getExternalStoresForGameId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalStoreDto"}}}}}},"tags":["game-repository"]}},"/v1/game/repository/{id}":{"post":{"operationId":"GameRepositoryController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameRepositoryFindOneDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Game"}}}}},"tags":["game-repository"]}},"/v1/game/repository":{"post":{"operationId":"GameRepositoryController_findAllByIds","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameRepositoryFindAllDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}}}}},"tags":["game-repository"]}},"/v1/sync/hltb/{gameId}":{"get":{"operationId":"HltbController_findPlaytimeForGameId","parameters":[{"name":"gameId","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GamePlaytime"}}}}},"tags":["sync-hltb"]}},"/v1/achievements":{"get":{"operationId":"AchievementsController_getAchievements","parameters":[{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAchievementsResponseDto"}}}}},"tags":["achievements"]}},"/v1/achievements/obtained/{id}":{"get":{"operationId":"AchievementsController_getObtainedAchievement","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"targetUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObtainedAchievement"}}}}},"tags":["achievements"]}},"/v1/achievements/obtained":{"get":{"operationId":"AchievementsController_getAllObtainedAchievements","parameters":[{"name":"targetUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ObtainedAchievement"}}}}}},"tags":["achievements"]}},"/v1/achievements/{userId}/featured":{"get":{"operationId":"AchievementsController_getFeaturedAchievementForUserId","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObtainedAchievement"}}}}},"tags":["achievements"]}},"/v1/achievements/obtained/{id}/featured":{"put":{"operationId":"AchievementsController_updateFeaturedObtainedAchievement","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFeaturedObtainedAchievementDto"}}}},"responses":{"200":{"description":""}},"tags":["achievements"]}},"/v1/level/{userId}":{"get":{"operationId":"LevelController_findOne","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLevel"}}}}},"tags":["level"]}},"/v1/collections-entries":{"post":{"operationId":"CollectionsEntriesController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUpdateCollectionEntryDto"}}}},"responses":{"201":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/{id}":{"get":{"operationId":"CollectionsEntriesController_findEntryById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntry"}}}}},"tags":["collections-entries"]},"delete":{"operationId":"CollectionsEntriesController_deleteOwnEntry","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/game/{id}":{"get":{"operationId":"CollectionsEntriesController_findOwnEntryByGameId","summary":"","description":"Returns a specific collection entry based on game ID","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntry"}}}},"400":{"description":"Invalid query"}},"tags":["collections-entries"]}},"/v1/collections-entries/{id}/platforms/icons":{"get":{"operationId":"CollectionsEntriesController_getIconsForOwnedPlatforms","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/game/{id}/favorite":{"post":{"operationId":"CollectionsEntriesController_changeFavoriteStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFavoriteStatusCollectionEntryDto"}}}},"responses":{"204":{"description":""}},"tags":["collections-entries"]}},"/v1/collections-entries/library/{id}":{"get":{"operationId":"CollectionsEntriesController_findAllByLibraryId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/library/{id}/favorites":{"get":{"operationId":"CollectionsEntriesController_findFavoritesByLibraryId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/collections-entries/collection/{id}":{"post":{"operationId":"CollectionsEntriesController_findAllByCollectionId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindCollectionEntriesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionEntriesPaginatedResponseDto"}}}}},"tags":["collections-entries"]}},"/v1/health":{"get":{"operationId":"HealthController_health","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["health"]}},"/v1/activities/feed":{"get":{"operationId":"ActivitiesFeedController_buildActivitiesFeed","parameters":[{"name":"criteria","required":true,"in":"query","schema":{"enum":["following","all"],"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesFeedPaginatedResponseDto"}}}}},"tags":["activities-feed"]}},"/v1/follow/status":{"get":{"operationId":"FollowController_getFollowerStatus","parameters":[{"name":"followerUserId","required":true,"in":"query","schema":{"type":"string"}},{"name":"followedUserId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowStatusDto"}}}}},"tags":["follow"]}},"/v1/follow/{id}":{"get":{"operationId":"FollowController_getUserFollowById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserFollow"}}}}},"tags":["follow"]}},"/v1/follow/info":{"post":{"operationId":"FollowController_getFollowInfo","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowInfoRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowInfoResponseDto"}}}}},"tags":["follow"]}},"/v1/follow":{"post":{"operationId":"FollowController_registerFollow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRegisterDto"}}}},"responses":{"201":{"description":""}},"tags":["follow"]},"delete":{"operationId":"FollowController_removeFollow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRemoveDto"}}}},"responses":{"200":{"description":""}},"tags":["follow"]}},"/v1/profile/statistics/overview/{userId}":{"get":{"operationId":"ProfileStatisticsController_getStatsOverview","summary":"","description":"Retrieves basic stats for a user profile","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileStatisticsOverviewDto"}}}}},"tags":["profile-statistics"]}},"/v1/profile/statistics/distribution/{userId}":{"get":{"operationId":"ProfileStatisticsController_getStatsDistribution","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}},{"name":"by","required":true,"in":"query","schema":{"enum":["release_year","finish_year"],"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileStatisticsDistributionResponseDto"}}}}},"tags":["profile-statistics"]}},"/v1/importer/watch/notification/{id}":{"get":{"operationId":"ImporterWatchController_findNotification","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterWatchNotification"}}}}},"tags":["importer-watch"]}},"/v1/importer/{source}":{"get":{"operationId":"ImporterController_findUnprocessedEntries","parameters":[{"name":"source","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterPaginatedResponseDto"}}}}},"tags":["importer"]}},"/v1/importer/status":{"post":{"operationId":"ImporterController_changeStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImporterStatusUpdateRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["importer"]}},"/v1/connections":{"get":{"operationId":"ConnectionsController_findAvailableConnections","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FindAvailableConnectionsResponseDto"}}}}}},"tags":["connections"]},"post":{"operationId":"ConnectionsController_createOrUpdate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionCreateDto"}}}},"responses":{"201":{"description":""}},"tags":["connections"]}},"/v1/connections/own":{"get":{"operationId":"ConnectionsController_findOwn","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserConnection"}}}}}},"tags":["connections"]}},"/v1/connections/own/{type}":{"get":{"operationId":"ConnectionsController_findOwnByType","parameters":[{"name":"type","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserConnection"}}}}},"tags":["connections"]}},"/v1/connections/{id}":{"delete":{"operationId":"ConnectionsController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["connections"]}},"/v1/comment":{"post":{"operationId":"CommentController_findAll","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindAllCommentsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindCommentsPaginatedResponseDto"}}}}},"tags":["comment"]}},"/v1/comment/{sourceType}/{id}":{"get":{"operationId":"CommentController_findOneById","parameters":[{"name":"sourceType","required":true,"in":"path","schema":{"type":"string"}},{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewComment"}}}}},"tags":["comment"]}},"/v1/comment/create":{"post":{"operationId":"CommentController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentDto"}}}},"responses":{"201":{"description":""}},"tags":["comment"]}},"/v1/comment/{id}":{"patch":{"operationId":"CommentController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCommentDto"}}}},"responses":{"204":{"description":""}},"tags":["comment"]},"delete":{"operationId":"CommentController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteCommentDto"}}}},"responses":{"200":{"description":""}},"tags":["comment"]}},"/v1/report":{"get":{"operationId":"ReportController_findAllByLatest","parameters":[{"name":"includeClosed","required":false,"in":"query","schema":{"default":false,"type":"boolean"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedReportResponseDto"}}}}},"tags":["report"]},"post":{"operationId":"ReportController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["report"]}},"/v1/report/{id}":{"get":{"operationId":"ReportController_findOneById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}}}},"tags":["report"]}},"/v1/report/{id}/handle":{"post":{"operationId":"ReportController_handle","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandleReportRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["report"]}}},"info":{"title":"GameNode API","description":"API docs for the videogame catalog system GameNode.

Built with love by the GameNode team.","version":"1.0","contact":{}},"tags":[],"servers":[],"components":{"schemas":{"Library":{"type":"object","properties":{"userId":{"type":"string","description":"@description The primary key of the library entity.\nAlso used to share the library with other users.\n\nSame as SuperTokens' userId."},"collections":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["userId","collections","createdAt","updatedAt"]},"GameCover":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameCollection":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"checksum":{"type":"string"},"url":{"type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}},"required":["id","name","slug","createdAt","updatedAt","checksum","url","games"]},"GameAlternativeName":{"type":"object","properties":{"id":{"type":"number"},"comment":{"type":"string"},"name":{"type":"string"},"checksum":{"type":"string"},"game":{"$ref":"#/components/schemas/Game"}},"required":["id","game"]},"GameArtwork":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameScreenshot":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["game","id"]},"GameLocalization":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameMode":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameGenre":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameTheme":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","createdAt","updatedAt"]},"GamePlayerPerspective":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameEngineLogo":{"type":"object","properties":{"engine":{"$ref":"#/components/schemas/GameEngine"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["engine","id"]},"GameCompanyLogo":{"type":"object","properties":{"company":{"$ref":"#/components/schemas/GameCompany"},"id":{"type":"number"},"alphaChannel":{"type":"boolean"},"animated":{"type":"boolean"},"height":{"type":"number"},"imageId":{"type":"string"},"url":{"type":"string"},"width":{"type":"number"},"checksum":{"type":"string"}},"required":["company","id"]},"GameCompany":{"type":"object","properties":{"id":{"type":"number"},"changeDate":{"format":"date-time","type":"string"},"changeDateCategory":{"type":"string"},"changedCompany":{"$ref":"#/components/schemas/GameCompany"},"checksum":{"type":"string"},"country":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"description":{"type":"string"},"logo":{"$ref":"#/components/schemas/GameCompanyLogo"},"name":{"type":"string"},"parent":{"$ref":"#/components/schemas/GameCompany"},"slug":{"type":"string"},"startDate":{"format":"date-time","type":"string"},"startDateCategory":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"url":{"type":"string"}},"required":["id","createdAt","name","slug","updatedAt"]},"GamePlatform":{"type":"object","properties":{"id":{"type":"number"},"abbreviation":{"type":"string"},"alternative_name":{"type":"string"},"category":{"type":"number","enum":[1,2,3,4,5,6]},"checksum":{"type":"string"},"generation":{"type":"number"},"name":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"collectionEntries":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}}},"required":["id","abbreviation","alternative_name","category","checksum","generation","name","createdAt","updatedAt","games","collectionEntries"]},"GameEngine":{"type":"object","properties":{"logo":{"$ref":"#/components/schemas/GameEngineLogo"},"companies":{"type":"array","items":{"$ref":"#/components/schemas/GameCompany"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["logo","companies","platforms","games","id","createdAt","updatedAt"]},"GameKeyword":{"type":"object","properties":{"game":{"$ref":"#/components/schemas/Game"},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["game","id","createdAt","updatedAt"]},"GameFranchise":{"type":"object","properties":{"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"id":{"type":"number"},"checksum":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["games","id","createdAt","updatedAt"]},"GameExternalGame":{"type":"object","properties":{"id":{"type":"number"},"uid":{"type":"string","description":"Corresponds to the game id on the target source (see GameExternalGameCategory).\nIt's called uid, not uuid."},"category":{"type":"number","enum":[1,5,10,11,13,14,15,20,22,23,26,28,29,30,31,32,36,37,54,55]},"media":{"type":"number","enum":[1,2]},"checksum":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"year":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"}},"required":["id","uid","createdAt","updatedAt","game","gameId"]},"GameInvolvedCompany":{"type":"object","properties":{"id":{"type":"number"},"checksum":{"type":"string"},"company":{"$ref":"#/components/schemas/GameCompany"},"companyId":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"developer":{"type":"boolean"},"porting":{"type":"boolean"},"publisher":{"type":"boolean"},"supporting":{"type":"boolean"},"updatedAt":{"format":"date-time","type":"string"},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}},"required":["id","company","companyId","createdAt","developer","porting","publisher","supporting","updatedAt","games"]},"Game":{"type":"object","properties":{"id":{"type":"number","description":"Should be mapped to the IGDB ID of the game."},"name":{"type":"string"},"slug":{"type":"string"},"aggregatedRating":{"type":"number"},"aggregatedRatingCount":{"type":"number"},"category":{"enum":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14],"type":"number"},"status":{"enum":[0,2,3,4,5,6,7,8],"type":"number"},"summary":{"type":"string"},"storyline":{"type":"string"},"checksum":{"type":"string"},"url":{"type":"string"},"firstReleaseDate":{"format":"date-time","type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"dlcs":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"dlcOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expansions":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expansionOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expandedGames":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"expandedGameOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"similarGames":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"similarGameOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remakes":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remakeOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remasters":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"remasterOf":{"type":"array","items":{"$ref":"#/components/schemas/Game"}},"cover":{"$ref":"#/components/schemas/GameCover"},"collection":{"$ref":"#/components/schemas/GameCollection"},"alternativeNames":{"type":"array","items":{"$ref":"#/components/schemas/GameAlternativeName"}},"artworks":{"type":"array","items":{"$ref":"#/components/schemas/GameArtwork"}},"screenshots":{"type":"array","items":{"$ref":"#/components/schemas/GameScreenshot"}},"gameLocalizations":{"type":"array","items":{"$ref":"#/components/schemas/GameLocalization"}},"gameModes":{"type":"array","items":{"$ref":"#/components/schemas/GameMode"}},"genres":{"type":"array","items":{"$ref":"#/components/schemas/GameGenre"}},"themes":{"type":"array","items":{"$ref":"#/components/schemas/GameTheme"}},"playerPerspectives":{"type":"array","items":{"$ref":"#/components/schemas/GamePlayerPerspective"}},"gameEngines":{"type":"array","items":{"$ref":"#/components/schemas/GameEngine"}},"keywords":{"type":"array","items":{"$ref":"#/components/schemas/GameKeyword"}},"franchises":{"type":"array","items":{"$ref":"#/components/schemas/GameFranchise"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"externalGames":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}},"involvedCompanies":{"type":"array","items":{"$ref":"#/components/schemas/GameInvolvedCompany"}},"source":{"type":"string","description":"Oh dear maintainer, please forgive me for using transient fields.","default":"MYSQL","enum":["MYSQL","MANTICORE"]}},"required":["id","name","slug","category","status","summary","storyline","checksum","url","firstReleaseDate","createdAt","updatedAt","involvedCompanies","source"]},"ProfileAvatar":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"mimetype":{"type":"string"},"extension":{"type":"string"},"size":{"type":"number"},"filename":{"type":"string"},"encoding":{"type":"string"}},"required":["id","profile","createdAt","updatedAt","mimetype","extension","size","filename","encoding"]},"ProfileBanner":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"mimetype":{"type":"string"},"extension":{"type":"string"},"size":{"type":"number"},"filename":{"type":"string"},"encoding":{"type":"string"}},"required":["id","profile","createdAt","updatedAt","mimetype","extension","size","filename","encoding"]},"Profile":{"type":"object","properties":{"userId":{"type":"string","description":"Shareable string ID\n\nSame as SuperTokens' userId."},"username":{"type":"string"},"bio":{"type":"string"},"avatar":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ProfileAvatar"}]},"banner":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ProfileBanner"}]},"usernameLastUpdatedAt":{"format":"date-time","type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["userId","username","bio","avatar","banner","usernameLastUpdatedAt","createdAt","updatedAt"]},"Review":{"type":"object","properties":{"id":{"type":"string"},"content":{"type":"string","nullable":true},"rating":{"type":"number"},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"collectionEntry":{"$ref":"#/components/schemas/CollectionEntry"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","content","rating","game","gameId","profile","profileUserId","collectionEntry","createdAt","updatedAt"]},"CollectionEntry":{"type":"object","properties":{"id":{"type":"string"},"collections":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"ownedPlatforms":{"description":"The platforms on which the user owns the game.","type":"array","items":{"$ref":"#/components/schemas/GamePlatform"}},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"isFavorite":{"type":"boolean"},"finishedAt":{"format":"date-time","type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","collections","game","gameId","ownedPlatforms","review","isFavorite","finishedAt","createdAt","updatedAt"]},"Collection":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"isPublic":{"type":"boolean"},"library":{"$ref":"#/components/schemas/Library"},"libraryUserId":{"type":"string"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}},"isFeatured":{"type":"boolean"},"isFinished":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","name","description","isPublic","library","libraryUserId","entries","isFeatured","isFinished","createdAt","updatedAt"]},"CreateCollectionDto":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"isPublic":{"type":"boolean"},"isFeatured":{"type":"boolean"},"isFinished":{"type":"boolean"}},"required":["name","isPublic","isFeatured","isFinished"]},"UpdateCollectionDto":{"type":"object","properties":{}},"CreateReviewDto":{"type":"object","properties":{"gameId":{"type":"number"},"content":{"type":"string","minLength":20},"rating":{"type":"number","minimum":0,"maximum":5}},"required":["gameId","content","rating"]},"FindAllReviewsByIdDto":{"type":"object","properties":{"reviewsIds":{"type":"array","items":{"type":"string"}}},"required":["reviewsIds"]},"ReviewScoreDistribution":{"type":"object","properties":{"1":{"type":"number"},"2":{"type":"number"},"3":{"type":"number"},"4":{"type":"number"},"5":{"type":"number"},"total":{"type":"number","description":"Total number of reviews"}},"required":["1","2","3","4","5","total"]},"ReviewScoreResponseDto":{"type":"object","properties":{"median":{"type":"number"},"distribution":{"$ref":"#/components/schemas/ReviewScoreDistribution"}},"required":["median","distribution"]},"PaginationInfo":{"type":"object","properties":{"totalItems":{"type":"number","description":"Total number of items available for the current query"},"totalPages":{"type":"number","description":"Total number of pages available for the current query"},"hasNextPage":{"type":"boolean","description":"If this query allows for a next page"}},"required":["totalItems","totalPages","hasNextPage"]},"FindReviewPaginatedDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Review"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"UpdateProfileDto":{"type":"object","properties":{"username":{"type":"string","minLength":4,"maxLength":20},"bio":{"type":"string","minLength":1,"maxLength":240}}},"UpdateProfileImageDto":{"type":"object","properties":{"type":{"type":"string","enum":["avatar","banner"]},"file":{"type":"object"}},"required":["type","file"]},"UserFollow":{"type":"object","properties":{"id":{"type":"number"},"follower":{"$ref":"#/components/schemas/Profile"},"followerUserId":{"type":"string"},"followed":{"$ref":"#/components/schemas/Profile"},"followedUserId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","follower","followerUserId","followed","followedUserId","createdAt","updatedAt"]},"Activity":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["REVIEW","FOLLOW","COLLECTION_ENTRY"]},"profile":{"description":"The associated profile with this Activity (e.g. user who performed an action)","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string"},"collectionEntry":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CollectionEntry"}]},"collectionEntryId":{"type":"string","nullable":true},"collection":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Collection"}]},"collectionId":{"type":"string","nullable":true},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"reviewId":{"type":"string","nullable":true},"userFollow":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/UserFollow"}]},"userFollowId":{"type":"number","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","type","profile","profileUserId","collectionEntry","collectionEntryId","collection","collectionId","review","reviewId","userFollow","userFollowId","createdAt","updatedAt"]},"ActivitiesPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"StatisticsActionDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"targetUserId":{"type":"string","minLength":36},"sourceType":{"enum":["game","review","activity","review_comment"],"type":"string"}},"required":["sourceId","sourceType"]},"FindOneStatisticsDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"sourceType":{"type":"string","enum":["game","review","activity","review_comment"]}},"required":["sourceId","sourceType"]},"GameRepositoryFilterDto":{"type":"object","properties":{"ids":{"description":"If this is supplied, filtering will be done only for entities specified here.
\nUseful to filter data received from entities which hold game ids (like GameStatistics, Reviews, etc.)","type":"array","items":{"type":"number"}},"status":{"type":"number","enum":[0,2,3,4,5,6,7,8]},"category":{"type":"number","enum":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]},"themes":{"type":"array","items":{"type":"number"}},"gameModes":{"type":"array","items":{"type":"number"}},"platforms":{"type":"array","items":{"type":"number"}},"genres":{"type":"array","items":{"type":"number"}},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}}},"FindStatisticsTrendingGamesDto":{"type":"object","properties":{"criteria":{"$ref":"#/components/schemas/GameRepositoryFilterDto"},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"ActivityStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"activity":{"$ref":"#/components/schemas/Activity"},"activityId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","activity","activityId","id","viewsCount","likesCount"]},"ReviewComment":{"type":"object","properties":{"review":{"$ref":"#/components/schemas/Review"},"reviewId":{"type":"string"},"id":{"type":"string"},"content":{"type":"string","description":"HTML content of the user's comment."},"profile":{"description":"Author of this comment","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string","description":"User id of the author of this comment"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["review","reviewId","id","content","profile","profileUserId","createdAt","updatedAt"]},"CommentStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"reviewComment":{"$ref":"#/components/schemas/ReviewComment"},"reviewCommentId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","reviewComment","reviewCommentId","id","viewsCount","likesCount"]},"UserLike":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/GameStatistics"}]},"gameStatisticsId":{"type":"number","nullable":true},"reviewStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewStatistics"}]},"reviewStatisticsId":{"type":"number","nullable":true},"activityStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ActivityStatistics"}]},"activityStatisticsId":{"type":"number","nullable":true},"commentStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CommentStatistics"}]},"commentStatisticsId":{"type":"number","nullable":true}},"required":["id","profile","profileUserId","createdAt","updatedAt","gameStatistics","gameStatisticsId","reviewStatistics","reviewStatisticsId","activityStatistics","activityStatisticsId","commentStatistics","commentStatisticsId"]},"ReviewStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"review":{"$ref":"#/components/schemas/Review"},"reviewId":{"type":"string"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","review","reviewId","id","viewsCount","likesCount"]},"UserView":{"type":"object","properties":{"id":{"type":"number"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/GameStatistics"}]},"reviewStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewStatistics"}]},"activityStatistics":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ActivityStatistics"}]},"commentStatistics":{"type":"object"}},"required":["id","profileUserId","createdAt","updatedAt","gameStatistics","reviewStatistics","activityStatistics","commentStatistics"]},"GameStatistics":{"type":"object","properties":{"views":{"type":"array","items":{"$ref":"#/components/schemas/UserView"}},"likes":{"type":"array","items":{"$ref":"#/components/schemas/UserLike"}},"game":{"$ref":"#/components/schemas/Game"},"gameId":{"type":"number"},"id":{"type":"number"},"viewsCount":{"type":"number"},"likesCount":{"type":"number"}},"required":["views","likes","game","gameId","id","viewsCount","likesCount"]},"GameStatisticsPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameStatistics"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindStatisticsTrendingReviewsDto":{"type":"object","properties":{"reviewId":{"type":"string","description":"Usually, this property should not be used unless a specific review needs to be retrieved, and it's easier to just\ncall the statistics controller."},"gameId":{"type":"number"},"userId":{"type":"string","minLength":36},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"ReviewStatisticsPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReviewStatistics"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindStatisticsTrendingActivitiesDto":{"type":"object","properties":{"activityId":{"type":"string","description":"Usually, this property should not be used unless a specific activity needs to be retrieved, and it's easier to just\ncall the statistics controller.","minLength":36},"userId":{"type":"string","minLength":36},"activityType":{"type":"string","enum":["REVIEW","FOLLOW","COLLECTION_ENTRY"]},"period":{"type":"string","enum":["day","week","month","quarter","half_year","year","all"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20}},"required":["period"]},"StatisticsStatus":{"type":"object","properties":{"isLiked":{"type":"boolean"},"isViewed":{"type":"boolean"}},"required":["isLiked","isViewed"]},"ImporterWatchNotification":{"type":"object","properties":{"id":{"type":"number"},"library":{"$ref":"#/components/schemas/Library"},"libraryUserId":{"type":"string"},"source":{"type":"string","enum":["steam"]},"games":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}}},"required":["id","library","libraryUserId","source","games"]},"Notification":{"type":"object","properties":{"id":{"type":"number"},"sourceType":{"enum":["game","review","activity","profile","importer","report"],"type":"string"},"category":{"description":"What this notification's about. E.g.: a new like, a new follower, a game launch, etc.","enum":["follow","like","comment","watch","alert"],"type":"string"},"review":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"reviewId":{"type":"string","nullable":true},"game":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Game"}]},"gameId":{"type":"number","nullable":true},"activity":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Activity"}]},"activityId":{"type":"string","nullable":true},"profile":{"nullable":true,"description":"User responsible for generating this notification (e.g. user that liked a review).","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string","nullable":true,"description":"User responsible for generating this notification (e.g. user that liked a review).\nWhen null/undefined, the notification was generated by the 'system'."},"importerNotification":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ImporterWatchNotification"}]},"importerNotificationId":{"type":"number"},"report":{"type":"object"},"reportId":{"type":"number","nullable":true},"isViewed":{"type":"boolean"},"targetProfile":{"nullable":true,"description":"User which is the target for this notification.
\nIf this is empty (null/undefined), the notification is targeted at all users.
\nNot to be confused with the 'profile' property.","allOf":[{"$ref":"#/components/schemas/Profile"}]},"targetProfileUserId":{"type":"string","nullable":true,"description":"User which is the target for this notification.
\nIf this is empty (null/undefined), the notification is targeted at all users.
\nNot to be confused with the 'profile' property."},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","sourceType","category","review","reviewId","game","gameId","activity","activityId","profile","profileUserId","importerNotification","importerNotificationId","report","reportId","isViewed","targetProfile","targetProfileUserId","createdAt","updatedAt"]},"NotificationAggregateDto":{"type":"object","properties":{"sourceId":{"oneOf":[{"type":"string"},{"type":"number"}]},"category":{"type":"string","enum":["follow","like","comment","watch","alert"]},"sourceType":{"type":"string","enum":["game","review","activity","profile","importer","report"]},"notifications":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}},"required":["sourceId","category","sourceType","notifications"]},"PaginatedNotificationAggregationDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NotificationAggregateDto"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"NotificationViewUpdateDto":{"type":"object","properties":{"isViewed":{"type":"boolean"},"notificationIds":{"type":"array","items":{"type":"number"}}},"required":["isViewed","notificationIds"]},"GameExternalStoreDto":{"type":"object","properties":{"icon":{"type":"string","nullable":true,"description":"Icon representing said store/service."},"storeName":{"type":"string","nullable":true},"id":{"type":"number"},"uid":{"type":"string","description":"Corresponds to the game id on the target source (see GameExternalGameCategory).\nIt's called uid, not uuid."},"category":{"type":"number","enum":[1,5,10,11,13,14,15,20,22,23,26,28,29,30,31,32,36,37,54,55]},"media":{"type":"number","enum":[1,2]},"checksum":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"year":{"type":"number"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"gameId":{"type":"number"}},"required":["icon","storeName","id","uid","createdAt","updatedAt","gameId"]},"GameRepositoryFindOneDto":{"type":"object","properties":{"relations":{"type":"object"}}},"GameRepositoryFindAllDto":{"type":"object","properties":{"gameIds":{"type":"array","items":{"type":"number"}},"relations":{"type":"object"}},"required":["gameIds"]},"GamePlaytime":{"type":"object","properties":{"id":{"type":"number"},"gameId":{"type":"number"},"game":{"$ref":"#/components/schemas/Game"},"sourceId":{"type":"number"},"timeMain":{"type":"number","nullable":true},"timePlus":{"type":"number","nullable":true},"time100":{"type":"number","nullable":true},"timeAll":{"type":"number","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","gameId","game","sourceId","timeMain","timePlus","time100","timeAll","createdAt","updatedAt"]},"AchievementDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"expGainAmount":{"type":"number"},"category":{"type":"number","enum":[0,1,2,3]}},"required":["id","name","description","expGainAmount","category"]},"PaginatedAchievementsResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AchievementDto"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"ObtainedAchievement":{"type":"object","properties":{"id":{"type":"number"},"achievementId":{"type":"string","description":"Achievement id specified in entries for achievements.data.ts"},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"isFeatured":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","achievementId","profile","profileUserId","isFeatured","createdAt","updatedAt"]},"UpdateFeaturedObtainedAchievementDto":{"type":"object","properties":{"isFeatured":{"type":"boolean"}},"required":["isFeatured"]},"UserLevel":{"type":"object","properties":{"userId":{"type":"string","description":"Should be the same as the profile's UserId"},"profile":{"$ref":"#/components/schemas/Profile"},"currentLevel":{"type":"number"},"currentLevelExp":{"type":"number","description":"XP in the current user-level"},"levelUpExpCost":{"type":"number","description":"Threshold XP to hit the next user-level"},"expMultiplier":{"type":"number","description":"The multiplier to apply to all exp gains"}},"required":["userId","profile","currentLevel","currentLevelExp","levelUpExpCost","expMultiplier"]},"CreateUpdateCollectionEntryDto":{"type":"object","properties":{"finishedAt":{"type":"date-time"},"collectionIds":{"type":"array","items":{"type":"string"}},"gameId":{"type":"number"},"platformIds":{"type":"array","items":{"type":"number"}},"isFavorite":{"type":"boolean","default":false}},"required":["collectionIds","gameId","platformIds","isFavorite"]},"CreateFavoriteStatusCollectionEntryDto":{"type":"object","properties":{"isFavorite":{"type":"boolean","default":false}},"required":["isFavorite"]},"CollectionEntriesPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CollectionEntry"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FindCollectionEntriesDto":{"type":"object","properties":{"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}}},"ActivitiesFeedPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FollowStatusDto":{"type":"object","properties":{"isFollowing":{"type":"boolean"}},"required":["isFollowing"]},"FollowInfoRequestDto":{"type":"object","properties":{"criteria":{"type":"string","enum":["followers","following"]},"targetUserId":{"type":"string","minLength":36},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}},"required":["criteria","targetUserId"]},"FollowInfoResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"FollowRegisterDto":{"type":"object","properties":{"followedUserId":{"type":"string","minLength":36}},"required":["followedUserId"]},"FollowRemoveDto":{"type":"object","properties":{"followedUserId":{"type":"string","minLength":36}},"required":["followedUserId"]},"ProfileStatisticsOverviewDto":{"type":"object","properties":{"totalGames":{"type":"number"},"totalCollections":{"type":"number"},"totalFinishedGames":{"type":"number"},"totalEstimatedPlaytime":{"type":"number","description":"Total playtime spent on finished games, based on available data and HLTB's 'main' profile."}},"required":["totalGames","totalCollections","totalFinishedGames","totalEstimatedPlaytime"]},"ProfileStatisticsDistributionResponseDto":{"type":"object","properties":{"distribution":{"type":"object"}},"required":["distribution"]},"ImporterPaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameExternalGame"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"ImporterStatusUpdateRequestDto":{"type":"object","properties":{"status":{"type":"string"},"externalGameId":{"type":"number"}},"required":["status","externalGameId"]},"FindAvailableConnectionsResponseDto":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["steam"]},"isImporterViable":{"type":"boolean"},"iconName":{"type":"string"}},"required":["name","type","isImporterViable","iconName"]},"UserConnection":{"type":"object","properties":{"id":{"type":"number"},"type":{"type":"string","enum":["steam"]},"profile":{"$ref":"#/components/schemas/Profile"},"profileUserId":{"type":"string"},"sourceUserId":{"type":"string"},"sourceUsername":{"type":"string"},"isImporterViable":{"type":"boolean","description":"If this connection can be used by the 'importer' system."},"isImporterEnabled":{"type":"boolean"}},"required":["id","type","profile","profileUserId","sourceUserId","sourceUsername","isImporterViable","isImporterEnabled"]},"ConnectionCreateDto":{"type":"object","properties":{"type":{"type":"string","enum":["steam"]},"userIdentifier":{"type":"string","description":"A string representing a username, user id or profile URL for the target connection
\ne.g. a Steam's profile URL","minLength":1},"isImporterEnabled":{"type":"boolean","default":false}},"required":["type","userIdentifier","isImporterEnabled"]},"FindAllCommentsDto":{"type":"object","properties":{"sourceId":{"type":"string","minLength":36},"sourceType":{"type":"string","enum":["review"]},"offset":{"type":"number","default":0},"limit":{"type":"number","default":20},"orderBy":{"type":"object"}},"required":["sourceId","sourceType"]},"FindCommentsPaginatedResponseDto":{"type":"object","properties":{"data":{"default":[],"type":"array","items":{"$ref":"#/components/schemas/ReviewComment"}},"pagination":{"default":{},"allOf":[{"$ref":"#/components/schemas/PaginationInfo"}]}},"required":["data","pagination"]},"CreateCommentDto":{"type":"object","properties":{"sourceId":{"type":"string","description":"UUID of the target entity. Comments can only be attributed to\nUUID based entities.","minLength":36},"sourceType":{"type":"string","enum":["review"]},"content":{"type":"string","minLength":1}},"required":["sourceId","sourceType","content"]},"UpdateCommentDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review"]},"content":{"type":"string","minLength":1}},"required":["sourceType","content"]},"DeleteCommentDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review"]}},"required":["sourceType"]},"Report":{"type":"object","properties":{"id":{"type":"number"},"sourceType":{"description":"Indexed to improve speed when filtering by type.","enum":["review","profile","review_comment"],"type":"string"},"category":{"enum":["spam","personal"],"type":"string"},"targetReview":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Review"}]},"targetReviewId":{"type":"string","nullable":true},"targetReviewComment":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/ReviewComment"}]},"targetReviewCommentId":{"type":"string","nullable":true},"targetProfile":{"description":"Profile that is being target of a report","allOf":[{"$ref":"#/components/schemas/Profile"}]},"targetProfileUserId":{"type":"string"},"reason":{"type":"string","nullable":true,"description":"User-submitted reason for report."},"profile":{"description":"User responsible for report.","allOf":[{"$ref":"#/components/schemas/Profile"}]},"profileUserId":{"type":"string"},"isClosed":{"type":"boolean"},"closeHandleAction":{"nullable":true,"description":"Action taken when closing this report","enum":["discard","alert","suspend","ban"],"type":"string"},"closeProfile":{"nullable":true,"description":"User responsible for closing this report","allOf":[{"$ref":"#/components/schemas/Profile"}]},"closeProfileUserId":{"type":"string","nullable":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","sourceType","category","targetReview","targetReviewId","targetReviewComment","targetReviewCommentId","targetProfile","targetProfileUserId","reason","profile","profileUserId","isClosed","closeHandleAction","closeProfile","closeProfileUserId","createdAt","updatedAt"]},"PaginatedReportResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Report"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}},"required":["data","pagination"]},"CreateReportRequestDto":{"type":"object","properties":{"sourceType":{"type":"string","enum":["review","profile","review_comment"]},"sourceId":{"type":"string","minLength":36},"category":{"type":"string","enum":["spam","personal"]},"reason":{"type":"string"}},"required":["sourceType","sourceId","category"]},"HandleReportRequestDto":{"type":"object","properties":{"action":{"type":"string","enum":["discard","alert","suspend","ban"]},"deleteReportedContent":{"type":"boolean","default":true}},"required":["action","deleteReportedContent"]}}}} \ No newline at end of file diff --git a/src/achievements/achievements.controller.ts b/src/achievements/achievements.controller.ts index 6d5f9c3..2598361 100644 --- a/src/achievements/achievements.controller.ts +++ b/src/achievements/achievements.controller.ts @@ -59,6 +59,12 @@ export class AchievementsController { ); } + @Get(":userId/featured") + @Public() + public getFeaturedAchievementForUserId(@Param("userId") userId: string) { + return this.achievementsService.getFeaturedAchievement(userId); + } + @Put("obtained/:id/featured") public updateFeaturedObtainedAchievement( @Session() session: SessionContainer, diff --git a/src/achievements/achievements.service.ts b/src/achievements/achievements.service.ts index e2184ce..f84917b 100644 --- a/src/achievements/achievements.service.ts +++ b/src/achievements/achievements.service.ts @@ -150,6 +150,13 @@ export class AchievementsService { }); } + async getFeaturedAchievement(userId: string) { + return await this.obtainedAchievementsRepository.findOneByOrFail({ + profileUserId: userId, + isFeatured: true, + }); + } + async updateFeaturedObtainedAchievement( userId: string, achievementId: string, diff --git a/src/profile/dto/create-profile.dto.ts b/src/profile/dto/create-profile.dto.ts index 9c533f2..2936842 100755 --- a/src/profile/dto/create-profile.dto.ts +++ b/src/profile/dto/create-profile.dto.ts @@ -5,7 +5,6 @@ export class CreateProfileDto { @Length(4, 20) @IsNotEmpty() username: string; - avatar: any; @IsString() @Length(1, 240) @IsOptional() diff --git a/src/profile/dto/update-profile-image.dto.ts b/src/profile/dto/update-profile-image.dto.ts new file mode 100644 index 0000000..56cefc3 --- /dev/null +++ b/src/profile/dto/update-profile-image.dto.ts @@ -0,0 +1,14 @@ +import { IsIn, IsNotEmpty } from "class-validator"; +import { ApiProperty } from "@nestjs/swagger"; + +export type ProfileImageIdentifier = "avatar" | "banner"; + +export class UpdateProfileImageDto { + file: any; + @ApiProperty({ + type: "string", + }) + @IsNotEmpty() + @IsIn(["avatar", "banner"]) + type: ProfileImageIdentifier; +} diff --git a/src/profile/entities/profile-avatar.entity.ts b/src/profile/entities/profile-avatar.entity.ts index 22beb96..1986167 100755 --- a/src/profile/entities/profile-avatar.entity.ts +++ b/src/profile/entities/profile-avatar.entity.ts @@ -1,5 +1,4 @@ import { - Column, CreateDateColumn, Entity, OneToOne, @@ -7,21 +6,12 @@ import { UpdateDateColumn, } from "typeorm"; import { Profile } from "./profile.entity"; +import { PersistedImageDetails } from "../../utils/persisted-image-details.entity"; @Entity() -export class ProfileAvatar { +export class ProfileAvatar extends PersistedImageDetails { @PrimaryGeneratedColumn() id: number; - @Column({ nullable: false }) - mimetype: string; - @Column({ nullable: false }) - extension: string; - @Column({ nullable: false }) - size: number; - @Column({ nullable: false }) - filename: string; - @Column({ nullable: false }) - encoding: string; @OneToOne(() => Profile, (profile) => profile.avatar) profile: Profile; @CreateDateColumn() diff --git a/src/profile/entities/profile-banner.entity.ts b/src/profile/entities/profile-banner.entity.ts new file mode 100644 index 0000000..14cbd93 --- /dev/null +++ b/src/profile/entities/profile-banner.entity.ts @@ -0,0 +1,21 @@ +import { + CreateDateColumn, + Entity, + OneToOne, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from "typeorm"; +import { PersistedImageDetails } from "../../utils/persisted-image-details.entity"; +import { Profile } from "./profile.entity"; + +@Entity() +export class ProfileBanner extends PersistedImageDetails { + @PrimaryGeneratedColumn() + id: number; + @OneToOne(() => Profile, (profile) => profile.avatar) + profile: Profile; + @CreateDateColumn() + createdAt: Date; + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/src/profile/entities/profile.entity.ts b/src/profile/entities/profile.entity.ts index f169698..f05a573 100755 --- a/src/profile/entities/profile.entity.ts +++ b/src/profile/entities/profile.entity.ts @@ -10,7 +10,13 @@ import { } from "typeorm"; import { ProfileAvatar } from "./profile-avatar.entity"; import { UserFollow } from "../../follow/entity/user-follow.entity"; +import { ProfileBanner } from "./profile-banner.entity"; +/** + * Profiles represent a user in the community scope. Unlike 'Library', they should be used by tables representing + * interactions with the GameNode community (e.g. a user like).
+ * Library's, Profile's and Supertokens' userIds are interchangeable. + */ @Entity() export class Profile { /** @@ -36,7 +42,12 @@ export class Profile { nullable: true, }) @JoinColumn() - avatar: ProfileAvatar; + avatar: ProfileAvatar | null; + @OneToOne(() => ProfileBanner, (banner) => banner.profile, { + nullable: true, + }) + @JoinColumn() + banner: ProfileBanner | null; @Column({ type: "timestamp", diff --git a/src/profile/profile.controller.ts b/src/profile/profile.controller.ts index d70cbbf..f20406c 100755 --- a/src/profile/profile.controller.ts +++ b/src/profile/profile.controller.ts @@ -9,6 +9,7 @@ import { FileTypeValidator, ParseFilePipe, UseGuards, + Put, } from "@nestjs/common"; import { ProfileService } from "./profile.service"; import { UpdateProfileDto } from "./dto/update-profile.dto"; @@ -19,23 +20,32 @@ import { SessionContainer } from "supertokens-node/recipe/session"; import { AuthGuard } from "../auth/auth.guard"; import { Profile } from "./entities/profile.entity"; import { Public } from "../auth/public.decorator"; +import { UpdateProfileImageDto } from "./dto/update-profile-image.dto"; +// No POST /profile endpoint @Controller("profile") @ApiTags("profile") @UseGuards(AuthGuard) export class ProfileController { constructor(private readonly profileService: ProfileService) {} - // No POST /profile endpoint - // Profiles are automatically created when a user registers (in the user-init module) - // If this fails, the findOneById() method has an uninitialized profile handler. - @Patch() - @ApiConsumes("multipart/form-data") - @UseInterceptors(FileInterceptor("avatar")) async update( @Session() session: SessionContainer, @Body() updateProfileDto: UpdateProfileDto, + ) { + return await this.profileService.update( + session.getUserId(), + updateProfileDto, + ); + } + + @Put("image") + @ApiConsumes("multipart/form-data") + @UseInterceptors(FileInterceptor("file")) + async updateImage( + @Session() session: SessionContainer, + @Body() updateImageDto: UpdateProfileImageDto, @UploadedFile( new ParseFilePipe({ fileIsRequired: false, @@ -46,12 +56,12 @@ export class ProfileController { ], }), ) - avatarFile?: Express.Multer.File, + file: Express.Multer.File, ) { - return await this.profileService.update( + await this.profileService.updateProfileImage( session.getUserId(), - updateProfileDto, - avatarFile, + updateImageDto, + file, ); } diff --git a/src/profile/profile.module.ts b/src/profile/profile.module.ts index 2fe6f45..c605aa4 100755 --- a/src/profile/profile.module.ts +++ b/src/profile/profile.module.ts @@ -4,9 +4,12 @@ import { ProfileController } from "./profile.controller"; import { TypeOrmModule } from "@nestjs/typeorm"; import { Profile } from "./entities/profile.entity"; import { ProfileAvatar } from "./entities/profile-avatar.entity"; +import { ProfileBanner } from "./entities/profile-banner.entity"; @Module({ - imports: [TypeOrmModule.forFeature([Profile, ProfileAvatar])], + imports: [ + TypeOrmModule.forFeature([Profile, ProfileAvatar, ProfileBanner]), + ], controllers: [ProfileController], providers: [ProfileService], exports: [ProfileService], diff --git a/src/profile/profile.service.ts b/src/profile/profile.service.ts index eafb970..f457b1c 100755 --- a/src/profile/profile.service.ts +++ b/src/profile/profile.service.ts @@ -10,21 +10,30 @@ import * as fs from "fs/promises"; import { generateUsername } from "unique-username-generator"; import mimetype from "mime-types"; import { filterBadWords } from "../utils/filterBadWords"; +import { + ProfileImageIdentifier, + UpdateProfileImageDto, +} from "./dto/update-profile-image.dto"; +import { ProfileBanner } from "./entities/profile-banner.entity"; + +const getImageFilePath = (filename: string, extension: string) => { + return `${publicImagesDir}/uploads/${filename}.${extension}`; +}; @Injectable() export class ProfileService { + private readonly ALLOWED_IMAGE_IDENTIFIERS = ["avatar", "banner"]; + private logger = new Logger(ProfileService.name); constructor( @InjectRepository(Profile) private profileRepository: Repository, @InjectRepository(ProfileAvatar) private profileAvatarRepository: Repository, + @InjectRepository(ProfileBanner) + private profileBannerRepository: Repository, ) {} - getAvatarFilePath(filename: string, extension: string) { - return `${publicImagesDir}/uploads/${filename}.${extension}`; - } - /** * Called at initial user registration * @param userId @@ -44,47 +53,80 @@ export class ProfileService { await this.profileRepository.insert(profile); } - async createAvatar(avatarFile: Express.Multer.File) { + private async persistImage( + type: ProfileImageIdentifier, + file: Express.Multer.File, + ) { const fileName = crypto.randomBytes(16).toString("hex"); - const fileExt = mimetype.extension(avatarFile.mimetype) || "jpeg"; + const fileExt = mimetype.extension(file.mimetype) || "jpeg"; - const filePath = this.getAvatarFilePath(fileName, fileExt); + const filePath = getImageFilePath(fileName, fileExt); try { - await fs.writeFile(filePath, avatarFile.buffer); + await fs.writeFile(filePath, file.buffer); } catch (e) { this.logger.error(e); - throw new HttpException("Error saving employee picture.", 500); + throw new HttpException("Error saving profile image.", 500); } - const profileAvatar = this.profileAvatarRepository.create({ - encoding: avatarFile.encoding, + + let targetRepository: Repository; + if (type === "avatar") { + targetRepository = this.profileAvatarRepository; + } else { + targetRepository = this.profileBannerRepository; + } + + const profileImage = targetRepository.create({ + encoding: file.encoding, filename: fileName, - mimetype: avatarFile.mimetype, + mimetype: file.mimetype, extension: fileExt, - size: avatarFile.size, + size: file.size, }); - return await this.profileAvatarRepository.save(profileAvatar); + return await targetRepository.save(profileImage); } - async detachAvatar(userId: string, removeFile = true) { - const avatar = await this.profileAvatarRepository.findOneBy({ - profile: { - userId, - }, - }); - if (!avatar) return; + private async detachImage( + userId: string, + type: ProfileImageIdentifier, + removeFile = true, + ) { + let targetEntity: ProfileAvatar | ProfileBanner; + let targetRepository: Repository; + if (type === "avatar") { + const avatar = await this.profileAvatarRepository.findOneBy({ + profile: { + userId, + }, + }); + if (!avatar) return; + targetEntity = avatar; + targetRepository = this.profileAvatarRepository; + } else { + const banner = await this.profileBannerRepository.findOneBy({ + profile: { + userId, + }, + }); + if (!banner) return; + targetEntity = banner; + targetRepository = this.profileBannerRepository; + } + await this.profileRepository .createQueryBuilder() - .relation("avatar") + .relation(type === "avatar" ? "avatar" : "banner") .of({ userId: userId, }) .set(null); - await this.profileAvatarRepository.delete(avatar.id); + + await targetRepository.delete(targetEntity.id); + if (removeFile) { - const filePath = this.getAvatarFilePath( - avatar.filename, - avatar.extension, + const filePath = getImageFilePath( + targetEntity.filename, + targetEntity.extension, ); try { await fs.access(filePath, fs.constants.F_OK); @@ -95,20 +137,48 @@ export class ProfileService { } } + public async updateProfileImage( + userId: string, + dto: UpdateProfileImageDto, + file: Express.Multer.File, + ) { + const profile = await this.findOneByIdOrFail(userId); + + if (file) { + if (!this.ALLOWED_IMAGE_IDENTIFIERS.includes(dto.type)) { + throw new HttpException( + "Invalid image type.", + HttpStatus.BAD_REQUEST, + { + cause: `Allowed values: ${this.ALLOWED_IMAGE_IDENTIFIERS}`, + }, + ); + } + await this.detachImage(userId, dto.type, true); + if (dto.type === "avatar") { + profile.avatar = await this.persistImage(dto.type, file); + } else { + profile.banner = await this.persistImage(dto.type, file); + } + } + + await this.profileRepository.save(profile); + } + async findAll() { return await this.profileRepository.find(); } async findOneById(userId: string): Promise { - const profile = await this.profileRepository.findOne({ + return await this.profileRepository.findOne({ where: { userId, }, relations: { avatar: true, + banner: true, }, }); - return profile; } async findOneByIdOrFail(userId: string) { @@ -120,18 +190,14 @@ export class ProfileService { } private async existsByUserName(username: string) { - return await this.profileRepository.exist({ + return await this.profileRepository.exists({ where: { username, }, }); } - async update( - userId: string, - updateProfileDto: UpdateProfileDto, - avatarFile?: Express.Multer.File, - ) { + async update(userId: string, updateProfileDto: UpdateProfileDto) { const profile = await this.findOneById(userId); if (!profile) { throw new HttpException( @@ -171,11 +237,6 @@ export class ProfileService { profile.bio = filterBadWords(updateProfileDto.bio); } - if (avatarFile) { - await this.detachAvatar(userId, true); - profile.avatar = await this.createAvatar(avatarFile); - } - await this.profileRepository.save(profile); } } diff --git a/src/utils/persisted-image-details.entity.ts b/src/utils/persisted-image-details.entity.ts new file mode 100644 index 0000000..b4974fd --- /dev/null +++ b/src/utils/persisted-image-details.entity.ts @@ -0,0 +1,18 @@ +import { Column } from "typeorm"; + +/** + * Abstract entity that contains required metadata for user uploaded images.
+ * Must be extended by a class decorated with @Entity to have effect. + */ +export abstract class PersistedImageDetails { + @Column({ nullable: false }) + mimetype: string; + @Column({ nullable: false }) + extension: string; + @Column({ nullable: false }) + size: number; + @Column({ nullable: false }) + filename: string; + @Column({ nullable: false }) + encoding: string; +} From 82e6c0604f4252377aa4e8fce1e793f51aa9f1a4 Mon Sep 17 00:00:00 2001 From: Lamarcke Date: Wed, 10 Jul 2024 14:26:46 -0300 Subject: [PATCH 6/7] - --- src/app.module.ts | 4 +- .../game-repository-create.service.ts | 2 +- .../game-repository.service.ts | 4 +- src/health/health.controller.ts | 3 +- .../dto/profile-metrics-distribution.dto.ts | 26 +++ .../dto/profile-metrics-overview.dto.ts} | 2 +- .../profile-metrics.controller.ts} | 24 +-- .../profile-metrics.module.ts | 19 ++ .../profile-metrics.service.ts | 190 ++++++++++++++++++ src/report/report.controller.ts | 1 - ...ile-statistics-distribution-request.dto.ts | 26 --- .../profile-statistics.module.ts | 18 -- .../profile-statistics.service.ts | 96 --------- src/statistics/statistics.module.ts | 1 - src/utils/toMap.ts | 25 +++ 15 files changed, 279 insertions(+), 162 deletions(-) create mode 100644 src/profile/profile-statistics/dto/profile-metrics-distribution.dto.ts rename src/{statistics/profile-statistics/dto/profile-statistics-overview.dto.ts => profile/profile-statistics/dto/profile-metrics-overview.dto.ts} (84%) rename src/{statistics/profile-statistics/profile-statistics.controller.ts => profile/profile-statistics/profile-metrics.controller.ts} (55%) create mode 100644 src/profile/profile-statistics/profile-metrics.module.ts create mode 100644 src/profile/profile-statistics/profile-metrics.service.ts delete mode 100644 src/statistics/profile-statistics/dto/profile-statistics-distribution-request.dto.ts delete mode 100644 src/statistics/profile-statistics/profile-statistics.module.ts delete mode 100644 src/statistics/profile-statistics/profile-statistics.service.ts create mode 100644 src/utils/toMap.ts diff --git a/src/app.module.ts b/src/app.module.ts index 4a0367c..d4bca12 100755 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -31,7 +31,7 @@ import { CommentModule } from "./comment/comment.module"; import { ImporterWatchModule } from "./importer/importer-watch/importer-watch.module"; import { ReportModule } from "./report/report.module"; import { SuspensionModule } from "./suspension/suspension.module"; -import { ProfileStatisticsModule } from "./statistics/profile-statistics/profile-statistics.module"; +import { ProfileMetricsModule } from "./profile/profile-statistics/profile-metrics.module"; /** * Should only be called after 'ConfigModule' is loaded (e.g. in useFactory) @@ -160,7 +160,7 @@ function getRedisConfig() { CollectionsModule, StatisticsModule, StatisticsQueueModule, - ProfileStatisticsModule, + ProfileMetricsModule, LevelModule, HealthModule, AchievementsModule, diff --git a/src/game/game-repository/game-repository-create.service.ts b/src/game/game-repository/game-repository-create.service.ts index 4bb03bc..6fd76ab 100644 --- a/src/game/game-repository/game-repository-create.service.ts +++ b/src/game/game-repository/game-repository-create.service.ts @@ -421,7 +421,7 @@ export class GameRepositoryCreateService { if (companies == undefined || companies.length === 0) return; for (const originalCompany of companies) { // Avoids errors where company.id is transformed to "undefined". - // Probably TypeORM messing something interanally. + // Probably TypeORM messing something internally. const company = structuredClone(originalCompany); if (company == undefined || typeof company.id !== "number") continue; diff --git a/src/game/game-repository/game-repository.service.ts b/src/game/game-repository/game-repository.service.ts index c04c4c1..cb0b5f5 100644 --- a/src/game/game-repository/game-repository.service.ts +++ b/src/game/game-repository/game-repository.service.ts @@ -97,8 +97,8 @@ export class GameRepositoryService { return game; } - private reOrderByIds(originalIds: number[], games: Game[]) { - const gamesMap = games.reduce((acc, current) => { + private reOrderByIds(originalIds: number[], unOrderedGames: Game[]) { + const gamesMap = unOrderedGames.reduce((acc, current) => { acc.set(current.id, current); return acc; }, new Map()); diff --git a/src/health/health.controller.ts b/src/health/health.controller.ts index 443da04..76d2bda 100644 --- a/src/health/health.controller.ts +++ b/src/health/health.controller.ts @@ -5,8 +5,7 @@ import { ApiTags } from "@nestjs/swagger"; @Controller("health") @ApiTags("health") export class HealthController { - constructor(private healthService: HealthService) { - } + constructor(private healthService: HealthService) {} @Get() async health() { diff --git a/src/profile/profile-statistics/dto/profile-metrics-distribution.dto.ts b/src/profile/profile-statistics/dto/profile-metrics-distribution.dto.ts new file mode 100644 index 0000000..006255d --- /dev/null +++ b/src/profile/profile-statistics/dto/profile-metrics-distribution.dto.ts @@ -0,0 +1,26 @@ +import { IsEnum, IsNotEmpty } from "class-validator"; + +export enum ProfileMetricsDistribution { + RELEASE_YEAR = "release_year", + FINISH_YEAR = "finish_year", +} + +export class ProfileMetricsDistributionRequestDto { + @IsNotEmpty() + @IsEnum(ProfileMetricsDistribution) + by: ProfileMetricsDistribution; +} + +/** + * Relation between a year (presented as string) and data for said period. + */ +export interface ProfileMetricsDistributionYearToData { + [p: string]: { + count: number; + totalEstimatedPlaytime: number; + }; +} + +export class ProfileMetricsDistributionResponseDto { + distribution: ProfileMetricsDistributionYearToData; +} diff --git a/src/statistics/profile-statistics/dto/profile-statistics-overview.dto.ts b/src/profile/profile-statistics/dto/profile-metrics-overview.dto.ts similarity index 84% rename from src/statistics/profile-statistics/dto/profile-statistics-overview.dto.ts rename to src/profile/profile-statistics/dto/profile-metrics-overview.dto.ts index 07c6677..8ef33f7 100644 --- a/src/statistics/profile-statistics/dto/profile-statistics-overview.dto.ts +++ b/src/profile/profile-statistics/dto/profile-metrics-overview.dto.ts @@ -1,4 +1,4 @@ -export class ProfileStatisticsOverviewDto { +export class ProfileMetricsOverviewDto { totalGames: number; totalCollections: number; totalFinishedGames: number; diff --git a/src/statistics/profile-statistics/profile-statistics.controller.ts b/src/profile/profile-statistics/profile-metrics.controller.ts similarity index 55% rename from src/statistics/profile-statistics/profile-statistics.controller.ts rename to src/profile/profile-statistics/profile-metrics.controller.ts index 86d0422..8029350 100644 --- a/src/statistics/profile-statistics/profile-statistics.controller.ts +++ b/src/profile/profile-statistics/profile-metrics.controller.ts @@ -1,20 +1,20 @@ import { Controller, Get, Param, Query, UseGuards } from "@nestjs/common"; import { ApiOkResponse, ApiTags } from "@nestjs/swagger"; -import { ProfileStatisticsService } from "./profile-statistics.service"; -import { ProfileStatisticsOverviewDto } from "./dto/profile-statistics-overview.dto"; +import { ProfileMetricsService } from "./profile-metrics.service"; +import { ProfileMetricsOverviewDto } from "./dto/profile-metrics-overview.dto"; import { AuthGuard } from "../../auth/auth.guard"; import { Public } from "../../auth/public.decorator"; import { - ProfileStatisticsDistributionRequestDto, - ProfileStatisticsDistributionResponseDto, -} from "./dto/profile-statistics-distribution-request.dto"; + ProfileMetricsDistributionRequestDto, + ProfileMetricsDistributionResponseDto, +} from "./dto/profile-metrics-distribution.dto"; -@Controller("profile/statistics") -@ApiTags("profile-statistics") +@Controller("profile/metrics") +@ApiTags("profile-metrics") @UseGuards(AuthGuard) -export class ProfileStatisticsController { +export class ProfileMetricsController { constructor( - private readonly profileStatisticsService: ProfileStatisticsService, + private readonly profileStatisticsService: ProfileMetricsService, ) {} /** @@ -23,7 +23,7 @@ export class ProfileStatisticsController { */ @Get("overview/:userId") @ApiOkResponse({ - type: ProfileStatisticsOverviewDto, + type: ProfileMetricsOverviewDto, }) @Public() async getStatsOverview(@Param("userId") userId: string) { @@ -32,11 +32,11 @@ export class ProfileStatisticsController { @Get("distribution/:userId") @ApiOkResponse({ - type: ProfileStatisticsDistributionResponseDto, + type: ProfileMetricsDistributionResponseDto, }) async getStatsDistribution( @Param("userId") userId: string, - @Query() dto: ProfileStatisticsDistributionRequestDto, + @Query() dto: ProfileMetricsDistributionRequestDto, ) { return this.profileStatisticsService.getDistribution(userId, dto); } diff --git a/src/profile/profile-statistics/profile-metrics.module.ts b/src/profile/profile-statistics/profile-metrics.module.ts new file mode 100644 index 0000000..fba72a5 --- /dev/null +++ b/src/profile/profile-statistics/profile-metrics.module.ts @@ -0,0 +1,19 @@ +import { Module } from "@nestjs/common"; +import { ProfileMetricsController } from "./profile-metrics.controller"; +import { ProfileMetricsService } from "./profile-metrics.service"; +import { CollectionsEntriesModule } from "../../collections/collections-entries/collections-entries.module"; +import { CollectionsModule } from "../../collections/collections.module"; +import { HltbSyncModule } from "../../sync/hltb/hltb-sync.module"; +import { GameRepositoryModule } from "../../game/game-repository/game-repository.module"; + +@Module({ + imports: [ + CollectionsModule, + CollectionsEntriesModule, + HltbSyncModule, + GameRepositoryModule, + ], + controllers: [ProfileMetricsController], + providers: [ProfileMetricsService], +}) +export class ProfileMetricsModule {} diff --git a/src/profile/profile-statistics/profile-metrics.service.ts b/src/profile/profile-statistics/profile-metrics.service.ts new file mode 100644 index 0000000..46ae08a --- /dev/null +++ b/src/profile/profile-statistics/profile-metrics.service.ts @@ -0,0 +1,190 @@ +import { Injectable } from "@nestjs/common"; +import { CollectionsService } from "../../collections/collections.service"; +import { CollectionsEntriesService } from "../../collections/collections-entries/collections-entries.service"; +import { ProfileMetricsOverviewDto } from "./dto/profile-metrics-overview.dto"; +import { HltbSyncService } from "../../sync/hltb/hltb-sync.service"; +import { + ProfileMetricsDistribution, + ProfileMetricsDistributionRequestDto, + ProfileMetricsDistributionYearToData, +} from "./dto/profile-metrics-distribution.dto"; +import { GamePlaytime } from "../../sync/hltb/entity/game-playtime.entity"; +import { GameRepositoryService } from "../../game/game-repository/game-repository.service"; +import { Game } from "../../game/game-repository/entities/game.entity"; + +@Injectable() +export class ProfileMetricsService { + constructor( + private readonly collectionsService: CollectionsService, + private readonly collectionsEntriesService: CollectionsEntriesService, + private readonly htlbService: HltbSyncService, + private readonly gameRepositoryService: GameRepositoryService, + ) {} + + /** + * Returns an estimate total playtime for games based on the 'main' HLTB profile. + * @param gameIds + * @private + * @returns Map - A map between gameIds and gamePlaytimes + */ + private async getPlaytimeForGames( + gameIds: number[], + ): Promise> { + const playtimes = await this.htlbService.findAllByGameIds(gameIds); + + return playtimes.reduce((acc, curr) => { + acc.set(curr.gameId, curr); + return acc; + }, new Map()); + } + + async getStatsOverview(userId: string): Promise { + const collections = + await this.collectionsService.findAllByUserIdWithPermissions( + undefined, + userId, + ); + const [collectionEntries] = + await this.collectionsEntriesService.findAllByUserIdWithPermissions( + undefined, + userId, + { + limit: undefined, + offset: 0, + }, + ); + + const finishedCollectionEntries = collectionEntries.filter((entry) => { + return entry.finishedAt != undefined; + }); + + const finishedGamesIds = finishedCollectionEntries.map( + (entry) => entry.gameId, + ); + + const playtimeMap = await this.getPlaytimeForGames(finishedGamesIds); + + let totalEstimatedPlaytime = 0; + for (const value of playtimeMap.values()) { + if (!value.timeMain) continue; + + totalEstimatedPlaytime += value.timeMain; + } + + return { + totalCollections: collections.length, + totalFinishedGames: finishedCollectionEntries.length, + totalGames: collectionEntries.length, + totalEstimatedPlaytime: totalEstimatedPlaytime, + }; + } + + async getDistribution( + userId: string, + dto: ProfileMetricsDistributionRequestDto, + ) { + const [collectionEntries] = + await this.collectionsEntriesService.findAllByUserIdWithPermissions( + undefined, + userId, + { + limit: undefined, + offset: 0, + }, + ); + + const distribution: ProfileMetricsDistributionYearToData = {}; + + switch (dto.by) { + case ProfileMetricsDistribution.FINISH_YEAR: { + const finishedGames = collectionEntries.filter( + (entry) => entry.finishedAt != undefined, + ); + const finishedGamesIds = finishedGames.map( + (entry) => entry.gameId, + ); + + const playtimeMap = + await this.getPlaytimeForGames(finishedGamesIds); + + for (const entry of finishedGames) { + const finishDate: Date = entry.finishedAt!; + const finishYear = finishDate.getFullYear().toString(); + const playtime = playtimeMap.get(entry.gameId); + + if (!Object.hasOwn(distribution, finishYear)) { + const estimatedPlaytime = playtime?.timeMain || 0; + + distribution[finishYear] = { + count: 1, + totalEstimatedPlaytime: estimatedPlaytime, + }; + + continue; + } + + const count = distribution[finishYear]["count"] + 1; + let totalPlaytime = + distribution[finishYear]["totalEstimatedPlaytime"] || 0; + if (playtime && playtime.timeMain) { + totalPlaytime += playtime.timeMain; + } + + distribution[finishYear] = { + count, + totalEstimatedPlaytime: totalPlaytime, + }; + } + break; + } + case ProfileMetricsDistribution.RELEASE_YEAR: { + const gamesIds = collectionEntries.map((entry) => entry.gameId); + const games = await this.gameRepositoryService.findAllByIds({ + gameIds: gamesIds, + }); + + const playtimesMap = await this.getPlaytimeForGames(gamesIds); + + const gamesMap = games.reduce((acc, curr) => { + acc.set(curr.id, curr); + return acc; + }, new Map()); + + for (const entry of collectionEntries) { + const relatedGame = gamesMap.get(entry.gameId); + const playtime = playtimesMap.get(entry.gameId); + // Technically impossible + if (!relatedGame) continue; + const releaseDate = relatedGame.firstReleaseDate; + const releaseYear = releaseDate.getFullYear().toString(); + + if (!Object.hasOwn(distribution, releaseYear)) { + const estimatedPlaytime = playtime?.timeMain || 0; + + distribution[releaseYear] = { + count: 1, + totalEstimatedPlaytime: estimatedPlaytime, + }; + + continue; + } + + const count = distribution[releaseYear]["count"] + 1; + let totalPlaytime = + distribution[releaseYear]["totalEstimatedPlaytime"] || + 0; + if (playtime && playtime.timeMain) { + totalPlaytime += playtime.timeMain; + } + + distribution[releaseYear] = { + count, + totalEstimatedPlaytime: totalPlaytime, + }; + } + + break; + } + } + } +} diff --git a/src/report/report.controller.ts b/src/report/report.controller.ts index 0df4d60..ac9c616 100644 --- a/src/report/report.controller.ts +++ b/src/report/report.controller.ts @@ -5,7 +5,6 @@ import { Param, Post, Query, - Req, UseGuards, UseInterceptors, } from "@nestjs/common"; diff --git a/src/statistics/profile-statistics/dto/profile-statistics-distribution-request.dto.ts b/src/statistics/profile-statistics/dto/profile-statistics-distribution-request.dto.ts deleted file mode 100644 index 513168e..0000000 --- a/src/statistics/profile-statistics/dto/profile-statistics-distribution-request.dto.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { IsEnum, IsNotEmpty } from "class-validator"; - -export enum ProfileStatisticsDistribution { - RELEASE_YEAR = "release_year", - FINISH_YEAR = "finish_year", -} - -export class ProfileStatisticsDistributionRequestDto { - @IsNotEmpty() - @IsEnum(ProfileStatisticsDistribution) - by: ProfileStatisticsDistribution; -} - -/** - * Relation between a year (presented as string) and data for said period. - */ -export interface ProfileStatisticsDistributionYearToData { - [p: string]: { - count: number; - totalEstimatedPlaytime: number; - }; -} - -export class ProfileStatisticsDistributionResponseDto { - distribution: ProfileStatisticsDistributionYearToData; -} diff --git a/src/statistics/profile-statistics/profile-statistics.module.ts b/src/statistics/profile-statistics/profile-statistics.module.ts deleted file mode 100644 index 41772f3..0000000 --- a/src/statistics/profile-statistics/profile-statistics.module.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Module } from "@nestjs/common"; -import { ProfileStatisticsController } from "./profile-statistics.controller"; -import { ProfileStatisticsService } from "./profile-statistics.service"; -import { CollectionsEntriesModule } from "../../collections/collections-entries/collections-entries.module"; -import { CollectionsModule } from "../../collections/collections.module"; -import { HltbSyncModule } from "../../sync/hltb/hltb-sync.module"; - -/** - * Module responsible for providing profile's stats' data.
- * This module is quite different from other modules with the same statistics prefix, because it doesn't - * resolve around user likes and views. - */ -@Module({ - imports: [CollectionsModule, CollectionsEntriesModule, HltbSyncModule], - controllers: [ProfileStatisticsController], - providers: [ProfileStatisticsService], -}) -export class ProfileStatisticsModule {} diff --git a/src/statistics/profile-statistics/profile-statistics.service.ts b/src/statistics/profile-statistics/profile-statistics.service.ts deleted file mode 100644 index 646f904..0000000 --- a/src/statistics/profile-statistics/profile-statistics.service.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { Injectable, UseGuards } from "@nestjs/common"; -import { AuthGuard } from "../../auth/auth.guard"; -import { CollectionsService } from "../../collections/collections.service"; -import { CollectionsEntriesService } from "../../collections/collections-entries/collections-entries.service"; -import { ProfileStatisticsOverviewDto } from "./dto/profile-statistics-overview.dto"; -import { HltbSyncService } from "../../sync/hltb/hltb-sync.service"; -import { - ProfileStatisticsDistribution, - ProfileStatisticsDistributionRequestDto, -} from "./dto/profile-statistics-distribution-request.dto"; - -@Injectable() -export class ProfileStatisticsService { - constructor( - private readonly collectionsService: CollectionsService, - private readonly collectionsEntriesService: CollectionsEntriesService, - private readonly htlbService: HltbSyncService, - ) {} - - /** - * Returns an estimate total playtime for games based on the HLTB 'main' profile. - * @param gameIds - * @private - */ - private async getTotalPlaytimeForGames(gameIds: number[]) { - const playtimes = await this.htlbService.findAllByGameIds(gameIds); - return playtimes.reduce((prev, curr) => { - if (!curr.timeMain) return prev; - - return prev + curr.timeMain; - }, 0); - } - - async getStatsOverview( - userId: string, - ): Promise { - const collections = - await this.collectionsService.findAllByUserIdWithPermissions( - undefined, - userId, - ); - const [collectionEntries] = - await this.collectionsEntriesService.findAllByUserIdWithPermissions( - undefined, - userId, - { - limit: undefined, - offset: 0, - }, - ); - - const finishedCollectionEntries = collectionEntries.filter((entry) => { - return entry.finishedAt != undefined; - }); - - const finishedGamesIds = finishedCollectionEntries.map( - (entry) => entry.gameId, - ); - - const estimatedPlaytime = - await this.getTotalPlaytimeForGames(finishedGamesIds); - - return { - totalCollections: collections.length, - totalFinishedGames: finishedCollectionEntries.length, - totalGames: collectionEntries.length, - totalEstimatedPlaytime: estimatedPlaytime, - }; - } - - async getDistribution( - userId: string, - dto: ProfileStatisticsDistributionRequestDto, - ) { - const [collectionEntries] = - await this.collectionsEntriesService.findAllByUserIdWithPermissions( - undefined, - userId, - { - limit: undefined, - offset: 0, - }, - ); - - switch (dto.by) { - case ProfileStatisticsDistribution.FINISH_YEAR: { - const finishedGames = collectionEntries.filter( - (entry) => entry.finishedAt != undefined, - ); - break; - } - case ProfileStatisticsDistribution.RELEASE_YEAR: - break; - } - } -} diff --git a/src/statistics/statistics.module.ts b/src/statistics/statistics.module.ts index 1630ff8..9b922e7 100644 --- a/src/statistics/statistics.module.ts +++ b/src/statistics/statistics.module.ts @@ -13,7 +13,6 @@ import { ActivityStatisticsService } from "./activity-statistics.service"; import { ActivityStatistics } from "./entity/activity-statistics.entity"; import { CommentStatisticsService } from "./comment-statistics.service"; import { CommentStatistics } from "./entity/comment-statistics.entity"; -import { ProfileStatisticsModule } from "./profile-statistics/profile-statistics.module"; @Module({ imports: [ diff --git a/src/utils/toMap.ts b/src/utils/toMap.ts new file mode 100644 index 0000000..d802adc --- /dev/null +++ b/src/utils/toMap.ts @@ -0,0 +1,25 @@ +import { Game } from "../game/game-repository/entities/game.entity"; + +type IdentifierType = T[K] extends number + ? number + : T[K] extends string + ? string + : symbol; + +/** + * Converts a given list to a map composed of its items. + * @param list - list to convert + * @param identifier - list item type identifier - either a number or string + */ +export function toMap( + list: T[], + identifier: K, +): Map, T> { + return list.reduce((acc, curr) => { + acc.set(curr[identifier], curr); + return acc; + }, new Map()); +} + +const list: Game[] = []; +const map = toMap(list, "id"); From 44d2849543230156c27e8b1c84b2037c2fa51e1e Mon Sep 17 00:00:00 2001 From: Lamarcke Date: Wed, 10 Jul 2024 14:29:32 -0300 Subject: [PATCH 7/7] - --- .../profile-statistics/profile-metrics.service.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/profile/profile-statistics/profile-metrics.service.ts b/src/profile/profile-statistics/profile-metrics.service.ts index 46ae08a..53bd953 100644 --- a/src/profile/profile-statistics/profile-metrics.service.ts +++ b/src/profile/profile-statistics/profile-metrics.service.ts @@ -11,6 +11,7 @@ import { import { GamePlaytime } from "../../sync/hltb/entity/game-playtime.entity"; import { GameRepositoryService } from "../../game/game-repository/game-repository.service"; import { Game } from "../../game/game-repository/entities/game.entity"; +import { toMap } from "../../utils/toMap"; @Injectable() export class ProfileMetricsService { @@ -32,10 +33,7 @@ export class ProfileMetricsService { ): Promise> { const playtimes = await this.htlbService.findAllByGameIds(gameIds); - return playtimes.reduce((acc, curr) => { - acc.set(curr.gameId, curr); - return acc; - }, new Map()); + return toMap(playtimes, "gameId"); } async getStatsOverview(userId: string): Promise { @@ -145,10 +143,7 @@ export class ProfileMetricsService { const playtimesMap = await this.getPlaytimeForGames(gamesIds); - const gamesMap = games.reduce((acc, curr) => { - acc.set(curr.id, curr); - return acc; - }, new Map()); + const gamesMap = toMap(games, "id"); for (const entry of collectionEntries) { const relatedGame = gamesMap.get(entry.gameId);