Things were working, suddenly regressed
This commit is contained in:
131
SVSim.EmulatedEntrypoint/Controllers/MyPageController.cs
Normal file
131
SVSim.EmulatedEntrypoint/Controllers/MyPageController.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SVSim.Database.Models;
|
||||
using SVSim.Database.Repositories.Globals;
|
||||
using SVSim.Database.Repositories.Viewer;
|
||||
using SVSim.EmulatedEntrypoint.Constants;
|
||||
using SVSim.EmulatedEntrypoint.Models.Dtos;
|
||||
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests;
|
||||
using SVSim.EmulatedEntrypoint.Models.Dtos.Responses;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint.Controllers;
|
||||
|
||||
public class MyPageController : SVSimController
|
||||
{
|
||||
private readonly IViewerRepository _viewerRepository;
|
||||
private readonly IGlobalsRepository _globalsRepository;
|
||||
|
||||
public MyPageController(IViewerRepository viewerRepository, IGlobalsRepository globalsRepository)
|
||||
{
|
||||
_viewerRepository = viewerRepository;
|
||||
_globalsRepository = globalsRepository;
|
||||
}
|
||||
|
||||
[HttpPost("index")]
|
||||
public async Task<ActionResult<MyPageIndexResponse>> Index(MyPageIndexRequest request)
|
||||
{
|
||||
var shortUdidClaim = User.Claims.FirstOrDefault(c => c.Type == ShadowverseClaimTypes.ShortUdidClaim)?.Value;
|
||||
if (shortUdidClaim is null || !long.TryParse(shortUdidClaim, out long shortUdid))
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
Viewer? viewer = await _viewerRepository.GetViewerByShortUdid(shortUdid);
|
||||
if (viewer is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var deviceHeader = Request.Headers["DEVICE"].FirstOrDefault();
|
||||
int deviceType = int.TryParse(deviceHeader, out int parsed) ? parsed : 0;
|
||||
|
||||
// Stubs below are tagged TODO(mypage-stub). See the "Current server implementation"
|
||||
// section of docs/api-spec/endpoints/post-login/mypage-index.md for the table of what
|
||||
// each one would source from. Grep for "mypage-stub" to enumerate them.
|
||||
return new MyPageIndexResponse
|
||||
{
|
||||
UserInfo = new UserInfo(deviceType, viewer),
|
||||
UnreceivedMissionRewardCount = 0, // TODO(mypage-stub): viewer mission progress
|
||||
ReceiveFriendApplyCount = 0, // TODO(mypage-stub): viewer friend-request inbox
|
||||
UnreadPresentCount = 0, // TODO(mypage-stub): viewer presents/mail
|
||||
FriendBattleInviteCount = 0, // TODO(mypage-stub): viewer room-invite count
|
||||
GuildNotification = new GuildNotification(), // TODO(mypage-stub): viewer guild state
|
||||
LastAnnounceId = 0, // TODO(mypage-stub): globals announcement metadata
|
||||
LastAnnounceUpdateTime = string.Empty, // TODO(mypage-stub): globals announcement metadata
|
||||
FeatureMaintenanceList = new(), // TODO(mypage-stub): FeatureMaintenanceEntry rows
|
||||
ArenaInfo = await BuildArenaInfosAsync(),
|
||||
IsArenaChallengePeriod = false, // TODO(mypage-stub): globals/ArenaSeason flag
|
||||
IsAvailableColosseumFreeEntry = false, // TODO(mypage-stub): viewer + globals free-entry quota
|
||||
Convention = new Convention // TODO(mypage-stub): viewer offline-event participation
|
||||
{
|
||||
IsJoinTournament = false,
|
||||
IsAdminWatchUser = false,
|
||||
},
|
||||
UserConfig = new UserConfig(), // TODO(mypage-stub): persist viewer UserConfig
|
||||
Quest = new Quest(), // TODO(mypage-stub): active Quest event + viewer flags
|
||||
MasterPointRankingPeriod = new MasterPointRankingPeriod
|
||||
{
|
||||
// TODO(mypage-stub): source begin_time/end_time/period_num/necessary_score from the
|
||||
// current Master Points season row in globals. Far-future fallback so the client's
|
||||
// DateTime.Parse(end_time) succeeds and _masterResetNextTime gets seeded.
|
||||
EndTime = "2030-01-01 00:00:00",
|
||||
},
|
||||
PreReleaseStatus = 0, // TODO(mypage-stub): derive from PreReleaseInfo
|
||||
UserMyPageInfo = new UserMyPageInfo // TODO(mypage-stub): viewer mypage BG selection
|
||||
{
|
||||
UserMyPageSetting = new MyPageBgSetting(),
|
||||
},
|
||||
BasicPuzzle = new BasicPuzzle { IsDisplayBadge = false }, // TODO(mypage-stub): viewer practice-puzzle progress
|
||||
IsBattlePassPeriod = (await _globalsRepository.GetGameConfiguration("default")).IsBattlePassPeriod,
|
||||
SpecialCrystalInfo = new(), // TODO(mypage-stub): same shape/source as /load/index
|
||||
// ColosseumInfo, ShopNotification, StoryNotification, IsHiddenBossAppeared all
|
||||
// default-constructed by MyPageIndexResponse's field initializers.
|
||||
// TODO(mypage-stub): wire colosseum_info from current Colosseum cup row.
|
||||
// TODO(mypage-stub): wire shop_notification from per-product shop-appeal state.
|
||||
// TODO(mypage-stub): wire story_notification from viewer story progress.
|
||||
// TODO(mypage-stub): wire is_hidden_boss_appeared from globals event flag.
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same shape as LoadController.BuildArenaInfosAsync, but /mypage/index has no
|
||||
/// Keys.Contains("arena_info") guard on the client (ArenaData(jsonData["arena_info"])
|
||||
/// at MyPageTask.cs:55 indexes [0] unconditionally). When no current Take Two season is
|
||||
/// seeded we fall back to a minimal one-entry list so the client's ArenaData ctor doesn't
|
||||
/// crash with IndexOutOfRange.
|
||||
/// </summary>
|
||||
private async Task<List<ArenaInfo>> BuildArenaInfosAsync()
|
||||
{
|
||||
var season = await _globalsRepository.GetCurrentArenaSeason();
|
||||
if (season is null)
|
||||
{
|
||||
return new List<ArenaInfo>
|
||||
{
|
||||
new ArenaInfo
|
||||
{
|
||||
Mode = 0,
|
||||
Enable = 0,
|
||||
Cost = 0,
|
||||
RupeeCost = 0,
|
||||
TicketCost = 0,
|
||||
IsJoin = false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return new List<ArenaInfo>
|
||||
{
|
||||
new ArenaInfo
|
||||
{
|
||||
Mode = season.Mode,
|
||||
Enable = season.Enable,
|
||||
Cost = season.Cost,
|
||||
RupeeCost = season.RupyCost,
|
||||
TicketCost = season.TicketCost,
|
||||
IsJoin = season.IsJoin,
|
||||
// format_info is intentionally omitted here — /mypage/index's ArenaData
|
||||
// ctor only needs the top-level fields. /load/index round-trips it via
|
||||
// JsonbReadOptions; pull it in if a downstream check ever needs it.
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user