feat(tutorial): add /tutorial/gift_top with hardcoded starter present list
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
76
SVSim.EmulatedEntrypoint/Controllers/GiftController.cs
Normal file
76
SVSim.EmulatedEntrypoint/Controllers/GiftController.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SVSim.Database;
|
||||
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Gift;
|
||||
using SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Gift;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Tutorial-scoped gift endpoints. We do NOT implement a generic gift system here —
|
||||
/// only the /tutorial/gift_top and /tutorial/gift_receive aliases needed for the
|
||||
/// step 31 → 41 reward flow. A full gift inbox is future work; if/when needed,
|
||||
/// add /gift/top and /gift/receive_gift aliases to this controller.
|
||||
/// </summary>
|
||||
public class GiftController : SVSimController
|
||||
{
|
||||
/// <summary>The hardcoded tutorial gift bundle every fresh viewer sees at step 31.</summary>
|
||||
public static readonly IReadOnlyList<PresentDto> TutorialGifts = new[]
|
||||
{
|
||||
new PresentDto { PresentId = "71478626", RewardType = "1", RewardDetailId = "0", RewardCount = "400", Message = "For completing the tutorial" },
|
||||
new PresentDto { PresentId = "71478627", RewardType = "9", RewardDetailId = "0", RewardCount = "100", Message = "For completing the tutorial" },
|
||||
new PresentDto { PresentId = "71478628", RewardType = "4", RewardDetailId = "1", RewardCount = "3", Message = "For completing the tutorial", ItemType = 1 },
|
||||
new PresentDto { PresentId = "71478629", RewardType = "4", RewardDetailId = "80001", RewardCount = "40", Message = "For completing the tutorial", ItemType = 2 },
|
||||
new PresentDto { PresentId = "71478630", RewardType = "4", RewardDetailId = "90001", RewardCount = "1", Message = "For completing the tutorial", ItemType = 2 },
|
||||
};
|
||||
|
||||
private readonly SVSimDbContext _db;
|
||||
|
||||
public GiftController(SVSimDbContext db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[HttpPost("/tutorial/gift_top")]
|
||||
public async Task<ActionResult<GiftTopResponse>> TutorialGiftTop([FromBody] GiftTopRequest request)
|
||||
{
|
||||
if (!TryGetViewerId(out long viewerId)) return Unauthorized();
|
||||
|
||||
var claimedList = await _db.ViewerClaimedTutorialGifts
|
||||
.Where(g => g.ViewerId == viewerId)
|
||||
.Select(g => g.PresentId)
|
||||
.ToListAsync();
|
||||
var claimed = new HashSet<string>(claimedList);
|
||||
|
||||
var nowString = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
var presents = TutorialGifts
|
||||
.Where(p => !claimed.Contains(p.PresentId))
|
||||
.Select(p => Clone(p, nowString))
|
||||
.ToList();
|
||||
var history = TutorialGifts
|
||||
.Where(p => claimed.Contains(p.PresentId))
|
||||
.Select(p => Clone(p, nowString))
|
||||
.ToList();
|
||||
|
||||
return new GiftTopResponse
|
||||
{
|
||||
PresentList = presents,
|
||||
PresentHistoryList = history,
|
||||
LimitOverPresentList = new(),
|
||||
};
|
||||
}
|
||||
|
||||
private static PresentDto Clone(PresentDto p, string createTime) => new()
|
||||
{
|
||||
PresentId = p.PresentId,
|
||||
RewardType = p.RewardType,
|
||||
RewardDetailId = p.RewardDetailId,
|
||||
RewardCount = p.RewardCount,
|
||||
ConditionNumber = p.ConditionNumber,
|
||||
PresentLimitType = p.PresentLimitType,
|
||||
RewardLimitTime = p.RewardLimitTime,
|
||||
CreateTime = createTime,
|
||||
ItemType = p.ItemType,
|
||||
Message = p.Message,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using MessagePack;
|
||||
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Gift;
|
||||
|
||||
[MessagePackObject]
|
||||
public class GiftTopRequest : BaseRequest
|
||||
{
|
||||
[JsonPropertyName("page")]
|
||||
[Key("page")]
|
||||
public int Page { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using MessagePack;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Gift;
|
||||
|
||||
[MessagePackObject]
|
||||
public class GiftTopResponse
|
||||
{
|
||||
[JsonPropertyName("present_list")]
|
||||
[Key("present_list")]
|
||||
public List<PresentDto> PresentList { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("present_history_list")]
|
||||
[Key("present_history_list")]
|
||||
public List<PresentDto> PresentHistoryList { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("limit_over_present_list")]
|
||||
[Key("limit_over_present_list")]
|
||||
public List<PresentDto> LimitOverPresentList { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prod sends most numeric-looking fields as STRINGS on this endpoint
|
||||
/// (present_id, reward_type, reward_detail_id, reward_count, condition_number,
|
||||
/// present_limit_type). item_type is an INT. We mirror the prod shape exactly.
|
||||
/// </summary>
|
||||
[MessagePackObject]
|
||||
public class PresentDto
|
||||
{
|
||||
[JsonPropertyName("present_id")]
|
||||
[Key("present_id")]
|
||||
public string PresentId { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("reward_type")]
|
||||
[Key("reward_type")]
|
||||
public string RewardType { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("reward_detail_id")]
|
||||
[Key("reward_detail_id")]
|
||||
public string RewardDetailId { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("reward_count")]
|
||||
[Key("reward_count")]
|
||||
public string RewardCount { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("condition_number")]
|
||||
[Key("condition_number")]
|
||||
public string ConditionNumber { get; set; } = "0";
|
||||
|
||||
[JsonPropertyName("present_limit_type")]
|
||||
[Key("present_limit_type")]
|
||||
public string PresentLimitType { get; set; } = "0";
|
||||
|
||||
[JsonPropertyName("reward_limit_time")]
|
||||
[Key("reward_limit_time")]
|
||||
public int RewardLimitTime { get; set; }
|
||||
|
||||
[JsonPropertyName("create_time")]
|
||||
[Key("create_time")]
|
||||
public string CreateTime { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Only present on item/pack-ticket entries (gifts where reward_type=4); omit on currency entries.</summary>
|
||||
[JsonPropertyName("item_type")]
|
||||
[Key("item_type")]
|
||||
public int? ItemType { get; set; }
|
||||
|
||||
[JsonPropertyName("message")]
|
||||
[Key("message")]
|
||||
public string Message { get; set; } = string.Empty;
|
||||
}
|
||||
Reference in New Issue
Block a user