mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-25 23:18:44 -07:00
feat: Update PlayerCheer and Avatar handling; enhance API responses and add new fields for 2023 client compatibility
This commit is contained in:
+110
-61
@@ -1,32 +1,114 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Text.Json;
|
||||
using DorkNet.Server.Auth;
|
||||
using DorkNet.Server.Data;
|
||||
using DorkNet.Server.Data.Entities;
|
||||
|
||||
namespace DorkNet.Server.Controllers.PlatformNotifications;
|
||||
|
||||
/// <summary>
|
||||
/// platformnotifications.rec.net — the 2023 client's platform push-
|
||||
/// notification preference service (RecNet.Runtime LELAJKMOMIA; the
|
||||
/// service host enum value 15 resolves to the PlatformNotifications
|
||||
/// entry of the service map, relative paths "preferences",
|
||||
/// "config/categories", "badge", "device").
|
||||
///
|
||||
/// Wire contracts verified against the 2023.03.21 ISIL decompile:
|
||||
///
|
||||
/// GET preferences → RecNet.PlatformNotificationPreferencesDTO — an
|
||||
/// OBJECT whose only key is "MutedCategories" (a list of category
|
||||
/// enum values). Generated reader JLHCGPANJCB.txt:151-185 registers
|
||||
/// exactly that key. LELAJKMOMIA.txt:1102 (DCGHGFDPAMM) issues the
|
||||
/// GET; an array/empty body throws the strict-reader error seen in
|
||||
/// Player.log:1409-1711 ("expected:'{', actual:'['" /
|
||||
/// "Malformed Response: '[]'" → "Failed to get notification
|
||||
/// preferences").
|
||||
///
|
||||
/// PUT preferences → LELAJKMOMIA.txt:1480 (KKPAKGOCPEA) sends the
|
||||
/// same DTO ({"MutedCategories":[...]}) with HTTP verb 3 = PUT
|
||||
/// (verb table HNLCIDLIIBO.txt:878-903). Fire-and-forget
|
||||
/// (LDGADANDBIO) — response body ignored.
|
||||
///
|
||||
/// GET config/categories → parsed as envelope MKIFDCBPEAD
|
||||
/// {"Results":[...],"TotalResults":N} (reader JBGKGCLPCHP.txt:203-238)
|
||||
/// then converted via Func<MKIFDCBPEAD, List<PlatformNotification-
|
||||
/// CategoryConfigDTO>> (LELAJKMOMIA.txt:1930 region). Each item is
|
||||
/// {"CategoryId","Importance","Name","Description","IsMuteable"}
|
||||
/// (reader JNFDPPCIPHG.txt:371-462).
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class PlatformNotificationsController(DorkNetDbContext db) : ControllerBase
|
||||
{
|
||||
private long Me => this.RequireCurrentPlayerId();
|
||||
|
||||
/// <summary>The category catalogue we expose. CategoryId values are
|
||||
/// round-tripped between config/categories and MutedCategories, so
|
||||
/// they only need to be internally consistent.</summary>
|
||||
private static readonly (int CategoryId, string Name, string Description)[] CategoryCatalog =
|
||||
{
|
||||
(1, "Messages", "Direct messages from other players"),
|
||||
(2, "Friend Requests", "Incoming friend requests"),
|
||||
(3, "Event Invites", "Invitations to events"),
|
||||
(4, "Announcements", "News and announcements from Rec Room"),
|
||||
};
|
||||
|
||||
[HttpGet("/preferences")]
|
||||
[HttpGet("/platformnotifications/preferences")]
|
||||
public async Task<IActionResult> Preferences()
|
||||
{
|
||||
var row = await db.NotificationPrefs.FirstOrDefaultAsync(p => p.PlayerId == Me);
|
||||
return Ok(ToPreferencesWire(row));
|
||||
// Exact DTO shape: {"MutedCategories":[...]} — see class doc.
|
||||
return Ok(new { MutedCategories = MutedCategoriesFor(row) });
|
||||
}
|
||||
|
||||
/// <summary>PUT preferences — body is the same DTO
|
||||
/// ({"MutedCategories":[1,4]}). Parsed manually so we tolerate any
|
||||
/// key casing and missing/null lists. Response body is ignored by
|
||||
/// the client (LDGADANDBIO), but we echo the stored DTO anyway.</summary>
|
||||
[HttpPut("/preferences")]
|
||||
[HttpPost("/preferences")]
|
||||
[HttpPut("/platformnotifications/preferences")]
|
||||
[HttpPost("/platformnotifications/preferences")]
|
||||
public async Task<IActionResult> SetPreferences([FromBody] PlatformNotificationPrefsRequest? body)
|
||||
public async Task<IActionResult> SetPreferences()
|
||||
{
|
||||
List<int>? muted = null;
|
||||
string raw;
|
||||
using (var reader = new StreamReader(Request.Body))
|
||||
raw = await reader.ReadToEndAsync();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(raw))
|
||||
{
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(raw);
|
||||
if (doc.RootElement.ValueKind == JsonValueKind.Object)
|
||||
{
|
||||
foreach (var prop in doc.RootElement.EnumerateObject())
|
||||
{
|
||||
if (!prop.Name.Equals("MutedCategories", StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
if (prop.Value.ValueKind != JsonValueKind.Array) continue;
|
||||
muted = new List<int>();
|
||||
foreach (var el in prop.Value.EnumerateArray())
|
||||
{
|
||||
if (el.ValueKind == JsonValueKind.Number && el.TryGetInt32(out var v))
|
||||
muted.Add(v);
|
||||
else if (el.ValueKind == JsonValueKind.String
|
||||
&& int.TryParse(el.GetString(), out var s))
|
||||
muted.Add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
// Non-JSON body — treat as "no change".
|
||||
}
|
||||
}
|
||||
|
||||
var row = await db.NotificationPrefs.FirstOrDefaultAsync(p => p.PlayerId == Me);
|
||||
if (row is null)
|
||||
{
|
||||
@@ -38,85 +120,52 @@ public class PlatformNotificationsController(DorkNetDbContext db) : ControllerBa
|
||||
db.NotificationPrefs.Add(row);
|
||||
}
|
||||
|
||||
if (body is not null)
|
||||
if (muted is not null)
|
||||
{
|
||||
row.AllowAll = body.AllowAll ?? body.Enabled ?? row.AllowAll;
|
||||
row.AllowMessage = body.AllowMessages ?? body.Messages ?? row.AllowMessage;
|
||||
row.AllowFriendRequest = body.AllowFriendRequests ?? body.FriendRequests ?? row.AllowFriendRequest;
|
||||
row.AllowEventInvite = body.AllowEventInvites ?? body.EventInvites ?? row.AllowEventInvite;
|
||||
row.AllowAnnouncements = body.AllowAnnouncements ?? body.Announcements ?? row.AllowAnnouncements;
|
||||
row.AllowMessage = !muted.Contains(1);
|
||||
row.AllowFriendRequest = !muted.Contains(2);
|
||||
row.AllowEventInvite = !muted.Contains(3);
|
||||
row.AllowAnnouncements = !muted.Contains(4);
|
||||
row.UpdatedAt = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
return Ok(ToPreferencesWire(row));
|
||||
return Ok(new { MutedCategories = MutedCategoriesFor(row) });
|
||||
}
|
||||
|
||||
/// <summary>GET config/categories — {"Results":[...],"TotalResults":N}
|
||||
/// envelope of PlatformNotificationCategoryConfigDTO items.</summary>
|
||||
[HttpGet("/config/categories")]
|
||||
[HttpGet("/platformnotifications/config/categories")]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Categories()
|
||||
{
|
||||
var categories = new[]
|
||||
{
|
||||
Category(1, "messages", "Messages"),
|
||||
Category(2, "friendRequests", "Friend Requests"),
|
||||
Category(3, "eventInvites", "Event Invites"),
|
||||
Category(4, "announcements", "Announcements"),
|
||||
};
|
||||
var categories = CategoryCatalog
|
||||
.Select(c => new
|
||||
{
|
||||
c.CategoryId,
|
||||
Importance = 0,
|
||||
c.Name,
|
||||
c.Description,
|
||||
IsMuteable = true,
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
Categories = categories,
|
||||
Results = categories,
|
||||
TotalResults = categories.Length,
|
||||
});
|
||||
}
|
||||
|
||||
private static object Category(int id, string key, string name) => new
|
||||
private static int[] MutedCategoriesFor(NotificationPrefsEntity? row)
|
||||
{
|
||||
Id = id,
|
||||
CategoryId = id,
|
||||
Key = key,
|
||||
Name = name,
|
||||
DisplayName = name,
|
||||
IsEnabled = true,
|
||||
Enabled = true,
|
||||
DefaultEnabled = true,
|
||||
};
|
||||
|
||||
private static object ToPreferencesWire(NotificationPrefsEntity? row) => new
|
||||
{
|
||||
AllowAll = row?.AllowAll ?? true,
|
||||
Enabled = row?.AllowAll ?? true,
|
||||
AllowMessages = row?.AllowMessage ?? true,
|
||||
Messages = row?.AllowMessage ?? true,
|
||||
AllowFriendRequests = row?.AllowFriendRequest ?? true,
|
||||
FriendRequests = row?.AllowFriendRequest ?? true,
|
||||
AllowEventInvites = row?.AllowEventInvite ?? true,
|
||||
EventInvites = row?.AllowEventInvite ?? true,
|
||||
AllowAnnouncements = row?.AllowAnnouncements ?? true,
|
||||
Announcements = row?.AllowAnnouncements ?? true,
|
||||
Categories = new[]
|
||||
{
|
||||
new { CategoryId = 1, Key = "messages", Enabled = row?.AllowMessage ?? true },
|
||||
new { CategoryId = 2, Key = "friendRequests", Enabled = row?.AllowFriendRequest ?? true },
|
||||
new { CategoryId = 3, Key = "eventInvites", Enabled = row?.AllowEventInvite ?? true },
|
||||
new { CategoryId = 4, Key = "announcements", Enabled = row?.AllowAnnouncements ?? true },
|
||||
},
|
||||
};
|
||||
|
||||
public sealed class PlatformNotificationPrefsRequest
|
||||
{
|
||||
public bool? AllowAll { get; set; }
|
||||
public bool? Enabled { get; set; }
|
||||
public bool? AllowMessages { get; set; }
|
||||
public bool? Messages { get; set; }
|
||||
public bool? AllowFriendRequests { get; set; }
|
||||
public bool? FriendRequests { get; set; }
|
||||
public bool? AllowEventInvites { get; set; }
|
||||
public bool? EventInvites { get; set; }
|
||||
public bool? AllowAnnouncements { get; set; }
|
||||
public bool? Announcements { get; set; }
|
||||
if (row is null) return Array.Empty<int>();
|
||||
var muted = new List<int>(4);
|
||||
if (!row.AllowMessage) muted.Add(1);
|
||||
if (!row.AllowFriendRequest) muted.Add(2);
|
||||
if (!row.AllowEventInvite) muted.Add(3);
|
||||
if (!row.AllowAnnouncements) muted.Add(4);
|
||||
return muted.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user