Direct messages

This commit is contained in:
LittleSheep 2025-05-04 15:09:44 +08:00
parent d0a92bc8b3
commit 573f984e2c
3 changed files with 96 additions and 11 deletions

View File

@ -43,7 +43,7 @@ public partial class ChatController(AppDatabase db, ChatService cs) : Controller
var member = await db.ChatMembers var member = await db.ChatMembers
.Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId) .Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId)
.FirstOrDefaultAsync(); .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."); 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 var member = await db.ChatMembers
.Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId) .Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId)
.FirstOrDefaultAsync(); .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."); 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)
.Include(m => m.Account.Profile) .Include(m => m.Account.Profile)
.FirstOrDefaultAsync(); .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 var message = new Message
{ {

View File

@ -34,7 +34,7 @@ public enum ChatMemberRole
{ {
Owner = 100, Owner = 100,
Moderator = 50, Moderator = 50,
Normal = 0 Member = 0
} }
public enum ChatMemberNotify public enum ChatMemberNotify
@ -54,7 +54,7 @@ public class ChatMember : ModelBase
[MaxLength(1024)] public string? Nick { get; set; } [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 ChatMemberNotify Notify { get; set; } = ChatMemberNotify.All;
public Instant? JoinedAt { get; set; } public Instant? JoinedAt { get; set; }
public bool IsBot { get; set; } = false; public bool IsBot { get; set; } = false;

View File

@ -26,19 +26,102 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService
[HttpGet] [HttpGet]
public async Task<ActionResult<List<ChatRoom>>> ListJoinedChatRooms() public async Task<ActionResult<List<ChatRoom>>> 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 userId = currentUser.Id;
var members = await db.ChatMembers var chatRooms = await db.ChatMembers
.Where(m => m.AccountId == userId) .Where(m => m.AccountId == userId)
.Where(m => m.JoinedAt != null) .Where(m => m.JoinedAt != null)
.Include(e => e.ChatRoom) .Include(m => m.ChatRoom)
.Select(m => m.ChatRoom) .Select(m => m.ChatRoom)
.ToListAsync(); .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<long, ChatMember>();
// Map the results
var result = chatRooms.Select(r =>
{
if (r.Type == ChatRoomType.DirectMessage && directMembers.TryGetValue(r.Id, out var otherMember))
r.Members = new List<ChatMember> { otherMember };
return r;
}).ToList();
return Ok(result);
} }
public class DmCreationRequest
{
[Required] public long RelatedUserId { get; set; }
}
[HttpPost("direct")]
[Authorize]
public async Task<ActionResult<ChatRoom>> 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<ChatMember>
{
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 public class ChatRoomRequest
{ {
[Required] [MaxLength(1024)] public string? Name { get; set; } [Required] [MaxLength(1024)] public string? Name { get; set; }
@ -60,6 +143,7 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService
{ {
Name = request.Name, Name = request.Name,
Description = request.Description ?? string.Empty, Description = request.Description ?? string.Empty,
Type = ChatRoomType.Group,
Members = new List<ChatMember> Members = new List<ChatMember>
{ {
new() new()
@ -106,6 +190,7 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService
return Ok(chatRoom); return Ok(chatRoom);
} }
[HttpPatch("{id:long}")] [HttpPatch("{id:long}")]
public async Task<ActionResult<ChatRoom>> UpdateChatRoom(long id, [FromBody] ChatRoomRequest request) public async Task<ActionResult<ChatRoom>> 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")] [HttpPatch("{roomId:long}/members/{memberId:long}/role")]
[Authorize] [Authorize]
public async Task<ActionResult<ChatMember>> UpdateChatMemberRole(long roomId, long memberId, public async Task<ActionResult<ChatMember>> UpdateChatMemberRole(long roomId, long memberId,
[FromBody] ChatMemberRequest request) [FromBody] ChatMemberRequest request)
{ {
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); 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.Role == ChatMemberRole.Owner)
.Where(m => m.AccountId != currentUser.Id) .Where(m => m.AccountId != currentUser.Id)
.AnyAsync(); .AnyAsync();
if (!otherOwners) if (!otherOwners)
return BadRequest("The last owner cannot leave the chat. Transfer ownership first or delete the chat."); return BadRequest("The last owner cannot leave the chat. Transfer ownership first or delete the chat.");
} }