✨ Realm member listing apis
This commit is contained in:
parent
573f984e2c
commit
5844dfb657
@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using DysonNetwork.Sphere.Storage;
|
using DysonNetwork.Sphere.Storage;
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
@ -28,6 +29,11 @@ public class ChatRoom : ModelBase
|
|||||||
|
|
||||||
public long? RealmId { get; set; }
|
public long? RealmId { get; set; }
|
||||||
public Realm.Realm? Realm { get; set; }
|
public Realm.Realm? Realm { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
[JsonPropertyName("members")]
|
||||||
|
public ICollection<ChatMemberTransmissionObject> DirectMembers { get; set; } =
|
||||||
|
new List<ChatMemberTransmissionObject>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ChatMemberRole
|
public enum ChatMemberRole
|
||||||
@ -58,4 +64,38 @@ public class ChatMember : ModelBase
|
|||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ChatMemberTransmissionObject : ModelBase
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public long ChatRoomId { get; set; }
|
||||||
|
public long AccountId { get; set; }
|
||||||
|
public Account.Account Account { get; set; } = null!;
|
||||||
|
|
||||||
|
[MaxLength(1024)] public string? Nick { get; set; }
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
public static ChatMemberTransmissionObject FromEntity(ChatMember member)
|
||||||
|
{
|
||||||
|
return new ChatMemberTransmissionObject
|
||||||
|
{
|
||||||
|
Id = member.Id,
|
||||||
|
ChatRoomId = member.ChatRoomId,
|
||||||
|
AccountId = member.AccountId,
|
||||||
|
Account = member.Account,
|
||||||
|
Nick = member.Nick,
|
||||||
|
Role = member.Role,
|
||||||
|
Notify = member.Notify,
|
||||||
|
JoinedAt = member.JoinedAt,
|
||||||
|
IsBot = member.IsBot,
|
||||||
|
CreatedAt = member.CreatedAt,
|
||||||
|
UpdatedAt = member.UpdatedAt,
|
||||||
|
DeletedAt = member.DeletedAt
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
@ -20,6 +20,16 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService
|
|||||||
.Include(e => e.Realm)
|
.Include(e => e.Realm)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
if (chatRoom is null) return NotFound();
|
if (chatRoom is null) return NotFound();
|
||||||
|
if (chatRoom.Type != ChatRoomType.DirectMessage) return Ok(chatRoom);
|
||||||
|
|
||||||
|
// Preload members for direct messages
|
||||||
|
var currentUser = HttpContext.Items["CurrentUser"] as Account.Account;
|
||||||
|
var directMembers = await db.ChatMembers
|
||||||
|
.Where(m => (currentUser != null && m.AccountId != currentUser!.Id))
|
||||||
|
.Include(m => m.Account)
|
||||||
|
.Include(m => m.Account.Profile)
|
||||||
|
.ToListAsync();
|
||||||
|
chatRoom.DirectMembers = directMembers.Select(ChatMemberTransmissionObject.FromEntity).ToList();
|
||||||
return Ok(chatRoom);
|
return Ok(chatRoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,21 +65,22 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService
|
|||||||
var result = chatRooms.Select(r =>
|
var result = chatRooms.Select(r =>
|
||||||
{
|
{
|
||||||
if (r.Type == ChatRoomType.DirectMessage && directMembers.TryGetValue(r.Id, out var otherMember))
|
if (r.Type == ChatRoomType.DirectMessage && directMembers.TryGetValue(r.Id, out var otherMember))
|
||||||
r.Members = new List<ChatMember> { otherMember };
|
r.DirectMembers = new List<ChatMemberTransmissionObject>
|
||||||
|
{ ChatMemberTransmissionObject.FromEntity(otherMember) };
|
||||||
return r;
|
return r;
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DmCreationRequest
|
public class DirectMessageRequest
|
||||||
{
|
{
|
||||||
[Required] public long RelatedUserId { get; set; }
|
[Required] public long RelatedUserId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("direct")]
|
[HttpPost("direct")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<ChatRoom>> CreateDirectMessage([FromBody] DmCreationRequest request)
|
public async Task<ActionResult<ChatRoom>> CreateDirectMessage([FromBody] DirectMessageRequest request)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser)
|
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser)
|
||||||
return Unauthorized();
|
return Unauthorized();
|
||||||
|
@ -41,9 +41,9 @@ public enum RealmMemberRole
|
|||||||
public class RealmMember : ModelBase
|
public class RealmMember : ModelBase
|
||||||
{
|
{
|
||||||
public long RealmId { get; set; }
|
public long RealmId { get; set; }
|
||||||
[JsonIgnore] public Realm Realm { get; set; } = null!;
|
public Realm Realm { get; set; } = null!;
|
||||||
public long AccountId { get; set; }
|
public long AccountId { get; set; }
|
||||||
[JsonIgnore] public Account.Account Account { get; set; } = null!;
|
public Account.Account Account { get; set; } = null!;
|
||||||
|
|
||||||
public RealmMemberRole Role { get; set; } = RealmMemberRole.Normal;
|
public RealmMemberRole Role { get; set; } = RealmMemberRole.Normal;
|
||||||
public Instant? JoinedAt { get; set; }
|
public Instant? JoinedAt { get; set; }
|
||||||
|
@ -39,8 +39,6 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) :
|
|||||||
|
|
||||||
return members.ToList();
|
return members.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("/")]
|
|
||||||
|
|
||||||
[HttpGet("invites")]
|
[HttpGet("invites")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
@ -147,27 +145,84 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) :
|
|||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet("{slug}/members")]
|
||||||
|
public async Task<ActionResult<List<RealmMember>>> ListMembers(
|
||||||
|
string slug,
|
||||||
|
[FromQuery] int offset = 0,
|
||||||
|
[FromQuery] int take = 20
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var realm = await db.Realms
|
||||||
|
.Where(r => r.Slug == slug)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
if (realm is null) return NotFound();
|
||||||
|
|
||||||
[HttpDelete("{slug}/members/me")]
|
if (!realm.IsPublic)
|
||||||
|
{
|
||||||
|
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||||
|
var isMember = await db.RealmMembers
|
||||||
|
.AnyAsync(m => m.AccountId == currentUser.Id && m.RealmId == realm.Id && m.JoinedAt != null);
|
||||||
|
if (!isMember) return StatusCode(403, "You must be a member to view this realm's members.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var query = db.RealmMembers
|
||||||
|
.Where(m => m.RealmId == realm.Id)
|
||||||
|
.Where(m => m.JoinedAt != null);
|
||||||
|
|
||||||
|
var total = await query.CountAsync();
|
||||||
|
Response.Headers["X-Total"] = total.ToString();
|
||||||
|
|
||||||
|
var members = await query
|
||||||
|
.OrderBy(m => m.CreatedAt)
|
||||||
|
.Skip(offset)
|
||||||
|
.Take(take)
|
||||||
|
.Include(m => m.Account)
|
||||||
|
.Include(m => m.Account.Profile)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return Ok(members);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{slug}/members/me")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult> LeaveRealm(string slug)
|
public async Task<ActionResult<RealmMember>> GetCurrentIdentity(string slug)
|
||||||
{
|
{
|
||||||
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 member = await db.RealmMembers
|
||||||
|
.Where(m => m.AccountId == userId)
|
||||||
|
.Where(m => m.Realm.Slug == slug)
|
||||||
|
.Include(m => m.Account)
|
||||||
|
.Include(m => m.Account.Profile)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
if (member is null) return NotFound();
|
||||||
|
return Ok(member);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{slug}/members/me")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult> LeaveRealm(string slug)
|
||||||
|
{
|
||||||
|
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||||
|
var userId = currentUser.Id;
|
||||||
|
|
||||||
var member = await db.RealmMembers
|
var member = await db.RealmMembers
|
||||||
.Where(m => m.AccountId == userId)
|
.Where(m => m.AccountId == userId)
|
||||||
.Where(m => m.Realm.Slug == slug)
|
.Where(m => m.Realm.Slug == slug)
|
||||||
.Where(m => m.JoinedAt != null)
|
.Where(m => m.JoinedAt != null)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
if (member is null) return NotFound();
|
if (member is null) return NotFound();
|
||||||
|
|
||||||
if (member.Role == RealmMemberRole.Owner)
|
if (member.Role == RealmMemberRole.Owner)
|
||||||
return StatusCode(403, "Owner cannot leave their own realm.");
|
return StatusCode(403, "Owner cannot leave their own realm.");
|
||||||
|
|
||||||
db.RealmMembers.Remove(member);
|
db.RealmMembers.Remove(member);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user