From 5fcef3ffe7e6563a79d825984fa07c295238802a Mon Sep 17 00:00:00 2001 From: Alexa <53471801+Alexa-RR@users.noreply.github.com> Date: Sun, 12 Jul 2026 13:18:32 +0300 Subject: [PATCH] feat: Remove unnecessary push notifications for avatar updates in AdminController; update comments for clarity --- .../InfluencerPartnerProgramController.cs | 58 +++++++------------ .../Controllers/Admin/AdminController.cs | 46 ++++++--------- 2 files changed, 41 insertions(+), 63 deletions(-) diff --git a/DorkNet.Server/Controllers/API/InfluencerPartnerProgram/InfluencerPartnerProgramController.cs b/DorkNet.Server/Controllers/API/InfluencerPartnerProgram/InfluencerPartnerProgramController.cs index e596826..a6a98f4 100644 --- a/DorkNet.Server/Controllers/API/InfluencerPartnerProgram/InfluencerPartnerProgramController.cs +++ b/DorkNet.Server/Controllers/API/InfluencerPartnerProgram/InfluencerPartnerProgramController.cs @@ -1,7 +1,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using DorkNet.Models.Auth; using DorkNet.Server.Auth; using DorkNet.Server.Data; using DorkNet.Server.Data.Entities; @@ -11,6 +10,14 @@ namespace DorkNet.Server.Controllers.API.InfluencerPartnerProgram; [ApiController] public class InfluencerPartnerProgramController(DorkNetDbContext db) : ControllerBase { + // The 2023 client's influencer API (RecNet.Runtime IBEEFFGHGND) reads + // BARE scalars, NOT wrapped account objects: + // influencers → List (account ids) + // influencer → Nullable (the account id, or null) + // myinfluencer → Nullable (supported influencer's id, or null) + // Returning an object here crashes the strict reader + // ("expected:'Number Token', actual:'{'"), which is what broke the + // profile view (and the cheer flow that opens it). [HttpGet("api/influencerpartnerprogram/influencers")] [AllowAnonymous] public async Task Influencers([FromQuery] int take = 50) @@ -22,29 +29,17 @@ public class InfluencerPartnerProgramController(DorkNetDbContext db) : Controlle .Distinct() .Take(take) .ToListAsync(); - var players = await db.Players - .Where(p => creatorIds.Contains(p.Id)) - .OrderBy(p => p.Username) - .ToListAsync(); - var influencers = players.Select(ToInfluencerWire).ToList(); - return Ok(new Dictionary - { - ["Influencers"] = influencers, - ["influencers"] = influencers, - ["Accounts"] = influencers, - ["accounts"] = influencers, - }); + return Ok(creatorIds.Select(id => (int)id).ToArray()); } [HttpGet("api/influencerpartnerprogram/influencer")] [AllowAnonymous] public async Task Influencer([FromQuery] long? accountId = null, [FromQuery] string? username = null) { - var player = accountId is long id - ? await db.Players.FirstOrDefaultAsync(p => p.Id == id) - : await db.Players.FirstOrDefaultAsync(p => p.Username == username); - if (player is null) return NotFound(); - return Ok(ToInfluencerWire(player)); + var playerId = accountId is long id + ? await db.Players.Where(p => p.Id == id).Select(p => (long?)p.Id).FirstOrDefaultAsync() + : await db.Players.Where(p => p.Username == username).Select(p => (long?)p.Id).FirstOrDefaultAsync(); + return Content(playerId is long pid ? ((int)pid).ToString() : "null", "application/json"); } [HttpGet("api/influencerpartnerprogram/myinfluencer")] @@ -54,10 +49,11 @@ public class InfluencerPartnerProgramController(DorkNetDbContext db) : Controlle var me = this.RequireCurrentPlayerId(); var setting = await db.PlayerSettings .FirstOrDefaultAsync(s => s.PlayerId == me && s.Key == "influencer:supported"); - if (setting is null || !long.TryParse(setting.Value, out var influencerId)) - return Ok(new { Influencer = (object?)null }); - var player = await db.Players.FirstOrDefaultAsync(p => p.Id == influencerId); - return Ok(new { Influencer = player is null ? null : ToInfluencerWire(player) }); + return Content( + setting is not null && long.TryParse(setting.Value, out var influencerId) + ? ((int)influencerId).ToString() + : "null", + "application/json"); } [HttpPost("api/influencerpartnerprogram/support")] @@ -86,7 +82,10 @@ public class InfluencerPartnerProgramController(DorkNetDbContext db) : Controlle setting.Value = influencer.Id.ToString(); } await db.SaveChangesAsync(); - return Ok(new { Success = true, Influencer = ToInfluencerWire(influencer) }); + // Client return type is LDGADANDBIO (the fire-and-forget POST response + // handle, same as PlayerCheer create) — it only checks success and + // ignores the body, so no typed shape is required here. + return Ok(new { Success = true, Influencer = (int)influencer.Id }); } [HttpPost("api/influencerpartnerprogram/remove")] @@ -99,17 +98,4 @@ public class InfluencerPartnerProgramController(DorkNetDbContext db) : Controlle .ExecuteDeleteAsync(); return Ok(new { Success = true }); } - - private static RecNetAccount ToInfluencerWire(PlayerEntity player) => new() - { - AccountId = (int)player.Id, - RawUsername = player.Username, - Username = player.Username, - DisplayName = player.DisplayName ?? player.Username, - ProfileImage = player.ProfileImageName ?? string.Empty, - TreatAsJunior = false, - HasBirthday = true, - Platforms = 1, - CreatedAt = player.CreatedAt == default ? DateTime.UtcNow : player.CreatedAt, - }; } diff --git a/DorkNet.Server/Controllers/Admin/AdminController.cs b/DorkNet.Server/Controllers/Admin/AdminController.cs index d339dce..d1a3cbd 100644 --- a/DorkNet.Server/Controllers/Admin/AdminController.cs +++ b/DorkNet.Server/Controllers/Admin/AdminController.cs @@ -2214,12 +2214,10 @@ public class AdminController( await LogAsync("reset_avatar", "player", id, ""); await db.SaveChangesAsync(); - // Push a profile update so the affected watch re-fetches its - // avatar without waiting for the next scene load. - await notifications.NotifyAsync(id, - PushNotificationId.SubscriptionUpdateProfile, - new { Reason = "AdminAvatarReset" }); - + // No push: the affected client refetches its avatar on the next + // scene load. The old SubscriptionUpdateProfile {Reason:"…"} blob + // couldn't force an avatar refetch (wrong channel) and only decoded + // to a blank account ("Orphan player account (0)"). return Ok(new { avatar.PlayerId, @@ -2251,10 +2249,9 @@ public class AdminController( await LogAsync("set_avatar", "player", id, body.OutfitSelections ?? ""); await db.SaveChangesAsync(); - await notifications.NotifyAsync(id, - PushNotificationId.SubscriptionUpdateProfile, - new { Reason = "AdminAvatarUpdate" }); - + // No push: avatar changes propagate to other players in-room via + // Photon, and the affected client refetches on next scene load. The + // old SubscriptionUpdateProfile blob only spawned a blank account. return Ok(new { avatar.PlayerId, avatar.OutfitSelections, avatar.HairColor, avatar.SkinColor }); } @@ -2291,10 +2288,9 @@ public class AdminController( await LogAsync("grant_item", "player", id, $"{body.ItemId} x{qty}"); await db.SaveChangesAsync(); - await notifications.NotifyAsync(id, - PushNotificationId.SubscriptionUpdateProfile, - new { Reason = "InventoryGrant", body.ItemId, Quantity = qty }); - + // No push: the client shows the granted item on its next avatar + // fetch. The old SubscriptionUpdateProfile blob only spawned a + // blank account ("Orphan player account (0)"). return Ok(new { granted = body.ItemId, quantity = qty }); } @@ -2353,10 +2349,9 @@ public class AdminController( $"cosmetics+{addedCosmetics} (catalog={catalog.Count}) slugs+{addedSlugs}"); await db.SaveChangesAsync(); - await notifications.NotifyAsync(id, - PushNotificationId.SubscriptionUpdateProfile, - new { Reason = "AdminUnlockAll" }); - + // No push: the client shows the unlocked items on its next avatar + // fetch. The old SubscriptionUpdateProfile blob only spawned a + // blank account ("Orphan player account (0)"). return Ok(new { id, @@ -2447,10 +2442,10 @@ public class AdminController( await LogAsync("set_level", "player", id, $"{previous} -> {newLevel}"); await db.SaveChangesAsync(); + // AccountChanged sends the correct full account. The old extra + // SubscriptionUpdateProfile {Reason:"AdminLevelSet",…} blob was a + // redundant blank-account push ("Orphan player account (0)"). await notifications.AccountChanged(p); - await notifications.NotifyAsync(id, - PushNotificationId.SubscriptionUpdateProfile, - new { Reason = "AdminLevelSet", Level = p.Level, XP = p.XP, PreviousLevel = previous }); return Ok(new { p.Id, p.Level, p.XP }); } @@ -2497,12 +2492,9 @@ public class AdminController( $"inserted={missing.Count} types=[{string.Join(",", missing)}]"); await db.SaveChangesAsync(); - // Nudge the watch to re-fetch its cheer list so the pinned-cheer - // picker shows the newly-unlocked badges without a relog. - await notifications.NotifyAsync(id, - PushNotificationId.SubscriptionUpdateProfile, - new { Reason = "AdminCheerUnlock", Inserted = missing.Count }); - + // No push: the pinned-cheer picker refetches the cheer list on next + // open. The old SubscriptionUpdateProfile blob only spawned a blank + // account ("Orphan player account (0)"). return Ok(new { id, inserted = missing.Count, types = missing }); }