Skip to content

Commit 21d1137

Browse files
authored
Overhaul & rewrite serialization of Recent Activity (#782)
This splits things up to work like the rest of the API. Key points: - Proper separation between API and Game data types - Most logic is no longer tangled in `ActivityPage` - APIv3 now has access to groups (we should remove the `events` array in APIv4) - Grouping is now done as properly intended - Pagination in-game should be a bit better - This is a bit more performant since we truncate to the last 6 months by default, but work still needs to be done after Postgres. - Activity generation is now handled entirely in `Refresh.Database`
2 parents 4c53b26 + 6bbd182 commit 21d1137

29 files changed

Lines changed: 830 additions & 535 deletions

Refresh.Database/GameDatabaseContext.Activity.cs

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -10,37 +10,14 @@ namespace Refresh.Database;
1010

1111
public partial class GameDatabaseContext // Activity
1212
{
13-
[Pure]
14-
public DatabaseList<Event> GetUserRecentActivity(ActivityQueryParameters parameters)
15-
{
16-
IEnumerable<Event> query = this.GetRecentActivity(parameters);
17-
18-
if (parameters.User != null)
19-
{
20-
List<ObjectId?> favouriteUsers = this.GetUsersFavouritedByUser(parameters.User, 1000, 0).Select(f => (ObjectId?)f.UserId).ToList();
21-
List<ObjectId?> userFriends = this.GetUsersMutuals(parameters.User).Select(u => (ObjectId?)u.UserId).ToList();
22-
23-
query = query.Where(e =>
24-
e.User.UserId == parameters.User.UserId ||
25-
e.StoredObjectId == parameters.User.UserId ||
26-
favouriteUsers.Contains(e.User.UserId) ||
27-
favouriteUsers.Contains(e.StoredObjectId) ||
28-
userFriends.Contains(e.User.UserId) ||
29-
userFriends.Contains(e.StoredObjectId) ||
30-
this.GetLevelById(e.StoredSequentialId ?? int.MaxValue)?.Publisher?.UserId == parameters.User.UserId ||
31-
e.EventType == EventType.LevelTeamPick ||
32-
e.EventType == EventType.UserFirstLogin
33-
);
34-
}
35-
36-
return new DatabaseList<Event>(query.OrderByDescending(e => e.Timestamp), parameters.Skip, parameters.Count);
37-
}
38-
39-
private IEnumerable<Event> GetRecentActivity(ActivityQueryParameters parameters)
13+
private IEnumerable<Event> GetEvents(ActivityQueryParameters parameters)
4014
{
4115
if (parameters.Timestamp == 0)
4216
parameters.Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
4317

18+
if (parameters.EndTimestamp == 0)
19+
parameters.EndTimestamp = DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(30.5 * 6)).ToUnixTimeMilliseconds();
20+
4421
DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeMilliseconds(parameters.Timestamp);
4522
DateTimeOffset endTimestamp = DateTimeOffset.FromUnixTimeMilliseconds(parameters.EndTimestamp);
4623

@@ -77,31 +54,86 @@ private IEnumerable<Event> GetRecentActivity(ActivityQueryParameters parameters)
7754

7855
return query;
7956
}
57+
58+
private DatabaseActivityPage GetRecentActivity(IEnumerable<Event> eventQuery, ActivityQueryParameters parameters)
59+
{
60+
if (parameters.Timestamp == 0)
61+
parameters.Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
62+
63+
List<Event> events = eventQuery
64+
.OrderByDescending(e => e.Timestamp)
65+
.Skip(parameters.Skip)
66+
.Take(parameters.Count)
67+
.ToList();
68+
69+
DatabaseActivityPage page = new(this, events, parameters);
70+
71+
return page;
72+
}
8073

8174
[Pure]
8275
public DatabaseList<Event> GetGlobalRecentActivity(ActivityQueryParameters parameters)
8376
{
84-
return new DatabaseList<Event>(this.GetRecentActivity(parameters).OrderByDescending(e => e.Timestamp), parameters.Skip, parameters.Count);
77+
return new DatabaseList<Event>(this.GetEvents(parameters).OrderByDescending(e => e.Timestamp), parameters.Skip, parameters.Count);
8578
}
8679

8780
[Pure]
88-
public DatabaseList<Event> GetRecentActivityForLevel(
81+
public DatabaseActivityPage GetGlobalRecentActivityPage(ActivityQueryParameters parameters)
82+
{
83+
return this.GetRecentActivity(this.GetEvents(parameters), parameters);
84+
}
85+
86+
[Pure]
87+
public DatabaseActivityPage GetUserRecentActivity(ActivityQueryParameters parameters)
88+
{
89+
IEnumerable<Event> query = this.GetEvents(parameters);
90+
91+
if (parameters.User != null)
92+
{
93+
List<ObjectId?> favouriteUsers = this.GetUsersFavouritedByUser(parameters.User, 1000, 0).Select(f => (ObjectId?)f.UserId).ToList();
94+
List<ObjectId?> userFriends = this.GetUsersMutuals(parameters.User).Select(u => (ObjectId?)u.UserId).ToList();
95+
96+
query = query.Where(e =>
97+
e.User?.UserId == parameters.User.UserId ||
98+
e.StoredObjectId == parameters.User.UserId ||
99+
favouriteUsers.Contains(e.User?.UserId) ||
100+
favouriteUsers.Contains(e.StoredObjectId) ||
101+
userFriends.Contains(e.User?.UserId) ||
102+
userFriends.Contains(e.StoredObjectId) ||
103+
this.GetLevelById(e.StoredSequentialId ?? int.MaxValue)?.Publisher?.UserId == parameters.User.UserId ||
104+
e.EventType == EventType.LevelTeamPick ||
105+
e.EventType == EventType.UserFirstLogin
106+
);
107+
}
108+
109+
query = query.OrderByDescending(e => e.Timestamp);
110+
111+
return GetRecentActivity(query, parameters);
112+
}
113+
114+
[Pure]
115+
public DatabaseActivityPage GetRecentActivityForLevel(
89116
GameLevel level,
90117
ActivityQueryParameters parameters
91118
)
92119
{
93-
return new DatabaseList<Event>(this.GetRecentActivity(parameters)
94-
.Where(e => e._StoredDataType == 1 && e.StoredSequentialId == level.LevelId)
95-
.OrderByDescending(e => e.Timestamp), parameters.Skip, parameters.Count);
120+
IEnumerable<Event> events = this.GetEvents(parameters)
121+
.Where(e => e._StoredDataType == (int)EventDataType.Level && e.StoredSequentialId == level.LevelId)
122+
.OrderByDescending(e => e.Timestamp);
123+
124+
return GetRecentActivity(events, parameters);
96125
}
97126

98127
[Pure]
99-
public DatabaseList<Event> GetRecentActivityFromUser(ActivityQueryParameters parameters)
128+
public DatabaseActivityPage GetRecentActivityFromUser(ActivityQueryParameters parameters)
100129
{
101130
Debug.Assert(parameters.User != null);
102-
return new DatabaseList<Event>(this.GetRecentActivity(parameters)
131+
132+
IEnumerable<Event> events = this.GetEvents(parameters)
103133
.Where(e => e.User?.UserId == parameters.User.UserId)
104-
.OrderByDescending(e => e.Timestamp), parameters.Skip, parameters.Count);
134+
.OrderByDescending(e => e.Timestamp);
135+
136+
return GetRecentActivity(events, parameters);
105137
}
106138

107139
public int GetTotalEventCount() => this.Events.Count();
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
namespace Refresh.Database.Models.Activity;
2+
3+
#nullable disable
4+
5+
public abstract class DatabaseActivityGroup
6+
{
7+
public abstract string GroupType { get; }
8+
public DateTimeOffset Timestamp { get; set; } = DateTimeOffset.MinValue;
9+
public List<Event> Events { get; set; } = [];
10+
public List<DatabaseActivityGroup> Children { get; set; } = [];
11+
12+
#nullable enable
13+
14+
internal List<DatabaseActivityUserGroup>? UserChildren = [];
15+
16+
internal void Cleanup()
17+
{
18+
foreach (DatabaseActivityGroup group in this.Children)
19+
group.Cleanup();
20+
21+
this.UserChildren = null;
22+
}
23+
24+
public void TraverseChildrenForEventsRecursively(Action<Event> callback)
25+
{
26+
foreach (Event @event in this.Events)
27+
{
28+
callback(@event);
29+
}
30+
31+
foreach (DatabaseActivityGroup group in this.Children)
32+
{
33+
group.TraverseChildrenForEventsRecursively(callback);
34+
}
35+
}
36+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Refresh.Database.Models.Levels;
2+
3+
namespace Refresh.Database.Models.Activity;
4+
5+
public class DatabaseActivityLevelGroup : DatabaseActivityGroup
6+
{
7+
public DatabaseActivityLevelGroup(GameLevel level)
8+
{
9+
this.Level = level;
10+
}
11+
12+
public override string GroupType => "level";
13+
public GameLevel Level { get; set; }
14+
}

0 commit comments

Comments
 (0)