using System.Net; using XFEToolBox.Core.Chat; using XFEExtension.NetCore.ServerInteractive.Attributes; namespace XFEToolBox.Server.Services.Chat; public partial class ChatGroupService : ChatServiceBase { [EntryPoint("v1/chat/groups/recommended")] public async Task RecommendedGroupsEntryPoint() { await ExecuteChatAsync(async repository => { var groups = await repository.GetRecommendedGroupsAsync( User.Id, GetString("query", allowEmpty: true), GetInt32("limit") ?? 30, GetInt32("offset") ?? 0); return groups.Select(ToGroupSummary).ToArray(); }); } [EntryPoint("v1/chat/groups/mine")] public async Task MyGroupsEntryPoint() { await ExecuteChatAsync(async repository => { var groups = await repository.GetMyGroupsAsync(User.Id); return groups.Select(ToGroupSummary).ToArray(); }); } [EntryPoint("v1/chat/groups/lookup")] public async Task LookupGroupEntryPoint() { await ExecuteChatAsync(async repository => { var groupNumber = GetString("groupNumber") ?? throw InvalidRequest("缺少 groupNumber。"); var group = await repository.FindGroupByNumberAsync(groupNumber, User.Id) ?? throw NotFound("未找到该群号。"); return ToGroupSummary(group); }); } [EntryPoint("v1/chat/groups/create")] public async Task CreateGroupEntryPoint() { await ExecuteChatAsync(async repository => { var name = GetString("name") ?? throw InvalidRequest("群名称不能为空。"); var isPublic = GetBoolean("isPublic") ?? throw InvalidRequest("isPublic 必须是布尔值。"); var group = await repository.CreateGroupAsync( User.Id, name, GetString("description", allowEmpty: true), isPublic ? ChatGroupVisibility.Public : ChatGroupVisibility.Private); return ToGroupSummary(group); }, HttpStatusCode.Created); } [EntryPoint("v1/chat/groups/join")] public async Task JoinGroupEntryPoint() { await ExecuteChatAsync(async repository => { var groupNumber = GetString("groupNumber") ?? throw InvalidRequest("缺少 groupNumber。"); var group = await repository.JoinGroupByNumberAsync(groupNumber, User.Id); var result = ToGroupSummary(group); await PublishToGroupBestEffortAsync(group.Id, "chat.group.members.updated", new { groupId = group.Id, userId = User.Id, action = "joined" }, group.ConversationId); return result; }); } [EntryPoint("v1/chat/groups/invite")] public async Task InviteFriendEntryPoint() { await ExecuteChatAsync(async repository => { var groupId = GetString("groupId") ?? throw InvalidRequest("缺少 groupId。"); var friendUserId = GetString("friendUserId") ?? throw InvalidRequest("缺少 friendUserId。"); if (FindUser(friendUserId) is null) throw NotFound("好友用户不存在。"); var invitation = await repository.InviteFriendToGroupAsync( groupId, User.Id, friendUserId, GetString("message", allowEmpty: true)); var result = await ToGroupInvitationInfoAsync(repository, invitation, User.Id) ?? throw NotFound("群邀请创建失败。"); await PublishToUserBestEffortAsync(friendUserId, "chat.group.invited", result); var cardRecord = await repository.FindMessageByGroupInvitationIdAsync(invitation.Id); if (cardRecord is not null) { var card = await ToMessageInfoAsync(repository, cardRecord, friendUserId); await Task.WhenAll( PublishToUserBestEffortAsync(friendUserId, "chat.message.created", card, cardRecord.ConversationId), PublishToUserBestEffortAsync(User.Id, "chat.message.created", card, cardRecord.ConversationId)); } return result; }, HttpStatusCode.Created); } [EntryPoint("v1/chat/groups/invitations")] public async Task ListInvitationsEntryPoint() { await ExecuteChatAsync(async repository => { var records = await repository.GetGroupInvitationsAsync(User.Id); var result = new List(records.Count); foreach (var record in records) { var invitation = await ToGroupInvitationInfoAsync(repository, record, User.Id); if (invitation is not null) result.Add(invitation); } return result.ToArray(); }); } [EntryPoint("v1/chat/groups/invitations/respond")] public async Task RespondInvitationEntryPoint() { await ExecuteChatAsync(async repository => { var invitationId = GetString("invitationId") ?? throw InvalidRequest("缺少 invitationId。"); var accept = GetBoolean("accept") ?? throw InvalidRequest("accept 必须是布尔值。"); var record = await repository.RespondToGroupInvitationAsync(invitationId, User.Id, accept); var result = await ToGroupInvitationInfoAsync(repository, record, User.Id) ?? throw NotFound("群邀请不存在。"); await Task.WhenAll( PublishToUserBestEffortAsync(record.InvitedByUserId, "chat.group.invitation.updated", result), PublishToUserBestEffortAsync(record.InvitedUserId, "chat.group.invitation.updated", result)); if (accept) { await PublishToGroupBestEffortAsync(record.GroupId, "chat.group.members.updated", new { groupId = record.GroupId, userId = record.InvitedUserId, action = "joined" }, result.Group.ConversationId); } return result; }); } [EntryPoint("v1/chat/groups/update")] public async Task UpdateGroupEntryPoint() { await ExecuteChatAsync(async repository => { var groupId = GetString("groupId") ?? throw InvalidRequest("缺少 groupId。"); var name = GetString("name") ?? throw InvalidRequest("群名称不能为空。"); var isPublic = GetBoolean("isPublic") ?? throw InvalidRequest("isPublic 必须是布尔值。"); var group = await repository.UpdateGroupAsync( groupId, User.Id, name, GetString("description", allowEmpty: true), isPublic ? ChatGroupVisibility.Public : ChatGroupVisibility.Private); var result = ToGroupSummary(group); await PublishToGroupBestEffortAsync(group.Id, "chat.group.updated", result, group.ConversationId); return result; }); } [EntryPoint("v1/chat/groups/members")] public async Task GroupMembersEntryPoint() { await ExecuteChatAsync(async repository => { var groupId = GetString("groupId") ?? throw InvalidRequest("缺少 groupId。"); var members = await repository.GetGroupMembersAsync(groupId, User.Id); return members.Select(member => new ChatGroupMemberInfo { GroupId = member.GroupId, User = ToUserSummary(member.UserId), Role = member.Role, JoinedAtUtc = member.JoinedAtUtc }).ToArray(); }); } [EntryPoint("v1/chat/groups/members/remove")] public async Task RemoveGroupMemberEntryPoint() { await ExecuteChatAsync(async repository => { var groupId = GetString("groupId") ?? throw InvalidRequest("缺少 groupId。"); var userId = GetString("userId") ?? throw InvalidRequest("缺少 userId。"); await repository.RemoveGroupMemberAsync(groupId, User.Id, userId); var result = new { groupId, userId, removed = true }; await Task.WhenAll( EvictUserFromGroupCallsBestEffortAsync(groupId, userId, "member-removed"), PublishToGroupBestEffortAsync(groupId, "chat.group.members.updated", new { groupId, userId, action = "removed" }), PublishToUserBestEffortAsync(userId, "chat.group.members.updated", new { groupId, userId, action = "removed" })); return result; }); } [EntryPoint("v1/chat/groups/members/role")] public async Task SetGroupMemberRoleEntryPoint() { await ExecuteChatAsync(async repository => { var groupId = GetString("groupId") ?? throw InvalidRequest("缺少 groupId。"); var userId = GetString("userId") ?? throw InvalidRequest("缺少 userId。"); var role = GetEnum("role") ?? throw InvalidRequest("role 无效。"); await repository.SetGroupMemberRoleAsync(groupId, User.Id, userId, role); var result = new { groupId, userId, role, updated = true }; await PublishToGroupBestEffortAsync(groupId, "chat.group.members.updated", new { groupId, userId, role, action = "roleChanged" }); return result; }); } [EntryPoint("v1/chat/groups/owner/transfer")] public async Task TransferGroupOwnershipEntryPoint() { await ExecuteChatAsync(async repository => { var groupId = GetString("groupId") ?? throw InvalidRequest("缺少 groupId。"); var userId = GetString("userId") ?? throw InvalidRequest("缺少 userId。"); await repository.TransferGroupOwnershipAsync(groupId, User.Id, userId); var result = new { groupId, ownerUserId = userId, transferred = true }; await PublishToGroupBestEffortAsync(groupId, "chat.group.members.updated", new { groupId, userId, action = "ownerTransferred" }); return result; }); } [EntryPoint("v1/chat/groups/leave")] public async Task LeaveGroupEntryPoint() { await ExecuteChatAsync(async repository => { var groupId = GetString("groupId") ?? throw InvalidRequest("缺少 groupId。"); await repository.LeaveGroupAsync(groupId, User.Id); var result = new { groupId, left = true }; await Task.WhenAll( EvictUserFromGroupCallsBestEffortAsync(groupId, User.Id, "member-left"), PublishToGroupBestEffortAsync(groupId, "chat.group.members.updated", new { groupId, userId = User.Id, action = "left" }), PublishToUserBestEffortAsync(User.Id, "chat.group.members.updated", new { groupId, userId = User.Id, action = "left" })); return result; }); } }