mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-25 23:18:44 -07:00
feat: Remove unnecessary push notifications for avatar updates in AdminController; update comments for clarity
This commit is contained in:
+22
-36
@@ -1,7 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using DorkNet.Models.Auth;
|
|
||||||
using DorkNet.Server.Auth;
|
using DorkNet.Server.Auth;
|
||||||
using DorkNet.Server.Data;
|
using DorkNet.Server.Data;
|
||||||
using DorkNet.Server.Data.Entities;
|
using DorkNet.Server.Data.Entities;
|
||||||
@@ -11,6 +10,14 @@ namespace DorkNet.Server.Controllers.API.InfluencerPartnerProgram;
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
public class InfluencerPartnerProgramController(DorkNetDbContext db) : ControllerBase
|
public class InfluencerPartnerProgramController(DorkNetDbContext db) : ControllerBase
|
||||||
{
|
{
|
||||||
|
// The 2023 client's influencer API (RecNet.Runtime IBEEFFGHGND) reads
|
||||||
|
// BARE scalars, NOT wrapped account objects:
|
||||||
|
// influencers → List<Int32> (account ids)
|
||||||
|
// influencer → Nullable<Int32> (the account id, or null)
|
||||||
|
// myinfluencer → Nullable<Int32> (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")]
|
[HttpGet("api/influencerpartnerprogram/influencers")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public async Task<IActionResult> Influencers([FromQuery] int take = 50)
|
public async Task<IActionResult> Influencers([FromQuery] int take = 50)
|
||||||
@@ -22,29 +29,17 @@ public class InfluencerPartnerProgramController(DorkNetDbContext db) : Controlle
|
|||||||
.Distinct()
|
.Distinct()
|
||||||
.Take(take)
|
.Take(take)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
var players = await db.Players
|
return Ok(creatorIds.Select(id => (int)id).ToArray());
|
||||||
.Where(p => creatorIds.Contains(p.Id))
|
|
||||||
.OrderBy(p => p.Username)
|
|
||||||
.ToListAsync();
|
|
||||||
var influencers = players.Select(ToInfluencerWire).ToList();
|
|
||||||
return Ok(new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
["Influencers"] = influencers,
|
|
||||||
["influencers"] = influencers,
|
|
||||||
["Accounts"] = influencers,
|
|
||||||
["accounts"] = influencers,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("api/influencerpartnerprogram/influencer")]
|
[HttpGet("api/influencerpartnerprogram/influencer")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public async Task<IActionResult> Influencer([FromQuery] long? accountId = null, [FromQuery] string? username = null)
|
public async Task<IActionResult> Influencer([FromQuery] long? accountId = null, [FromQuery] string? username = null)
|
||||||
{
|
{
|
||||||
var player = accountId is long id
|
var playerId = accountId is long id
|
||||||
? await db.Players.FirstOrDefaultAsync(p => p.Id == id)
|
? await db.Players.Where(p => p.Id == id).Select(p => (long?)p.Id).FirstOrDefaultAsync()
|
||||||
: await db.Players.FirstOrDefaultAsync(p => p.Username == username);
|
: await db.Players.Where(p => p.Username == username).Select(p => (long?)p.Id).FirstOrDefaultAsync();
|
||||||
if (player is null) return NotFound();
|
return Content(playerId is long pid ? ((int)pid).ToString() : "null", "application/json");
|
||||||
return Ok(ToInfluencerWire(player));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("api/influencerpartnerprogram/myinfluencer")]
|
[HttpGet("api/influencerpartnerprogram/myinfluencer")]
|
||||||
@@ -54,10 +49,11 @@ public class InfluencerPartnerProgramController(DorkNetDbContext db) : Controlle
|
|||||||
var me = this.RequireCurrentPlayerId();
|
var me = this.RequireCurrentPlayerId();
|
||||||
var setting = await db.PlayerSettings
|
var setting = await db.PlayerSettings
|
||||||
.FirstOrDefaultAsync(s => s.PlayerId == me && s.Key == "influencer:supported");
|
.FirstOrDefaultAsync(s => s.PlayerId == me && s.Key == "influencer:supported");
|
||||||
if (setting is null || !long.TryParse(setting.Value, out var influencerId))
|
return Content(
|
||||||
return Ok(new { Influencer = (object?)null });
|
setting is not null && long.TryParse(setting.Value, out var influencerId)
|
||||||
var player = await db.Players.FirstOrDefaultAsync(p => p.Id == influencerId);
|
? ((int)influencerId).ToString()
|
||||||
return Ok(new { Influencer = player is null ? null : ToInfluencerWire(player) });
|
: "null",
|
||||||
|
"application/json");
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("api/influencerpartnerprogram/support")]
|
[HttpPost("api/influencerpartnerprogram/support")]
|
||||||
@@ -86,7 +82,10 @@ public class InfluencerPartnerProgramController(DorkNetDbContext db) : Controlle
|
|||||||
setting.Value = influencer.Id.ToString();
|
setting.Value = influencer.Id.ToString();
|
||||||
}
|
}
|
||||||
await db.SaveChangesAsync();
|
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")]
|
[HttpPost("api/influencerpartnerprogram/remove")]
|
||||||
@@ -99,17 +98,4 @@ public class InfluencerPartnerProgramController(DorkNetDbContext db) : Controlle
|
|||||||
.ExecuteDeleteAsync();
|
.ExecuteDeleteAsync();
|
||||||
return Ok(new { Success = true });
|
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,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2214,12 +2214,10 @@ public class AdminController(
|
|||||||
await LogAsync("reset_avatar", "player", id, "");
|
await LogAsync("reset_avatar", "player", id, "");
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
// Push a profile update so the affected watch re-fetches its
|
// No push: the affected client refetches its avatar on the next
|
||||||
// avatar without waiting for the next scene load.
|
// scene load. The old SubscriptionUpdateProfile {Reason:"…"} blob
|
||||||
await notifications.NotifyAsync(id,
|
// couldn't force an avatar refetch (wrong channel) and only decoded
|
||||||
PushNotificationId.SubscriptionUpdateProfile,
|
// to a blank account ("Orphan player account (0)").
|
||||||
new { Reason = "AdminAvatarReset" });
|
|
||||||
|
|
||||||
return Ok(new
|
return Ok(new
|
||||||
{
|
{
|
||||||
avatar.PlayerId,
|
avatar.PlayerId,
|
||||||
@@ -2251,10 +2249,9 @@ public class AdminController(
|
|||||||
await LogAsync("set_avatar", "player", id, body.OutfitSelections ?? "");
|
await LogAsync("set_avatar", "player", id, body.OutfitSelections ?? "");
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
await notifications.NotifyAsync(id,
|
// No push: avatar changes propagate to other players in-room via
|
||||||
PushNotificationId.SubscriptionUpdateProfile,
|
// Photon, and the affected client refetches on next scene load. The
|
||||||
new { Reason = "AdminAvatarUpdate" });
|
// old SubscriptionUpdateProfile blob only spawned a blank account.
|
||||||
|
|
||||||
return Ok(new { avatar.PlayerId, avatar.OutfitSelections, avatar.HairColor, avatar.SkinColor });
|
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 LogAsync("grant_item", "player", id, $"{body.ItemId} x{qty}");
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
await notifications.NotifyAsync(id,
|
// No push: the client shows the granted item on its next avatar
|
||||||
PushNotificationId.SubscriptionUpdateProfile,
|
// fetch. The old SubscriptionUpdateProfile blob only spawned a
|
||||||
new { Reason = "InventoryGrant", body.ItemId, Quantity = qty });
|
// blank account ("Orphan player account (0)").
|
||||||
|
|
||||||
return Ok(new { granted = body.ItemId, quantity = qty });
|
return Ok(new { granted = body.ItemId, quantity = qty });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2353,10 +2349,9 @@ public class AdminController(
|
|||||||
$"cosmetics+{addedCosmetics} (catalog={catalog.Count}) slugs+{addedSlugs}");
|
$"cosmetics+{addedCosmetics} (catalog={catalog.Count}) slugs+{addedSlugs}");
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
await notifications.NotifyAsync(id,
|
// No push: the client shows the unlocked items on its next avatar
|
||||||
PushNotificationId.SubscriptionUpdateProfile,
|
// fetch. The old SubscriptionUpdateProfile blob only spawned a
|
||||||
new { Reason = "AdminUnlockAll" });
|
// blank account ("Orphan player account (0)").
|
||||||
|
|
||||||
return Ok(new
|
return Ok(new
|
||||||
{
|
{
|
||||||
id,
|
id,
|
||||||
@@ -2447,10 +2442,10 @@ public class AdminController(
|
|||||||
|
|
||||||
await LogAsync("set_level", "player", id, $"{previous} -> {newLevel}");
|
await LogAsync("set_level", "player", id, $"{previous} -> {newLevel}");
|
||||||
await db.SaveChangesAsync();
|
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.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 });
|
return Ok(new { p.Id, p.Level, p.XP });
|
||||||
}
|
}
|
||||||
@@ -2497,12 +2492,9 @@ public class AdminController(
|
|||||||
$"inserted={missing.Count} types=[{string.Join(",", missing)}]");
|
$"inserted={missing.Count} types=[{string.Join(",", missing)}]");
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
// Nudge the watch to re-fetch its cheer list so the pinned-cheer
|
// No push: the pinned-cheer picker refetches the cheer list on next
|
||||||
// picker shows the newly-unlocked badges without a relog.
|
// open. The old SubscriptionUpdateProfile blob only spawned a blank
|
||||||
await notifications.NotifyAsync(id,
|
// account ("Orphan player account (0)").
|
||||||
PushNotificationId.SubscriptionUpdateProfile,
|
|
||||||
new { Reason = "AdminCheerUnlock", Inserted = missing.Count });
|
|
||||||
|
|
||||||
return Ok(new { id, inserted = missing.Count, types = missing });
|
return Ok(new { id, inserted = missing.Count, types = missing });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user