From 9f1e25baf5c95524d60e047b0dd52a96bf55d8b6 Mon Sep 17 00:00:00 2001 From: jvyden Date: Wed, 16 Oct 2024 17:53:10 -0400 Subject: [PATCH] Implement APIv3/Game endpoints for getting events by a user Also cleans up some naming to make things more clear. --- .../Activity/GameDatabaseContext.Activity.cs | 10 ++++ .../Endpoints/ApiV3/ActivityApiEndpoints.cs | 60 ++++++++++++++++++- .../Endpoints/Game/ActivityEndpoints.cs | 8 +-- .../Types/Activity/ActivityPage.cs | 40 ++++++++++++- 4 files changed, 110 insertions(+), 8 deletions(-) diff --git a/Refresh.GameServer/Database/Activity/GameDatabaseContext.Activity.cs b/Refresh.GameServer/Database/Activity/GameDatabaseContext.Activity.cs index b0bc4f33..8f14c03e 100644 --- a/Refresh.GameServer/Database/Activity/GameDatabaseContext.Activity.cs +++ b/Refresh.GameServer/Database/Activity/GameDatabaseContext.Activity.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using JetBrains.Annotations; using MongoDB.Bson; using Refresh.GameServer.Types.Activity; @@ -92,6 +93,15 @@ ActivityQueryParameters parameters .Where(e => e._StoredDataType == 1 && e.StoredSequentialId == level.LevelId) .OrderByDescending(e => e.Timestamp), parameters.Skip, parameters.Count); } + + [Pure] + public DatabaseList GetRecentActivityFromUser(ActivityQueryParameters parameters) + { + Debug.Assert(parameters.User != null); + return new DatabaseList(this.GetRecentActivity(parameters) + .Where(e => e.User?.UserId == parameters.User.UserId) + .OrderByDescending(e => e.Timestamp), parameters.Skip, parameters.Count); + } public int GetTotalEventCount() => this.Events.Count(); } \ No newline at end of file diff --git a/Refresh.GameServer/Endpoints/ApiV3/ActivityApiEndpoints.cs b/Refresh.GameServer/Endpoints/ApiV3/ActivityApiEndpoints.cs index 74072631..1380da53 100644 --- a/Refresh.GameServer/Endpoints/ApiV3/ActivityApiEndpoints.cs +++ b/Refresh.GameServer/Endpoints/ApiV3/ActivityApiEndpoints.cs @@ -63,7 +63,65 @@ public ApiResponse GetRecentActivityForLevel(RequestCon (int skip, int count) = context.GetPageData(); - ActivityPage page = ActivityPage.ApiLevelActivity(database, level, new ActivityQueryParameters + ActivityPage page = ActivityPage.ApiForLevelActivity(database, level, new ActivityQueryParameters + { + Timestamp = timestamp, + Skip = skip, + Count = count, + User = user, + }, dataContext, false); + return ApiActivityPageResponse.FromOld(page, dataContext); + } + + [ApiV3Endpoint("users/uuid/{uuid}/activity"), Authentication(false)] + [DocUsesPageData, DocSummary("Fetch a list of recent happenings for a particular user")] + [DocQueryParam("timestamp", "A timestamp in unix seconds, used to search backwards")] + [DocError(typeof(ApiValidationError), ApiValidationError.NumberParseErrorWhen)] + [DocError(typeof(ApiNotFoundError), "The user could not be found")] + public ApiResponse GetRecentActivityForUserUuid(RequestContext context, + GameDatabaseContext database, IDataStore dataStore, + [DocSummary("The UUID of the user")] string uuid, DataContext dataContext) + { + long timestamp = 0; + + string? tsStr = context.QueryString["timestamp"]; + if (tsStr != null && !long.TryParse(tsStr, out timestamp)) return ApiValidationError.NumberParseError; + + GameUser? user = database.GetUserByUuid(uuid); + if (user == null) return ApiNotFoundError.Instance; + + (int skip, int count) = context.GetPageData(); + + ActivityPage page = ActivityPage.ApiFromUserActivity(database, new ActivityQueryParameters + { + Timestamp = timestamp, + Skip = skip, + Count = count, + User = user, + }, dataContext, false); + return ApiActivityPageResponse.FromOld(page, dataContext); + } + + [ApiV3Endpoint("users/name/{username}/activity"), Authentication(false)] + [DocUsesPageData, DocSummary("Fetch a list of recent happenings for a particular user")] + [DocQueryParam("timestamp", "A timestamp in unix seconds, used to search backwards")] + [DocError(typeof(ApiValidationError), ApiValidationError.NumberParseErrorWhen)] + [DocError(typeof(ApiNotFoundError), "The user could not be found")] + public ApiResponse GetRecentActivityForUserUsername(RequestContext context, + GameDatabaseContext database, IDataStore dataStore, + [DocSummary("The username of the user")] string username, DataContext dataContext) + { + long timestamp = 0; + + string? tsStr = context.QueryString["timestamp"]; + if (tsStr != null && !long.TryParse(tsStr, out timestamp)) return ApiValidationError.NumberParseError; + + GameUser? user = database.GetUserByUsername(username); + if (user == null) return ApiNotFoundError.Instance; + + (int skip, int count) = context.GetPageData(); + + ActivityPage page = ActivityPage.ApiFromUserActivity(database, new ActivityQueryParameters { Timestamp = timestamp, Skip = skip, diff --git a/Refresh.GameServer/Endpoints/Game/ActivityEndpoints.cs b/Refresh.GameServer/Endpoints/Game/ActivityEndpoints.cs index 90e92bec..2528442f 100644 --- a/Refresh.GameServer/Endpoints/Game/ActivityEndpoints.cs +++ b/Refresh.GameServer/Endpoints/Game/ActivityEndpoints.cs @@ -42,7 +42,7 @@ public class ActivityEndpoints : EndpointGroup if (endTimestamp == 0) endTimestamp = timestamp - 86400000 * 7; // 1 week - return ActivityPage.UserActivity(database, new ActivityQueryParameters + return ActivityPage.GameUserActivity(database, new ActivityQueryParameters { Timestamp = timestamp, EndTimestamp = endTimestamp, @@ -77,7 +77,7 @@ public Response GetRecentActivityForLevel(RequestContext context, GameDatabaseCo if (endTimestamp == 0) endTimestamp = timestamp - 86400000 * 7; // 1 week - ActivityPage page = ActivityPage.GameLevelActivity(database, level, new ActivityQueryParameters + ActivityPage page = ActivityPage.GameForLevelActivity(database, level, new ActivityQueryParameters { Count = 20, Skip = 0, @@ -95,7 +95,7 @@ public Response GetRecentActivityForLevel(RequestContext context, GameDatabaseCo [GameEndpoint("stream/user2/{username}", ContentType.Xml)] [NullStatusCode(BadRequest)] [MinimumRole(GameUserRole.Restricted)] - public Response GetRecentActivityForUser(RequestContext context, GameDatabaseContext database, string username, + public Response GetRecentActivityFromUser(RequestContext context, GameDatabaseContext database, string username, DataContext dataContext) { GameUser? user = database.GetUserByUsername(username); @@ -119,7 +119,7 @@ public Response GetRecentActivityForUser(RequestContext context, GameDatabaseCon if (endTimestamp == 0) endTimestamp = timestamp - 86400000 * 7; // 1 week - return new Response(ActivityPage.UserActivity(database, new ActivityQueryParameters + return new Response(ActivityPage.GameFromUserActivity(database, new ActivityQueryParameters { Timestamp = timestamp, EndTimestamp = endTimestamp, diff --git a/Refresh.GameServer/Types/Activity/ActivityPage.cs b/Refresh.GameServer/Types/Activity/ActivityPage.cs index 81a74b16..ee474186 100644 --- a/Refresh.GameServer/Types/Activity/ActivityPage.cs +++ b/Refresh.GameServer/Types/Activity/ActivityPage.cs @@ -119,7 +119,7 @@ private void FillInInfo(GameDatabaseContext database, bool generateGroups, Activ } } - public static ActivityPage GameLevelActivity(GameDatabaseContext database, + public static ActivityPage GameForLevelActivity(GameDatabaseContext database, GameLevel level, ActivityQueryParameters parameters, DataContext dataContext) { @@ -137,7 +137,7 @@ public static ActivityPage GameLevelActivity(GameDatabaseContext database, return page; } - public static ActivityPage ApiLevelActivity(GameDatabaseContext database, + public static ActivityPage ApiForLevelActivity(GameDatabaseContext database, GameLevel level, ActivityQueryParameters parameters, DataContext dataContext, @@ -155,7 +155,41 @@ public static ActivityPage ApiLevelActivity(GameDatabaseContext database, return page; } - public static ActivityPage UserActivity(GameDatabaseContext database, + public static ActivityPage ApiFromUserActivity(GameDatabaseContext database, + ActivityQueryParameters parameters, + DataContext dataContext, + bool generateGroups = true) + { + DatabaseList events = database.GetRecentActivityFromUser(parameters); + + ActivityPage page = new() + { + Events = events.Items, + }; + + page.FillInInfo(database, generateGroups, parameters, dataContext); + + return page; + } + + public static ActivityPage GameFromUserActivity(GameDatabaseContext database, + ActivityQueryParameters parameters, DataContext dataContext) + { + DatabaseList events = database.GetRecentActivityFromUser(parameters); + + ActivityPage page = new() + { + Events = events.Items, + }; + + page.FillInInfo(database, true, parameters, dataContext); + + page.Groups.Groups = page.Groups.Groups.SelectMany(group => group.Subgroups?.Items ?? []).ToList(); + + return page; + } + + public static ActivityPage GameUserActivity(GameDatabaseContext database, ActivityQueryParameters parameters, DataContext dataContext, bool generateGroups = true)