feat(guild): leave + remove with leader-leaves rule
- LeaveAsync: regular/subleader removes self; leader blocked if members remain; sole-member leader auto-routes to BreakupAsync. - RemoveAsync: leader-only kick (SubLeader has no remove authority per GuildManager.cs decompile); self-remove and cross-guild target rejected. - GuildController: wired /guild/leave (BaseRequest) and /guild/remove (GuildRemoveRequest.remove_viewer_id field). - SpyGuildChatService: extended Emissions with EmissionsWithBody tuple to allow body-content assertions in leave/remove tests. - 8 new integration tests; all 1493 pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -299,10 +299,20 @@ public sealed class GuildController : SVSimController
|
||||
}
|
||||
|
||||
[HttpPost("leave")]
|
||||
public Task<ActionResult<EmptyResponse>> Leave([FromBody] BaseRequest _, CancellationToken ct) => Stub();
|
||||
public async Task<ActionResult<EmptyResponse>> Leave([FromBody] BaseRequest _, CancellationToken ct)
|
||||
{
|
||||
if (!TryGetViewerId(out var viewerId)) return Unauthorized();
|
||||
var r = await _guild.LeaveAsync(viewerId, ct);
|
||||
return r.IsOk ? new EmptyResponse() : MapErrorToWire(r);
|
||||
}
|
||||
|
||||
[HttpPost("remove")]
|
||||
public Task<ActionResult<EmptyResponse>> Remove([FromBody] GuildRemoveRequest req, CancellationToken ct) => Stub();
|
||||
public async Task<ActionResult<EmptyResponse>> Remove([FromBody] GuildRemoveRequest req, CancellationToken ct)
|
||||
{
|
||||
if (!TryGetViewerId(out var viewerId)) return Unauthorized();
|
||||
var r = await _guild.RemoveAsync(viewerId, req.RemoveViewerId, ct);
|
||||
return r.IsOk ? new EmptyResponse() : MapErrorToWire(r);
|
||||
}
|
||||
|
||||
[HttpPost("change_role")]
|
||||
public Task<ActionResult<GuildChangeRoleResponse>> ChangeRole([FromBody] GuildChangeRoleRequest req, CancellationToken ct)
|
||||
|
||||
Reference in New Issue
Block a user