Forgot unversioned xd
This commit is contained in:
147
SVSim.EmulatedEntrypoint/Controllers/AdminController.cs
Normal file
147
SVSim.EmulatedEntrypoint/Controllers/AdminController.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SVSim.Database;
|
||||
using SVSim.Database.Enums;
|
||||
using SVSim.Database.Models;
|
||||
using SVSim.Database.Repositories.Viewer;
|
||||
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Admin;
|
||||
using SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Admin;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Util endpoints for bootstrapping the dev environment. Anonymous-allowed today — security
|
||||
/// audit pending (don't expose these to the public internet).
|
||||
/// </summary>
|
||||
public class AdminController : SVSimController
|
||||
{
|
||||
private readonly IViewerRepository _viewerRepository;
|
||||
private readonly SVSimDbContext _dbContext;
|
||||
|
||||
public AdminController(IViewerRepository viewerRepository, SVSimDbContext dbContext)
|
||||
{
|
||||
_viewerRepository = viewerRepository;
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upsert a viewer from external data (typically captured from the live game via the
|
||||
/// SVSimLoader dump). Matches existing viewers by SteamId; creates a new one if missing.
|
||||
/// Only essential fields are imported today — extend as needed.
|
||||
/// </summary>
|
||||
[AllowAnonymous]
|
||||
[HttpPost("import_viewer")]
|
||||
public async Task<ActionResult<ImportViewerResponse>> ImportViewer(ImportViewerRequest request)
|
||||
{
|
||||
if (request.SteamId == 0)
|
||||
{
|
||||
return BadRequest("steam_id is required");
|
||||
}
|
||||
|
||||
// SocialAccountConnection is [Owned]-by-Viewer — can't query the owned table directly;
|
||||
// look up the Viewer with a matching owned connection instead.
|
||||
var existing = await _dbContext.Viewers
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(v => v.SocialAccountConnections.Any(sac =>
|
||||
sac.AccountType == SocialAccountType.Steam && sac.AccountId == request.SteamId));
|
||||
|
||||
long viewerId;
|
||||
bool wasCreated;
|
||||
|
||||
if (existing is null)
|
||||
{
|
||||
var created = await _viewerRepository.RegisterViewer(
|
||||
request.DisplayName ?? "Imported Viewer",
|
||||
SocialAccountType.Steam,
|
||||
request.SteamId);
|
||||
viewerId = created.Id;
|
||||
wasCreated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
viewerId = existing.Id;
|
||||
wasCreated = false;
|
||||
}
|
||||
|
||||
// Reload with all the nav properties we need to mutate. RegisterViewer SaveChanges'd
|
||||
// already, so we re-fetch with full graph and apply the updates.
|
||||
var viewer = await _dbContext.Viewers
|
||||
.Include(v => v.Info).ThenInclude(i => i.SelectedEmblem)
|
||||
.Include(v => v.Info).ThenInclude(i => i.SelectedDegree)
|
||||
.Include(v => v.Currency)
|
||||
.Include(v => v.MissionData)
|
||||
.Include(v => v.Classes).ThenInclude(c => c.Class)
|
||||
.Include(v => v.Sleeves)
|
||||
.Include(v => v.Emblems)
|
||||
.Include(v => v.Degrees)
|
||||
.Include(v => v.LeaderSkins)
|
||||
.Include(v => v.MyPageBackgrounds)
|
||||
.FirstAsync(v => v.Id == viewerId);
|
||||
|
||||
if (request.DisplayName is not null) viewer.DisplayName = request.DisplayName;
|
||||
if (request.CountryCode is not null) viewer.Info.CountryCode = request.CountryCode;
|
||||
if (request.TutorialState.HasValue) viewer.MissionData.TutorialState = request.TutorialState.Value;
|
||||
|
||||
if (request.Currency is not null)
|
||||
{
|
||||
if (request.Currency.Crystals.HasValue) viewer.Currency.Crystals = request.Currency.Crystals.Value;
|
||||
if (request.Currency.Rupees.HasValue) viewer.Currency.Rupees = request.Currency.Rupees.Value;
|
||||
if (request.Currency.RedEther.HasValue) viewer.Currency.RedEther = request.Currency.RedEther.Value;
|
||||
}
|
||||
|
||||
if (request.SelectedEmblemId.HasValue)
|
||||
{
|
||||
var emblem = await _dbContext.Emblems.FindAsync(request.SelectedEmblemId.Value);
|
||||
if (emblem is not null) viewer.Info.SelectedEmblem = emblem;
|
||||
}
|
||||
if (request.SelectedDegreeId.HasValue)
|
||||
{
|
||||
var degree = await _dbContext.Degrees.FindAsync(request.SelectedDegreeId.Value);
|
||||
if (degree is not null) viewer.Info.SelectedDegree = degree;
|
||||
}
|
||||
|
||||
await ReplaceOwned(viewer.Sleeves, request.OwnedSleeveIds, _dbContext.Sleeves);
|
||||
await ReplaceOwned(viewer.Emblems, request.OwnedEmblemIds, _dbContext.Emblems);
|
||||
await ReplaceOwned(viewer.Degrees, request.OwnedDegreeIds, _dbContext.Degrees);
|
||||
await ReplaceOwned(viewer.LeaderSkins, request.OwnedLeaderSkinIds, _dbContext.LeaderSkins);
|
||||
await ReplaceOwned(viewer.MyPageBackgrounds, request.OwnedMyPageBackgroundIds, _dbContext.MyPageBackgrounds);
|
||||
|
||||
if (request.Classes is not null)
|
||||
{
|
||||
foreach (var importClass in request.Classes)
|
||||
{
|
||||
var existingClass = viewer.Classes.FirstOrDefault(c => c.Class.Id == importClass.ClassId);
|
||||
if (existingClass is not null)
|
||||
{
|
||||
existingClass.Level = importClass.Level;
|
||||
existingClass.Exp = importClass.Exp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
return new ImportViewerResponse
|
||||
{
|
||||
ViewerId = viewer.Id,
|
||||
ShortUdid = viewer.ShortUdid,
|
||||
WasCreated = wasCreated
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the owned-collection with the master rows matching the supplied ids.
|
||||
/// Null `ids` is a no-op (preserve existing). Empty list clears the collection.
|
||||
/// </summary>
|
||||
private async Task ReplaceOwned<TEntity>(List<TEntity> owned, List<int>? ids, DbSet<TEntity> table)
|
||||
where TEntity : class
|
||||
{
|
||||
if (ids is null) return;
|
||||
owned.Clear();
|
||||
if (ids.Count == 0) return;
|
||||
|
||||
var rows = await table.Where(e => ids.Contains(EF.Property<int>(e, "Id"))).ToListAsync();
|
||||
owned.AddRange(rows);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user