feat(guild): invite state machine
Add surrogate PK (IDENTITY bigint) to GuildInvite for wire invite_id. Implement InviteAsync, CancelInviteAsync, RejectInviteAsync, ListOutgoingInvitesAsync, ListInvitedGuildsAsync in GuildService. Wire 5 endpoints: invite_user_list, invited_guild_list, invite, cancel_invite, reject_invite in GuildController. Migration: AddGuildInviteSurrogatePk — drops composite PK, adds Id IDENTITY column, adds unique index on (GuildId, InviteeViewerId). 6 integration tests in GuildInviteFlowTests all green. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,8 +13,12 @@ public sealed class GuildInviteRepository : IGuildInviteRepository
|
||||
=> _db.GuildInvites.FirstOrDefaultAsync(
|
||||
i => i.GuildId == guildId && i.InviteeViewerId == inviteeViewerId, ct);
|
||||
|
||||
public Task<GuildInvite?> GetByIdAsync(long inviteId, CancellationToken ct = default)
|
||||
=> _db.GuildInvites.FirstOrDefaultAsync(i => i.Id == inviteId, ct);
|
||||
|
||||
public async Task<IReadOnlyList<GuildInvite>> ListPendingForInviteeAsync(long viewerId, CancellationToken ct = default)
|
||||
=> await _db.GuildInvites
|
||||
.Include(i => i.Guild)
|
||||
.Where(i => i.InviteeViewerId == viewerId && i.Status == GuildInviteStatus.Pending)
|
||||
.ToListAsync(ct);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace SVSim.Database.Repositories.Guild;
|
||||
public interface IGuildInviteRepository
|
||||
{
|
||||
Task<GuildInvite?> GetAsync(int guildId, long inviteeViewerId, CancellationToken ct = default);
|
||||
Task<GuildInvite?> GetByIdAsync(long inviteId, CancellationToken ct = default);
|
||||
Task<IReadOnlyList<GuildInvite>> ListPendingForInviteeAsync(long viewerId, CancellationToken ct = default);
|
||||
Task<IReadOnlyList<GuildInvite>> ListPendingForGuildAsync(int guildId, CancellationToken ct = default);
|
||||
Task<int> CountPendingForInviteeAsync(long viewerId, CancellationToken ct = default);
|
||||
|
||||
Reference in New Issue
Block a user