132 lines
6.6 KiB
C#
132 lines
6.6 KiB
C#
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.
|
|
}
|
|
};
|
|
}
|
|
}
|