From 573f984e2cc4d45fbebd77e7750cd7ddc5abef83 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 4 May 2025 15:09:44 +0800 Subject: [PATCH] :sparkles: Direct messages --- DysonNetwork.Sphere/Chat/ChatController.cs | 6 +- DysonNetwork.Sphere/Chat/ChatRoom.cs | 4 +- .../Chat/ChatRoomController.cs | 97 +++++++++++++++++-- 3 files changed, 96 insertions(+), 11 deletions(-) diff --git a/DysonNetwork.Sphere/Chat/ChatController.cs b/DysonNetwork.Sphere/Chat/ChatController.cs index 5a7cdcc..847349d 100644 --- a/DysonNetwork.Sphere/Chat/ChatController.cs +++ b/DysonNetwork.Sphere/Chat/ChatController.cs @@ -43,7 +43,7 @@ public partial class ChatController(AppDatabase db, ChatService cs) : Controller var member = await db.ChatMembers .Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId) .FirstOrDefaultAsync(); - if (member == null || member.Role < ChatMemberRole.Normal) + if (member == null || member.Role < ChatMemberRole.Member) return StatusCode(403, "You are not a member of this chat room."); } @@ -81,7 +81,7 @@ public partial class ChatController(AppDatabase db, ChatService cs) : Controller var member = await db.ChatMembers .Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId) .FirstOrDefaultAsync(); - if (member == null || member.Role < ChatMemberRole.Normal) + if (member == null || member.Role < ChatMemberRole.Member) return StatusCode(403, "You are not a member of this chat room."); } @@ -118,7 +118,7 @@ public partial class ChatController(AppDatabase db, ChatService cs) : Controller .Include(m => m.Account) .Include(m => m.Account.Profile) .FirstOrDefaultAsync(); - if (member == null || member.Role < ChatMemberRole.Normal) return StatusCode(403, "You need to be a normal member to send messages here."); + if (member == null || member.Role < ChatMemberRole.Member) return StatusCode(403, "You need to be a normal member to send messages here."); var message = new Message { diff --git a/DysonNetwork.Sphere/Chat/ChatRoom.cs b/DysonNetwork.Sphere/Chat/ChatRoom.cs index cfcc3ac..e7f0941 100644 --- a/DysonNetwork.Sphere/Chat/ChatRoom.cs +++ b/DysonNetwork.Sphere/Chat/ChatRoom.cs @@ -34,7 +34,7 @@ public enum ChatMemberRole { Owner = 100, Moderator = 50, - Normal = 0 + Member = 0 } public enum ChatMemberNotify @@ -54,7 +54,7 @@ public class ChatMember : ModelBase [MaxLength(1024)] public string? Nick { get; set; } - public ChatMemberRole Role { get; set; } = ChatMemberRole.Normal; + public ChatMemberRole Role { get; set; } = ChatMemberRole.Member; public ChatMemberNotify Notify { get; set; } = ChatMemberNotify.All; public Instant? JoinedAt { get; set; } public bool IsBot { get; set; } = false; diff --git a/DysonNetwork.Sphere/Chat/ChatRoomController.cs b/DysonNetwork.Sphere/Chat/ChatRoomController.cs index 94e68f2..904e9bc 100644 --- a/DysonNetwork.Sphere/Chat/ChatRoomController.cs +++ b/DysonNetwork.Sphere/Chat/ChatRoomController.cs @@ -26,19 +26,102 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService [HttpGet] public async Task>> ListJoinedChatRooms() { - if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); + if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) + return Unauthorized(); + var userId = currentUser.Id; - var members = await db.ChatMembers + var chatRooms = await db.ChatMembers .Where(m => m.AccountId == userId) .Where(m => m.JoinedAt != null) - .Include(e => e.ChatRoom) + .Include(m => m.ChatRoom) .Select(m => m.ChatRoom) .ToListAsync(); - return members.ToList(); + var directRoomsId = chatRooms + .Where(r => r.Type == ChatRoomType.DirectMessage) + .Select(r => r.Id) + .ToList(); + var directMembers = directRoomsId.Count != 0 + ? await db.ChatMembers + .Where(m => directRoomsId.Contains(m.ChatRoomId)) + .Where(m => m.AccountId != userId) + .Include(m => m.Account) + .Include(m => m.Account.Profile) + .ToDictionaryAsync(m => m.ChatRoomId, m => m) + : new Dictionary(); + + // Map the results + var result = chatRooms.Select(r => + { + if (r.Type == ChatRoomType.DirectMessage && directMembers.TryGetValue(r.Id, out var otherMember)) + r.Members = new List { otherMember }; + return r; + }).ToList(); + + return Ok(result); } + public class DmCreationRequest + { + [Required] public long RelatedUserId { get; set; } + } + + [HttpPost("direct")] + [Authorize] + public async Task> CreateDirectMessage([FromBody] DmCreationRequest request) + { + if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) + return Unauthorized(); + + var relatedUser = await db.Accounts.FindAsync(request.RelatedUserId); + if (relatedUser is null) + return BadRequest("Related user was not found"); + + // Check if DM already exists between these users + var existingDm = await db.ChatRooms + .Include(c => c.Members) + .Where(c => c.Type == ChatRoomType.DirectMessage && c.Members.Count == 2) + .Where(c => c.Members.Any(m => m.AccountId == currentUser.Id)) + .Where(c => c.Members.Any(m => m.AccountId == request.RelatedUserId)) + .FirstOrDefaultAsync(); + + if (existingDm != null) + return Ok(existingDm); // Return existing DM if found + + // Create new DM chat room + var dmRoom = new ChatRoom + { + Name = $"DM between #{currentUser.Id} and #{request.RelatedUserId}", + Type = ChatRoomType.DirectMessage, + IsPublic = false, + Members = new List + { + new() + { + AccountId = currentUser.Id, + Role = ChatMemberRole.Owner, + JoinedAt = NodaTime.Instant.FromDateTimeUtc(DateTime.UtcNow) + }, + new() + { + AccountId = request.RelatedUserId, + Role = ChatMemberRole.Member, + JoinedAt = null, // Pending status + } + } + }; + + db.ChatRooms.Add(dmRoom); + await db.SaveChangesAsync(); + + var invitedMember = dmRoom.Members.First(m => m.AccountId == request.RelatedUserId); + await crs.SendInviteNotify(invitedMember); + + return Ok(dmRoom); + } + + public class ChatRoomRequest { [Required] [MaxLength(1024)] public string? Name { get; set; } @@ -60,6 +143,7 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService { Name = request.Name, Description = request.Description ?? string.Empty, + Type = ChatRoomType.Group, Members = new List { new() @@ -106,6 +190,7 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService return Ok(chatRoom); } + [HttpPatch("{id:long}")] public async Task> UpdateChatRoom(long id, [FromBody] ChatRoomRequest request) { @@ -395,7 +480,7 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService [HttpPatch("{roomId:long}/members/{memberId:long}/role")] [Authorize] - public async Task> UpdateChatMemberRole(long roomId, long memberId, + public async Task> UpdateChatMemberRole(long roomId, long memberId, [FromBody] ChatMemberRequest request) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); @@ -515,7 +600,7 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService .Where(m => m.Role == ChatMemberRole.Owner) .Where(m => m.AccountId != currentUser.Id) .AnyAsync(); - + if (!otherOwners) return BadRequest("The last owner cannot leave the chat. Transfer ownership first or delete the chat."); }