From b327878f925aa24b54400a12db6638a4b1465e22 Mon Sep 17 00:00:00 2001 From: Rory& Date: Tue, 23 Jun 2026 08:40:03 +0200 Subject: [PATCH] Include presence in op14 response --- .../Spacebar.DataMappings.Generic/Member.cs | 43 +++++++++++++++++++ .../Spacebar.DataMappings.Generic/Session.cs | 19 ++++++++ .../Spacebar.DataMappings.Generic/User.cs | 5 +++ .../Controllers/Op14Controller.cs | 8 ++-- .../Extensions/Db/UserExtensions.cs | 2 +- 5 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 extra/admin-api/DataMappings/Spacebar.DataMappings.Generic/Session.cs diff --git a/extra/admin-api/DataMappings/Spacebar.DataMappings.Generic/Member.cs b/extra/admin-api/DataMappings/Spacebar.DataMappings.Generic/Member.cs index 1693edd3b..3f7c4fb63 100644 --- a/extra/admin-api/DataMappings/Spacebar.DataMappings.Generic/Member.cs +++ b/extra/admin-api/DataMappings/Spacebar.DataMappings.Generic/Member.cs @@ -20,4 +20,47 @@ public static class MemberExtensions Roles = member.Roles.Select(x => x.Id).ToList() }; } + + public static MemberWithPresence ToPublicMemberWithPresence(this Models.Db.Models.Member member, PartialUser? partialUser = null) + { + var onlineSessions = member.IdNavigation.Sessions.Where(x => x.Status is not ("offline" or "invisible" or "unknown")).ToList(); + var presence = new Presence() + { + User = partialUser ?? member.IdNavigation.ToPartialUser(), + Status = onlineSessions.OrderByDescending(x => x.LastSeen).First().Status, + GuildId = member.GuildId, + Activities = onlineSessions.SelectMany(x => x.GetActivities()).ToList(), + ClientStatus = onlineSessions.Aggregate(new Presence.ClientStatuses() { }, (res, sess) => + { + var cs = sess.GetClientStatuses(); + string? Maybe(string? source) + { + if (!string.IsNullOrWhiteSpace(source) && source is not ("offline" or "invisible" or "unknown")) return source; + return null; + } + + res.Desktop ??= Maybe(cs.Desktop); + res.Embedded ??= Maybe(cs.Embedded); + res.Mobile ??= Maybe(cs.Mobile); + res.Vr ??= Maybe(cs.Vr); + res.Web ??= Maybe(cs.Web); + + return res; + }) + }; + + return new() + { + User = partialUser ?? member.IdNavigation.ToPartialUser(), + AvatarDecorationData = member.AvatarDecorationData, + Avatar = string.IsNullOrWhiteSpace(member.Avatar) ? null : member.Avatar, + Banner = string.IsNullOrWhiteSpace(member.Banner) ? null : member.Banner, + Collectibles = member.Collectibles, + DisplayNameStyles = JsonSerializer.Deserialize(member.DisplayNameStyles ?? "null"), + Bio = string.IsNullOrWhiteSpace(member.Bio) ? null : member.Bio, + Nick = string.IsNullOrWhiteSpace(member.Nick) ? null : member.Nick, + Roles = member.Roles.Select(x => x.Id).ToList(), + Presence = presence + }; + } } \ No newline at end of file diff --git a/extra/admin-api/DataMappings/Spacebar.DataMappings.Generic/Session.cs b/extra/admin-api/DataMappings/Spacebar.DataMappings.Generic/Session.cs new file mode 100644 index 000000000..ef25d48fd --- /dev/null +++ b/extra/admin-api/DataMappings/Spacebar.DataMappings.Generic/Session.cs @@ -0,0 +1,19 @@ +using System.Text.Json; +using System.Text.Json.Nodes; +using Spacebar.Models.Generic; + +namespace Spacebar.DataMappings.Generic; + +public static class Session +{ + // TODO activity type + public static List GetActivities(this Models.Db.Models.Session session) + { + return JsonSerializer.Deserialize>(session.Activities)!; + } + + public static Presence.ClientStatuses GetClientStatuses(this Models.Db.Models.Session session) + { + return JsonSerializer.Deserialize(session.ClientStatus)!; + } +} \ No newline at end of file diff --git a/extra/admin-api/DataMappings/Spacebar.DataMappings.Generic/User.cs b/extra/admin-api/DataMappings/Spacebar.DataMappings.Generic/User.cs index 95bce884a..3672599f3 100644 --- a/extra/admin-api/DataMappings/Spacebar.DataMappings.Generic/User.cs +++ b/extra/admin-api/DataMappings/Spacebar.DataMappings.Generic/User.cs @@ -25,4 +25,9 @@ public static class User System = user.System, }; } + + extension(Models.Db.Models.User user) + { + public string Tag => $"{user.Username}#{user.Discriminator}"; + } } \ No newline at end of file diff --git a/extra/admin-api/Spacebar.Offload/Controllers/Op14Controller.cs b/extra/admin-api/Spacebar.Offload/Controllers/Op14Controller.cs index 79369de1e..9f1e655aa 100644 --- a/extra/admin-api/Spacebar.Offload/Controllers/Op14Controller.cs +++ b/extra/admin-api/Spacebar.Offload/Controllers/Op14Controller.cs @@ -142,7 +142,7 @@ public class Op14Controller(ILogger logger, SpacebarAspNetAuthen if (members.Count > 0) { memberList.Add(new RoleEntry() { Group = new() { Id = role.ToString(), Count = members.Count } }); - memberList.AddRange(members.Select(m => (IMemberListEntry)new MemberEntry() { Member = m.ToPublicMember() })); + memberList.AddRange(members.Select(m => (IMemberListEntry)new MemberEntry() { Member = m.ToPublicMemberWithPresence() })); } handledRoles.Add(role); @@ -167,7 +167,7 @@ public class Op14Controller(ILogger logger, SpacebarAspNetAuthen if (onlineMembers.Count > 0) { memberList.Add(new RoleEntry() { Group = new() { Id = "online", Count = onlineMembers.Count } }); - memberList.AddRange(onlineMembers.Select(m => (IMemberListEntry)new MemberEntry() { Member = m.ToPublicMember() })); + memberList.AddRange(onlineMembers.Select(m => (IMemberListEntry)new MemberEntry() { Member = m.ToPublicMemberWithPresence() })); } if (memberList.Count < 2000) @@ -194,7 +194,7 @@ public class Op14Controller(ILogger logger, SpacebarAspNetAuthen { Group = new() { Id = "offline", Count = offlineMembers.Count } }); - memberList.AddRange(offlineMembers.Select(m => (IMemberListEntry)new MemberEntry() { Member = m.ToPublicMember() })); + memberList.AddRange(offlineMembers.Select(m => (IMemberListEntry)new MemberEntry() { Member = m.ToPublicMemberWithPresence() })); } } @@ -226,5 +226,5 @@ internal struct RoleEntry : IMemberListEntry internal struct MemberEntry : IMemberListEntry { [JsonPropertyName("member")] - public Member Member { get; set; } + public MemberWithPresence Member { get; set; } } \ No newline at end of file diff --git a/extra/admin-api/Spacebar.Offload/Extensions/Db/UserExtensions.cs b/extra/admin-api/Spacebar.Offload/Extensions/Db/UserExtensions.cs index 27b4fb16f..d04fdc3a0 100644 --- a/extra/admin-api/Spacebar.Offload/Extensions/Db/UserExtensions.cs +++ b/extra/admin-api/Spacebar.Offload/Extensions/Db/UserExtensions.cs @@ -4,6 +4,6 @@ namespace Spacebar.GatewayOffload.Extensions.Db; public static class UserExtensions { extension(User user) { - public string Tag => $"{user.Username}#{user.Discriminator}"; + } } \ No newline at end of file