✨ Direct messages
This commit is contained in:
parent
d0a92bc8b3
commit
573f984e2c
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
@ -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.");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user