✨ Chat controller
This commit is contained in:
parent
8b5ca265b8
commit
da6a891b5f
@ -176,7 +176,7 @@ public class AppDatabase(
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<Chat.ChatMember>()
|
||||
.HasKey(pm => new { pm.ChatRoom, pm.AccountId });
|
||||
.HasKey(pm => new { pm.ChatRoomId, pm.AccountId });
|
||||
modelBuilder.Entity<Chat.ChatMember>()
|
||||
.HasOne(pm => pm.ChatRoom)
|
||||
.WithMany(p => p.Members)
|
||||
|
@ -1,50 +1,99 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Sphere.Account;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
|
||||
using DysonNetwork.Sphere.Realm;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
|
||||
namespace DysonNetwork.Sphere.Chat;
|
||||
|
||||
[ApiController]
|
||||
[Route("/chatrooms")]
|
||||
[Route("/chat")]
|
||||
public class ChatRoomController(AppDatabase db, FileService fs) : ControllerBase
|
||||
{
|
||||
[HttpGet("{id:long}")]
|
||||
public async Task<ActionResult<ChatRoom>> GetChatRoom(long id)
|
||||
{
|
||||
var chatRoom = await db.ChatRooms
|
||||
.Where(c => c.Id == id)
|
||||
.Include(e => e.Picture)
|
||||
.Include(e => e.Background)
|
||||
.FirstOrDefaultAsync();
|
||||
if (chatRoom is null) return NotFound();
|
||||
return Ok(chatRoom);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<ChatRoom>>> ListJoinedChatRooms()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||
var userId = currentUser.Id;
|
||||
|
||||
var members = await db.ChatMembers
|
||||
.Where(m => m.AccountId == userId)
|
||||
.Where(m => m.JoinedAt != null)
|
||||
.Include(e => e.ChatRoom)
|
||||
.Include(e => e.ChatRoom.Picture)
|
||||
.Include(e => e.ChatRoom.Background)
|
||||
.Include(e => e.ChatRoom.Type == ChatRoomType.DirectMessage ? e.ChatRoom.Members : null)
|
||||
.Select(m => m.ChatRoom)
|
||||
.ToListAsync();
|
||||
|
||||
return members.ToList();
|
||||
}
|
||||
|
||||
public class ChatRoomRequest
|
||||
{
|
||||
[Required] [MaxLength(1024)] public string? Name { get; set; }
|
||||
[MaxLength(4096)] public string? Description { get; set; }
|
||||
public string? PictureId { get; set; }
|
||||
public string? BackgroundId { get; set; }
|
||||
public long? RealmId { get; set; }
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<ChatRoom>> CreateChatRoom(ChatRoomRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||
if (request.Name is null) return BadRequest("You cannot create a chat room without a name.");
|
||||
|
||||
CloudFile? picture = null;
|
||||
if (request.PictureId is not null)
|
||||
{
|
||||
picture = await db.Files.FindAsync(request.PictureId);
|
||||
if (picture is null) return BadRequest("Invalid picture id, unable to find the file on cloud.");
|
||||
}
|
||||
|
||||
CloudFile? background = null;
|
||||
if (request.BackgroundId is not null)
|
||||
{
|
||||
background = await db.Files.FindAsync(request.BackgroundId);
|
||||
if (background is null) return BadRequest("Invalid background id, unable to find the file on cloud.");
|
||||
}
|
||||
|
||||
var chatRoom = new ChatRoom
|
||||
{
|
||||
Name = request.Name,
|
||||
Description = request.Description ?? string.Empty,
|
||||
Picture = picture,
|
||||
Background = background,
|
||||
CreatedAt = Instant.FromDateTimeUtc(DateTime.UtcNow)
|
||||
Members = new List<ChatMember>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Role = ChatMemberRole.Owner,
|
||||
AccountId = currentUser.Id
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (request.RealmId is not null)
|
||||
{
|
||||
var member = await db.RealmMembers
|
||||
.Where(m => m.AccountId == currentUser.Id)
|
||||
.Where(m => m.RealmId == request.RealmId)
|
||||
.FirstOrDefaultAsync();
|
||||
if (member is null || member.Role < RealmMemberRole.Moderator)
|
||||
return StatusCode(403, "You need at least be a moderator to create chat linked to the realm.");
|
||||
chatRoom.RealmId = member.RealmId;
|
||||
}
|
||||
|
||||
if (request.PictureId is not null)
|
||||
{
|
||||
chatRoom.Picture = await db.Files.FindAsync(request.PictureId);
|
||||
if (chatRoom.Picture is null) return BadRequest("Invalid picture id, unable to find the file on cloud.");
|
||||
}
|
||||
|
||||
if (request.BackgroundId is not null)
|
||||
{
|
||||
chatRoom.Background = await db.Files.FindAsync(request.BackgroundId);
|
||||
if (chatRoom.Background is null)
|
||||
return BadRequest("Invalid background id, unable to find the file on cloud.");
|
||||
}
|
||||
|
||||
db.ChatRooms.Add(chatRoom);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
@ -56,79 +105,116 @@ public class ChatRoomController(AppDatabase db, FileService fs) : ControllerBase
|
||||
return Ok(chatRoom);
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public async Task<ActionResult<ChatRoom>> GetChatRoom(long id)
|
||||
{
|
||||
var chatRoom = await db.ChatRooms.FindAsync(id);
|
||||
if (chatRoom is null) return NotFound();
|
||||
return Ok(chatRoom);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<ChatRoom>>> ListChatRooms()
|
||||
{
|
||||
var chatRooms = await db.ChatRooms.ToListAsync();
|
||||
return chatRooms;
|
||||
}
|
||||
|
||||
public class ChatRoomRequest
|
||||
{
|
||||
[Required]
|
||||
[MaxLength(1024)]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[MaxLength(4096)] public string? Description { get; set; }
|
||||
public string? PictureId { get; set; }
|
||||
public string? BackgroundId { get; set; }
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
[HttpPut("{id:long}")]
|
||||
public async Task<ActionResult<ChatRoom>> UpdateChatRoom(long id, [FromBody] ChatRoomRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||
|
||||
var chatRoom = await db.ChatRooms.FindAsync(id);
|
||||
var chatRoom = await db.ChatRooms
|
||||
.Where(e => e.Id == id)
|
||||
.Include(c => c.Picture)
|
||||
.Include(c => c.Background)
|
||||
.FirstOrDefaultAsync();
|
||||
if (chatRoom is null) return NotFound();
|
||||
|
||||
CloudFile? picture = null;
|
||||
if (chatRoom.RealmId is not null)
|
||||
{
|
||||
var realmMember = await db.RealmMembers
|
||||
.Where(m => m.AccountId == currentUser.Id)
|
||||
.Where(m => m.RealmId == chatRoom.RealmId)
|
||||
.FirstOrDefaultAsync();
|
||||
if (realmMember is null || realmMember.Role < RealmMemberRole.Moderator)
|
||||
return StatusCode(403, "You need at least be a realm moderator to update the chat.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var chatMember = await db.ChatMembers
|
||||
.Where(m => m.AccountId == currentUser.Id)
|
||||
.Where(m => m.ChatRoomId == chatRoom.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
if (chatMember is null || chatMember.Role < ChatMemberRole.Moderator)
|
||||
return StatusCode(403, "You need at least be a moderator to update the chat.");
|
||||
}
|
||||
|
||||
if (request.RealmId is not null)
|
||||
{
|
||||
var member = await db.RealmMembers
|
||||
.Where(m => m.AccountId == currentUser.Id)
|
||||
.Where(m => m.RealmId == request.RealmId)
|
||||
.FirstOrDefaultAsync();
|
||||
if (member is null || member.Role < RealmMemberRole.Moderator)
|
||||
return StatusCode(403, "You need at least be a moderator to transfer the chat linked to the realm.");
|
||||
chatRoom.RealmId = member.RealmId;
|
||||
}
|
||||
|
||||
if (request.PictureId is not null)
|
||||
{
|
||||
picture = await db.Files.FindAsync(request.PictureId);
|
||||
var picture = await db.Files.FindAsync(request.PictureId);
|
||||
if (picture is null) return BadRequest("Invalid picture id, unable to find the file on cloud.");
|
||||
await fs.MarkUsageAsync(picture, 1);
|
||||
if (chatRoom.Picture is not null) await fs.MarkUsageAsync(chatRoom.Picture, -1);
|
||||
chatRoom.Picture = picture;
|
||||
}
|
||||
else if(request.PictureId == "")
|
||||
{
|
||||
chatRoom.Picture = null;
|
||||
}
|
||||
CloudFile? background = null;
|
||||
|
||||
if (request.BackgroundId is not null)
|
||||
{
|
||||
background = await db.Files.FindAsync(request.BackgroundId);
|
||||
var background = await db.Files.FindAsync(request.BackgroundId);
|
||||
if (background is null) return BadRequest("Invalid background id, unable to find the file on cloud.");
|
||||
await fs.MarkUsageAsync(background, 1);
|
||||
if (chatRoom.Background is not null) await fs.MarkUsageAsync(chatRoom.Background, -1);
|
||||
chatRoom.Background = background;
|
||||
}
|
||||
else if(request.BackgroundId == "")
|
||||
{
|
||||
chatRoom.Background = null;
|
||||
}
|
||||
|
||||
if (request.Name is not null)
|
||||
chatRoom.Name = request.Name;
|
||||
if (request.Description is not null)
|
||||
chatRoom.Description = request.Description;
|
||||
|
||||
db.ChatRooms.Update(chatRoom);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return Ok(chatRoom);
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
[HttpDelete("{id:long}")]
|
||||
public async Task<ActionResult> DeleteChatRoom(long id)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||
|
||||
var chatRoom = await db.ChatRooms.FindAsync(id);
|
||||
var chatRoom = await db.ChatRooms
|
||||
.Where(e => e.Id == id)
|
||||
.Include(c => c.Picture)
|
||||
.Include(c => c.Background)
|
||||
.FirstOrDefaultAsync();
|
||||
if (chatRoom is null) return NotFound();
|
||||
|
||||
if (chatRoom.RealmId is not null)
|
||||
{
|
||||
var realmMember = await db.RealmMembers
|
||||
.Where(m => m.AccountId == currentUser.Id)
|
||||
.Where(m => m.RealmId == chatRoom.RealmId)
|
||||
.FirstOrDefaultAsync();
|
||||
if (realmMember is null || realmMember.Role < RealmMemberRole.Moderator)
|
||||
return StatusCode(403, "You need at least be a realm moderator to delete the chat.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var chatMember = await db.ChatMembers
|
||||
.Where(m => m.AccountId == currentUser.Id)
|
||||
.Where(m => m.ChatRoomId == chatRoom.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
if (chatMember is null || chatMember.Role < ChatMemberRole.Owner)
|
||||
return StatusCode(403, "You need at least be the owner to delete the chat.");
|
||||
}
|
||||
|
||||
db.ChatRooms.Remove(chatRoom);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
if (chatRoom.Picture is not null)
|
||||
await fs.MarkUsageAsync(chatRoom.Picture, -1);
|
||||
if (chatRoom.Background is not null)
|
||||
await fs.MarkUsageAsync(chatRoom.Background, -1);
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
}
|
2085
DysonNetwork.Sphere/Migrations/20250502040651_RealmAndChat.Designer.cs
generated
Normal file
2085
DysonNetwork.Sphere/Migrations/20250502040651_RealmAndChat.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,51 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NodaTime;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace DysonNetwork.Sphere.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class RealmAndChat : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<Instant>(
|
||||
name: "created_at",
|
||||
table: "publisher_members",
|
||||
type: "timestamp with time zone",
|
||||
nullable: false,
|
||||
defaultValue: NodaTime.Instant.FromUnixTimeTicks(0L));
|
||||
|
||||
migrationBuilder.AddColumn<Instant>(
|
||||
name: "deleted_at",
|
||||
table: "publisher_members",
|
||||
type: "timestamp with time zone",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Instant>(
|
||||
name: "updated_at",
|
||||
table: "publisher_members",
|
||||
type: "timestamp with time zone",
|
||||
nullable: false,
|
||||
defaultValue: NodaTime.Instant.FromUnixTimeTicks(0L));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "created_at",
|
||||
table: "publisher_members");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "deleted_at",
|
||||
table: "publisher_members");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "updated_at",
|
||||
table: "publisher_members");
|
||||
}
|
||||
}
|
||||
}
|
@ -645,6 +645,117 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
b.ToTable("auth_sessions", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatMember", b =>
|
||||
{
|
||||
b.Property<long>("ChatRoomId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("chat_room_id");
|
||||
|
||||
b.Property<long>("AccountId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("account_id");
|
||||
|
||||
b.Property<Instant>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at");
|
||||
|
||||
b.Property<Instant?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at");
|
||||
|
||||
b.Property<bool>("IsBot")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("is_bot");
|
||||
|
||||
b.Property<Instant?>("JoinedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("joined_at");
|
||||
|
||||
b.Property<int>("Role")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("role");
|
||||
|
||||
b.Property<Instant>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at");
|
||||
|
||||
b.HasKey("ChatRoomId", "AccountId")
|
||||
.HasName("pk_chat_members");
|
||||
|
||||
b.HasIndex("AccountId")
|
||||
.HasDatabaseName("ix_chat_members_account_id");
|
||||
|
||||
b.ToTable("chat_members", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatRoom", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("BackgroundId")
|
||||
.HasColumnType("character varying(128)")
|
||||
.HasColumnName("background_id");
|
||||
|
||||
b.Property<Instant>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at");
|
||||
|
||||
b.Property<Instant?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasMaxLength(4096)
|
||||
.HasColumnType("character varying(4096)")
|
||||
.HasColumnName("description");
|
||||
|
||||
b.Property<bool>("IsPublic")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("is_public");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(1024)
|
||||
.HasColumnType("character varying(1024)")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<string>("PictureId")
|
||||
.HasColumnType("character varying(128)")
|
||||
.HasColumnName("picture_id");
|
||||
|
||||
b.Property<long?>("RealmId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("realm_id");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("type");
|
||||
|
||||
b.Property<Instant>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_chat_rooms");
|
||||
|
||||
b.HasIndex("BackgroundId")
|
||||
.HasDatabaseName("ix_chat_rooms_background_id");
|
||||
|
||||
b.HasIndex("PictureId")
|
||||
.HasDatabaseName("ix_chat_rooms_picture_id");
|
||||
|
||||
b.HasIndex("RealmId")
|
||||
.HasDatabaseName("ix_chat_rooms_realm_id");
|
||||
|
||||
b.ToTable("chat_rooms", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionGroup", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@ -1192,6 +1303,132 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
b.ToTable("publisher_members", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Realm.Realm", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<long>("AccountId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("account_id");
|
||||
|
||||
b.Property<string>("BackgroundId")
|
||||
.HasColumnType("character varying(128)")
|
||||
.HasColumnName("background_id");
|
||||
|
||||
b.Property<Instant>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at");
|
||||
|
||||
b.Property<Instant?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasMaxLength(4096)
|
||||
.HasColumnType("character varying(4096)")
|
||||
.HasColumnName("description");
|
||||
|
||||
b.Property<bool>("IsCommunity")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("is_community");
|
||||
|
||||
b.Property<bool>("IsPublic")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("is_public");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(1024)
|
||||
.HasColumnType("character varying(1024)")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<string>("PictureId")
|
||||
.HasColumnType("character varying(128)")
|
||||
.HasColumnName("picture_id");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasMaxLength(1024)
|
||||
.HasColumnType("character varying(1024)")
|
||||
.HasColumnName("slug");
|
||||
|
||||
b.Property<Instant>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at");
|
||||
|
||||
b.Property<string>("VerifiedAs")
|
||||
.HasMaxLength(4096)
|
||||
.HasColumnType("character varying(4096)")
|
||||
.HasColumnName("verified_as");
|
||||
|
||||
b.Property<Instant?>("VerifiedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("verified_at");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_realms");
|
||||
|
||||
b.HasIndex("AccountId")
|
||||
.HasDatabaseName("ix_realms_account_id");
|
||||
|
||||
b.HasIndex("BackgroundId")
|
||||
.HasDatabaseName("ix_realms_background_id");
|
||||
|
||||
b.HasIndex("PictureId")
|
||||
.HasDatabaseName("ix_realms_picture_id");
|
||||
|
||||
b.HasIndex("Slug")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_realms_slug");
|
||||
|
||||
b.ToTable("realms", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmMember", b =>
|
||||
{
|
||||
b.Property<long>("RealmId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("realm_id");
|
||||
|
||||
b.Property<long>("AccountId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("account_id");
|
||||
|
||||
b.Property<Instant>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at");
|
||||
|
||||
b.Property<Instant?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("deleted_at");
|
||||
|
||||
b.Property<Instant?>("JoinedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("joined_at");
|
||||
|
||||
b.Property<int>("Role")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("role");
|
||||
|
||||
b.Property<Instant>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at");
|
||||
|
||||
b.HasKey("RealmId", "AccountId")
|
||||
.HasName("pk_realm_members");
|
||||
|
||||
b.HasIndex("AccountId")
|
||||
.HasDatabaseName("ix_realm_members_account_id");
|
||||
|
||||
b.ToTable("realm_members", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Storage.CloudFile", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
@ -1492,6 +1729,51 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
b.Navigation("Challenge");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatMember", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||
.WithMany()
|
||||
.HasForeignKey("AccountId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_chat_members_accounts_account_id");
|
||||
|
||||
b.HasOne("DysonNetwork.Sphere.Chat.ChatRoom", "ChatRoom")
|
||||
.WithMany("Members")
|
||||
.HasForeignKey("ChatRoomId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_chat_members_chat_rooms_chat_room_id");
|
||||
|
||||
b.Navigation("Account");
|
||||
|
||||
b.Navigation("ChatRoom");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatRoom", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background")
|
||||
.WithMany()
|
||||
.HasForeignKey("BackgroundId")
|
||||
.HasConstraintName("fk_chat_rooms_files_background_id");
|
||||
|
||||
b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture")
|
||||
.WithMany()
|
||||
.HasForeignKey("PictureId")
|
||||
.HasConstraintName("fk_chat_rooms_files_picture_id");
|
||||
|
||||
b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm")
|
||||
.WithMany("ChatRooms")
|
||||
.HasForeignKey("RealmId")
|
||||
.HasConstraintName("fk_chat_rooms_realms_realm_id");
|
||||
|
||||
b.Navigation("Background");
|
||||
|
||||
b.Navigation("Picture");
|
||||
|
||||
b.Navigation("Realm");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionGroupMember", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group")
|
||||
@ -1627,6 +1909,53 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
b.Navigation("Publisher");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Realm.Realm", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||
.WithMany()
|
||||
.HasForeignKey("AccountId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_realms_accounts_account_id");
|
||||
|
||||
b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background")
|
||||
.WithMany()
|
||||
.HasForeignKey("BackgroundId")
|
||||
.HasConstraintName("fk_realms_files_background_id");
|
||||
|
||||
b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture")
|
||||
.WithMany()
|
||||
.HasForeignKey("PictureId")
|
||||
.HasConstraintName("fk_realms_files_picture_id");
|
||||
|
||||
b.Navigation("Account");
|
||||
|
||||
b.Navigation("Background");
|
||||
|
||||
b.Navigation("Picture");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmMember", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||
.WithMany()
|
||||
.HasForeignKey("AccountId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_realm_members_accounts_account_id");
|
||||
|
||||
b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm")
|
||||
.WithMany("Members")
|
||||
.HasForeignKey("RealmId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_realm_members_realms_realm_id");
|
||||
|
||||
b.Navigation("Account");
|
||||
|
||||
b.Navigation("Realm");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Storage.CloudFile", b =>
|
||||
{
|
||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||
@ -1713,6 +2042,11 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
b.Navigation("Sessions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatRoom", b =>
|
||||
{
|
||||
b.Navigation("Members");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionGroup", b =>
|
||||
{
|
||||
b.Navigation("Members");
|
||||
@ -1735,6 +2069,13 @@ namespace DysonNetwork.Sphere.Migrations
|
||||
|
||||
b.Navigation("Posts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DysonNetwork.Sphere.Realm.Realm", b =>
|
||||
{
|
||||
b.Navigation("ChatRooms");
|
||||
|
||||
b.Navigation("Members");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public enum PublisherMemberRole
|
||||
Viewer = 25
|
||||
}
|
||||
|
||||
public class PublisherMember
|
||||
public class PublisherMember : ModelBase
|
||||
{
|
||||
public long PublisherId { get; set; }
|
||||
[JsonIgnore] public Publisher Publisher { get; set; } = null!;
|
||||
|
38
DysonNetwork.Sphere/Realm/RealmChatController.cs
Normal file
38
DysonNetwork.Sphere/Realm/RealmChatController.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using DysonNetwork.Sphere.Chat;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace DysonNetwork.Sphere.Realm;
|
||||
|
||||
[ApiController]
|
||||
[Route("/realm/{slug}")]
|
||||
public class RealmChatController(AppDatabase db) : ControllerBase
|
||||
{
|
||||
[HttpGet("/chat")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<List<ChatRoom>>> ListRealmChat(string slug)
|
||||
{
|
||||
var currentUser = HttpContext.Items["CurrentUser"] as Account.Account;
|
||||
|
||||
var realm = await db.Realms
|
||||
.Where(r => r.Slug == slug)
|
||||
.FirstOrDefaultAsync();
|
||||
if (realm is null) return NotFound();
|
||||
if (!realm.IsPublic)
|
||||
{
|
||||
if (currentUser is null) return Unauthorized();
|
||||
var member = await db.ChatMembers
|
||||
.Where(m => m.ChatRoomId == realm.Id)
|
||||
.Where(m => m.AccountId == currentUser.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
if (member is null) return BadRequest("You need at least one member to view the realm's chat.");
|
||||
}
|
||||
|
||||
var chatRooms = await db.ChatRooms
|
||||
.Where(c => c.RealmId == realm.Id)
|
||||
.ToListAsync();
|
||||
|
||||
return Ok(chatRooms);
|
||||
}
|
||||
}
|
@ -13,8 +13,6 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) :
|
||||
[HttpGet("{slug}")]
|
||||
public async Task<ActionResult<Realm>> GetRealm(string slug)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||
|
||||
var realm = await db.Realms
|
||||
.Where(e => e.Slug == slug)
|
||||
.Include(e => e.Picture)
|
||||
@ -27,7 +25,7 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) :
|
||||
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<List<Realm>>> ListManagedRealms()
|
||||
public async Task<ActionResult<List<Realm>>> ListJoinedRealms()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||
var userId = currentUser.Id;
|
||||
@ -38,10 +36,13 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) :
|
||||
.Include(e => e.Realm)
|
||||
.Include(e => e.Realm.Picture)
|
||||
.Include(e => e.Realm.Background)
|
||||
.Select(m => m.Realm)
|
||||
.ToListAsync();
|
||||
|
||||
return members.Select(m => m.Realm).ToList();
|
||||
return members.ToList();
|
||||
}
|
||||
|
||||
[HttpGet("/")]
|
||||
|
||||
[HttpGet("invites")]
|
||||
[Authorize]
|
||||
@ -179,7 +180,15 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) :
|
||||
Description = request.Description!,
|
||||
AccountId = currentUser.Id,
|
||||
IsCommunity = request.IsCommunity ?? false,
|
||||
IsPublic = request.IsPublic ?? false
|
||||
IsPublic = request.IsPublic ?? false,
|
||||
Members = new List<RealmMember>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Role = RealmMemberRole.Owner,
|
||||
AccountId = currentUser.Id
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (request.PictureId is not null)
|
||||
@ -242,6 +251,8 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) :
|
||||
{
|
||||
var picture = await db.Files.FindAsync(request.PictureId);
|
||||
if (picture is null) return BadRequest("Invalid picture id, unable to find the file on cloud.");
|
||||
await fs.MarkUsageAsync(picture, 1);
|
||||
if (realm.Picture is not null) await fs.MarkUsageAsync(realm.Picture, -1);
|
||||
realm.Picture = picture;
|
||||
}
|
||||
|
||||
@ -249,6 +260,8 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) :
|
||||
{
|
||||
var background = await db.Files.FindAsync(request.BackgroundId);
|
||||
if (background is null) return BadRequest("Invalid background id, unable to find the file on cloud.");
|
||||
await fs.MarkUsageAsync(background, 1);
|
||||
if (realm.Background is not null) await fs.MarkUsageAsync(realm.Background, -1);
|
||||
realm.Background = background;
|
||||
}
|
||||
|
||||
@ -265,6 +278,8 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) :
|
||||
|
||||
var realm = await db.Realms
|
||||
.Where(r => r.Slug == slug)
|
||||
.Include(r => r.Picture)
|
||||
.Include(r => r.Background)
|
||||
.FirstOrDefaultAsync();
|
||||
if (realm is null) return NotFound();
|
||||
|
||||
@ -276,6 +291,12 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) :
|
||||
|
||||
db.Realms.Remove(realm);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
if (realm.Picture is not null)
|
||||
await fs.MarkUsageAsync(realm.Picture, -1);
|
||||
if (realm.Background is not null)
|
||||
await fs.MarkUsageAsync(realm.Background, -1);
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user