feat(guild_chat): post text + stamp

Implements PostTextOrStampAsync: validates membership (NotInGuild),
validates stamp id against UsableStampList (PermissionDenied), rejects
type other than 0 or 1, allocates next per-guild message_id, appends row.
Wires /guild_chat/post controller action mapping failures to result_code=2.
Response is GuildChatPostResponse (empty body per spec). 7 integration tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-27 14:58:18 -04:00
parent a248c167e0
commit ab1e23b7cb
3 changed files with 338 additions and 5 deletions

View File

@@ -65,10 +65,38 @@ public sealed class GuildChatService : IGuildChatService
return new(msgs, wait);
}
// ── Not-yet-implemented stubs ────────────────────────────────────────────
// ── Post text / stamp ────────────────────────────────────────────────────
public Task<ChatPostResult> PostTextOrStampAsync(long viewerId, int type, string message, CancellationToken ct = default)
=> throw new NotImplementedException();
public async Task<ChatPostResult> PostTextOrStampAsync(long viewerId, int type, string message, CancellationToken ct = default)
{
var m = await _members.GetMembershipAsync(viewerId, ct);
if (m is null) return new(false, null);
var cfg = _cfg.Get<GuildConfig>();
if (type == 1)
{
if (!int.TryParse(message, out var stampId) || !cfg.UsableStampList.Contains(stampId))
return new(false, null);
}
else if (type != 0)
{
// Only NORMAL (0) and STAMP (1) are valid via this endpoint.
return new(false, null);
}
var now = DateTime.UtcNow;
var nextId = await _msgs.GetMaxMessageIdAsync(m.GuildId, ct) + 1;
var stored = await _msgs.AppendAsync(new GuildChatMessage
{
GuildId = m.GuildId,
MessageId = nextId,
AuthorViewerId = viewerId,
MessageType = type == 1 ? GuildChatMessageType.Stamp : GuildChatMessageType.Normal,
Body = message,
CreatedAt = now,
}, ct);
return new(true, stored.MessageId);
}
public Task<ChatPostResult> PostDeckAsync(long viewerId, string deckPayloadJson, CancellationToken ct = default)
=> throw new NotImplementedException();