From a45a923260c4cb1f78759e2211a72ef2dc7903f9 Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Thu, 6 Oct 2022 15:50:15 +0200 Subject: [PATCH] add group moderation and banning functionality to api (#13) * add group moderation and banning functionality to api * set moderator to false on group migration * send IsModerator in addition on group join Co-authored-by: rootdarkarchon --- MareAPI | 2 +- .../Hubs/MareHub.Functions.cs | 30 ++ .../Hubs/MareHub.Groups.cs | 181 +++++-- .../Data/MareDbContext.cs | 6 + .../20221006115929_GroupModerator.Designer.cs | 397 +++++++++++++++ .../20221006115929_GroupModerator.cs | 26 + .../20221006122618_groupbans.Designer.cs | 462 ++++++++++++++++++ .../Migrations/20221006122618_groupbans.cs | 136 ++++++ .../Migrations/MareDbContextModelSnapshot.cs | 75 ++- .../MareSynchronosShared/Models/GroupBan.cs | 19 + .../MareSynchronosShared/Models/GroupPair.cs | 1 + .../Utils/SharedDbFunctions.cs | 4 + 12 files changed, 1297 insertions(+), 42 deletions(-) create mode 100644 MareSynchronosServer/MareSynchronosShared/Migrations/20221006115929_GroupModerator.Designer.cs create mode 100644 MareSynchronosServer/MareSynchronosShared/Migrations/20221006115929_GroupModerator.cs create mode 100644 MareSynchronosServer/MareSynchronosShared/Migrations/20221006122618_groupbans.Designer.cs create mode 100644 MareSynchronosServer/MareSynchronosShared/Migrations/20221006122618_groupbans.cs create mode 100644 MareSynchronosServer/MareSynchronosShared/Models/GroupBan.cs diff --git a/MareAPI b/MareAPI index fc47c86..c2d740d 160000 --- a/MareAPI +++ b/MareAPI @@ -1 +1 @@ -Subproject commit fc47c861b7f7464bde6913e547ac191ae24a14cb +Subproject commit c2d740def246955b7b9001781e48ed80560db11f diff --git a/MareSynchronosServer/MareSynchronosServer/Hubs/MareHub.Functions.cs b/MareSynchronosServer/MareSynchronosServer/Hubs/MareHub.Functions.cs index 5b490ea..fd7e054 100644 --- a/MareSynchronosServer/MareSynchronosServer/Hubs/MareHub.Functions.cs +++ b/MareSynchronosServer/MareSynchronosServer/Hubs/MareHub.Functions.cs @@ -107,4 +107,34 @@ public partial class MareHub } } + private async Task<(bool IsValid, GroupPair ReferredPair)> TryValidateUserInGroup(string gid, string? uid = null) + { + uid ??= AuthenticatedUserId; + + var groupPair = await _dbContext.GroupPairs.Include(c => c.GroupUser).SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == uid).ConfigureAwait(false); + if (groupPair == null) return (false, null); + + return (true, groupPair); + } + + private async Task<(bool IsValid, Group ReferredGroup)> TryValidateGroupModeratorOrOwner(string gid) + { + var isOwnerResult = await TryValidateOwner(gid).ConfigureAwait(false); + if (isOwnerResult.isValid) return (true, isOwnerResult.ReferredGroup); + + if (isOwnerResult.ReferredGroup == null) return (false, null); + + var groupPairSelf = await _dbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == AuthenticatedUserId).ConfigureAwait(false); + if (groupPairSelf == null || !groupPairSelf.IsModerator) return (false, null); + + return (true, isOwnerResult.ReferredGroup); + } + + private async Task<(bool isValid, Group ReferredGroup)> TryValidateOwner(string gid) + { + var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false); + if (group == null) return (false, null); + + return (string.Equals(group.OwnerUID, AuthenticatedUserId, StringComparison.Ordinal), group); + } } diff --git a/MareSynchronosServer/MareSynchronosServer/Hubs/MareHub.Groups.cs b/MareSynchronosServer/MareSynchronosServer/Hubs/MareHub.Groups.cs index 4ae2b56..9fd7ae2 100644 --- a/MareSynchronosServer/MareSynchronosServer/Hubs/MareHub.Groups.cs +++ b/MareSynchronosServer/MareSynchronosServer/Hubs/MareHub.Groups.cs @@ -1,13 +1,11 @@ using MareSynchronos.API; using MareSynchronosServer.Utils; using MareSynchronosShared.Authentication; -using MareSynchronosShared.Data; using MareSynchronosShared.Models; using MareSynchronosShared.Utils; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; @@ -105,9 +103,8 @@ public partial class MareHub { _logger.LogCallInfo(Api.InvokeGroupGetUsersInGroup, gid); - var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false); - var existingPair = await _dbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == AuthenticatedUserId).ConfigureAwait(false); - if (group == null || existingPair == null) return new List(); + var (inGroup, _) = await TryValidateUserInGroup(gid).ConfigureAwait(false); + if (!inGroup) return new List(); var allPairs = await _dbContext.GroupPairs.Include(g => g.GroupUser).Where(g => g.GroupGID == gid && g.GroupUserUID != AuthenticatedUserId).ToListAsync().ConfigureAwait(false); return allPairs.Select(p => new GroupPairDto() @@ -117,7 +114,8 @@ public partial class MareHub IsRemoved = false, UserUID = p.GroupUser.UID, UserAlias = p.GroupUser.Alias, - IsPinned = p.IsPinned + IsPinned = p.IsPinned, + IsModerator = p.IsModerator, }).ToList(); } @@ -127,8 +125,8 @@ public partial class MareHub { _logger.LogCallInfo(Api.SendGroupChangeInviteState, gid, enabled.ToString()); - var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false); - if (group == null || !string.Equals(group.OwnerUID, AuthenticatedUserId, StringComparison.Ordinal)) return; + var (hasRights, group) = await TryValidateOwner(gid).ConfigureAwait(false); + if (!hasRights) return; group.InvitesEnabled = enabled; await _dbContext.SaveChangesAsync().ConfigureAwait(false); @@ -149,8 +147,7 @@ public partial class MareHub { _logger.LogCallInfo(Api.SendGroupDelete, gid); - var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false); - if (group == null || !string.Equals(group.OwnerUID, AuthenticatedUserId, StringComparison.Ordinal)) return; + var (hasRights, group) = await TryValidateOwner(gid).ConfigureAwait(false); _logger.LogCallInfo(Api.SendGroupDelete, gid, "Success"); @@ -180,12 +177,15 @@ public partial class MareHub var hashedPw = StringUtils.Sha256String(password); var existingUserCount = await _dbContext.GroupPairs.CountAsync(g => g.GroupGID == gid).ConfigureAwait(false); var joinedGroups = await _dbContext.GroupPairs.CountAsync(g => g.GroupUserUID == AuthenticatedUserId).ConfigureAwait(false); + var isBanned = await _dbContext.GroupBans.AnyAsync(g => g.GroupGID == gid && g.BannedUserUID == AuthenticatedUserId).ConfigureAwait(false); + if (group == null || !string.Equals(group.HashedPassword, hashedPw, StringComparison.Ordinal) || existingPair != null || existingUserCount >= _maxGroupUserCount || !group.InvitesEnabled - || joinedGroups >= _maxJoinedGroupsByUser) + || joinedGroups >= _maxJoinedGroupsByUser + || isBanned) return false; GroupPair newPair = new() @@ -219,7 +219,8 @@ public partial class MareHub IsRemoved = false, UserUID = AuthenticatedUserId, UserAlias = self.Alias, - IsPinned = false + IsPinned = false, + IsModerator = false, }).ConfigureAwait(false); var allUserPairs = await GetAllPairedClientsWithPauseState().ConfigureAwait(false); @@ -249,8 +250,8 @@ public partial class MareHub { _logger.LogCallInfo(Api.SendGroupLeave, gid); - var groupPair = await _dbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == AuthenticatedUserId).ConfigureAwait(false); - if (groupPair == null) return; + var (exists, groupPair) = await TryValidateUserInGroup(gid).ConfigureAwait(false); + if (!exists) return; var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false); @@ -333,8 +334,8 @@ public partial class MareHub { _logger.LogCallInfo(Api.SendGroupPause, gid, isPaused); - var groupPair = await _dbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == AuthenticatedUserId).ConfigureAwait(false); - if (groupPair == null) return; + var (exists, groupPair) = await TryValidateUserInGroup(gid).ConfigureAwait(false); + if (!exists) return; groupPair.IsPaused = isPaused; await _dbContext.SaveChangesAsync().ConfigureAwait(false); @@ -382,10 +383,11 @@ public partial class MareHub { _logger.LogCallInfo(Api.SendGroupRemoveUser, gid, uid); - var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false); - if (group == null || !string.Equals(group.OwnerUID, AuthenticatedUserId, StringComparison.Ordinal)) return; - var groupPair = await _dbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == uid).ConfigureAwait(false); - if (groupPair == null) return; + var (hasRights, group) = await TryValidateGroupModeratorOrOwner(gid).ConfigureAwait(false); + if (!hasRights) return; + + var (userExists, groupPair) = await TryValidateUserInGroup(gid, uid).ConfigureAwait(false); + if (!userExists) return; _logger.LogCallInfo(Api.SendGroupRemoveUser, gid, uid, "Success"); @@ -417,24 +419,127 @@ public partial class MareHub } } + [Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)] + [HubMethodName(Api.SendBanUserFromGroup)] + public async Task GroupBanUser(string gid, string uid, string reason) + { + _logger.LogCallInfo(Api.SendBanUserFromGroup, gid, uid); + + var (userHasRights, _) = await TryValidateGroupModeratorOrOwner(gid).ConfigureAwait(false); + if (!userHasRights) return; + + var (userExists, groupPair) = await TryValidateUserInGroup(gid, uid).ConfigureAwait(false); + if (!userExists) return; + + var alias = string.IsNullOrEmpty(groupPair.GroupUser.Alias) ? "-" : groupPair.GroupUser.Alias; + var ban = new GroupBan() + { + BannedByUID = AuthenticatedUserId, + BannedReason = $"{reason} (Alias at time of ban: {alias})", + BannedOn = DateTime.UtcNow, + BannedUserUID = uid, + GroupGID = gid, + }; + + _dbContext.Add(ban); + await _dbContext.SaveChangesAsync().ConfigureAwait(false); + + await GroupRemoveUser(gid, uid).ConfigureAwait(false); + + _logger.LogCallInfo(Api.SendBanUserFromGroup, gid, uid, "Success"); + } + + [Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)] + [HubMethodName(Api.SendUnbanUserFromGroup)] + public async Task GroupUnbanUser(string gid, string uid) + { + _logger.LogCallInfo(Api.SendUnbanUserFromGroup, gid, uid); + + var (userHasRights, _) = await TryValidateGroupModeratorOrOwner(gid).ConfigureAwait(false); + if (!userHasRights) return; + + var banEntry = await _dbContext.GroupBans.SingleOrDefaultAsync(g => g.GroupGID == gid && g.BannedUserUID == uid).ConfigureAwait(false); + if (banEntry == null) return; + + _dbContext.Remove(banEntry); + await _dbContext.SaveChangesAsync().ConfigureAwait(false); + + _logger.LogCallInfo(Api.SendUnbanUserFromGroup, gid, uid, "Success"); + } + + [Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)] + [HubMethodName(Api.InvokeGetBannedUsersForGroup)] + public async Task> GetGroupBannedUsers(string gid) + { + _logger.LogCallInfo(Api.InvokeGetBannedUsersForGroup, gid); + + var (userHasRights, _) = await TryValidateGroupModeratorOrOwner(gid).ConfigureAwait(false); + if (!userHasRights) return new List(); + + var banEntries = await _dbContext.GroupBans.Where(g => g.GroupGID == gid).ToListAsync().ConfigureAwait(false); + + List bannedGroupUsers = banEntries.Select(b => new BannedGroupUserDto() + { + BannedBy = b.BannedByUID, + BannedOn = b.BannedOn, + Reason = b.BannedReason, + UID = b.BannedUserUID, + + }).ToList(); + + _logger.LogCallInfo(Api.InvokeGetBannedUsersForGroup, gid, bannedGroupUsers.Count); + + return bannedGroupUsers; + } + + [Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)] + [HubMethodName(Api.SendGroupSetModerator)] + public async Task SetModerator(string gid, string uid, bool isModerator) + { + _logger.LogCallInfo(Api.SendGroupSetModerator, gid, uid, IsModerator); + + var (userHasRights, _) = await TryValidateOwner(gid).ConfigureAwait(false); + if (!userHasRights) return; + + var (userExists, userPair) = await TryValidateUserInGroup(gid, uid).ConfigureAwait(false); + if (!userExists) return; + + userPair.IsModerator = IsModerator; + await _dbContext.SaveChangesAsync().ConfigureAwait(false); + + var groupPairs = await _dbContext.GroupPairs.Where(g => g.GroupGID == gid).ToListAsync().ConfigureAwait(false); + + await Clients.Users(groupPairs.Select(g => g.GroupUserUID)).SendAsync(Api.OnGroupUserChange, new GroupPairDto() + { + GroupGID = gid, + IsModerator = isModerator, + UserUID = uid + }).ConfigureAwait(false); + + _logger.LogCallInfo(Api.SendGroupSetModerator, gid, uid, IsModerator, "Success"); + } + [Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)] [HubMethodName(Api.SendGroupChangeOwner)] public async Task ChangeOwnership(string gid, string uid) { _logger.LogCallInfo(Api.SendGroupChangeOwner, gid, uid); - var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false); - if (group == null || !string.Equals(group.OwnerUID, AuthenticatedUserId, StringComparison.Ordinal)) return; - var groupPair = await _dbContext.GroupPairs.Include(g => g.GroupUser).SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == uid).ConfigureAwait(false); - if (groupPair == null) return; + var (isOwner, group) = await TryValidateOwner(gid).ConfigureAwait(false); + if (!isOwner) return; + + var (isInGroup, newOwnerPair) = await TryValidateUserInGroup(gid, uid).ConfigureAwait(false); + if (!isInGroup) return; + var ownedShells = await _dbContext.Groups.CountAsync(g => g.OwnerUID == uid).ConfigureAwait(false); if (ownedShells >= _maxExistingGroupsByUser) return; var prevOwner = await _dbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == AuthenticatedUserId).ConfigureAwait(false); prevOwner.IsPinned = false; - group.Owner = groupPair.GroupUser; + group.Owner = newOwnerPair.GroupUser; group.Alias = null; - groupPair.IsPinned = true; + newOwnerPair.IsPinned = true; + newOwnerPair.IsModerator = false; await _dbContext.SaveChangesAsync().ConfigureAwait(false); _logger.LogCallInfo(Api.SendGroupChangeOwner, gid, uid, "Success"); @@ -452,7 +557,8 @@ public partial class MareHub { GroupGID = gid, UserUID = uid, - IsPinned = true + IsPinned = true, + IsModerator = false }).ConfigureAwait(false); } @@ -462,10 +568,8 @@ public partial class MareHub { _logger.LogCallInfo(Api.InvokeGroupChangePassword, gid); - var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false); - if (group == null || !string.Equals(group.OwnerUID, AuthenticatedUserId, StringComparison.Ordinal)) return false; - - if (password.Length < 10) return false; + var (isOwner, group) = await TryValidateOwner(gid).ConfigureAwait(false); + if (!isOwner || password.Length < 10) return false; _logger.LogCallInfo(Api.InvokeGroupChangePassword, gid, "Success"); @@ -481,10 +585,11 @@ public partial class MareHub { _logger.LogCallInfo(Api.SendGroupChangePinned, gid, uid, isPinned); - var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false); - if (group == null || !string.Equals(group.OwnerUID, AuthenticatedUserId, StringComparison.Ordinal)) return; - var groupPair = await _dbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == uid).ConfigureAwait(false); - if (groupPair == null) return; + var (userHasRights, _) = await TryValidateGroupModeratorOrOwner(gid).ConfigureAwait(false); + if (!userHasRights) return; + + var (userInGroup, groupPair) = await TryValidateUserInGroup(gid, uid).ConfigureAwait(false); + if (!userInGroup) return; groupPair.IsPinned = isPinned; await _dbContext.SaveChangesAsync().ConfigureAwait(false); @@ -507,12 +612,12 @@ public partial class MareHub { _logger.LogCallInfo(Api.SendGroupClear, gid); - var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false); - if (group == null || !string.Equals(group.OwnerUID, AuthenticatedUserId, StringComparison.Ordinal)) return; + var (hasRights, group) = await TryValidateGroupModeratorOrOwner(gid).ConfigureAwait(false); + if (!hasRights) return; var groupPairs = await _dbContext.GroupPairs.Where(p => p.GroupGID == gid).ToListAsync().ConfigureAwait(false); - await Clients.Users(groupPairs.Where(p => !p.IsPinned).Select(g => g.GroupUserUID)).SendAsync(Api.OnGroupChange, new GroupDto() + await Clients.Users(groupPairs.Where(p => !p.IsPinned && !p.IsModerator).Select(g => g.GroupUserUID)).SendAsync(Api.OnGroupChange, new GroupDto() { GID = group.GID, IsDeleted = true, diff --git a/MareSynchronosServer/MareSynchronosShared/Data/MareDbContext.cs b/MareSynchronosServer/MareSynchronosShared/Data/MareDbContext.cs index 7a132f6..c15d4c3 100644 --- a/MareSynchronosServer/MareSynchronosShared/Data/MareDbContext.cs +++ b/MareSynchronosServer/MareSynchronosShared/Data/MareDbContext.cs @@ -1,4 +1,5 @@ using MareSynchronosShared.Models; +using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace MareSynchronosShared.Data; @@ -41,6 +42,7 @@ public class MareDbContext : DbContext public DbSet BannedRegistrations { get; set; } public DbSet Groups { get; set; } public DbSet GroupPairs { get; set; } + public DbSet GroupBans { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -63,5 +65,9 @@ public class MareDbContext : DbContext modelBuilder.Entity().HasKey(u => new { u.GroupGID, u.GroupUserUID }); modelBuilder.Entity().HasIndex(c => c.GroupUserUID); modelBuilder.Entity().HasIndex(c => c.GroupGID); + modelBuilder.Entity().ToTable("group_bans"); + modelBuilder.Entity().HasKey(u => new { u.GroupGID, u.BannedUserUID }); + modelBuilder.Entity().HasIndex(c => c.BannedUserUID); + modelBuilder.Entity().HasIndex(c => c.GroupGID); } } \ No newline at end of file diff --git a/MareSynchronosServer/MareSynchronosShared/Migrations/20221006115929_GroupModerator.Designer.cs b/MareSynchronosServer/MareSynchronosShared/Migrations/20221006115929_GroupModerator.Designer.cs new file mode 100644 index 0000000..56ecd28 --- /dev/null +++ b/MareSynchronosServer/MareSynchronosShared/Migrations/20221006115929_GroupModerator.Designer.cs @@ -0,0 +1,397 @@ +// +using System; +using MareSynchronosShared.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MareSynchronosServer.Migrations +{ + [DbContext(typeof(MareDbContext))] + [Migration("20221006115929_GroupModerator")] + partial class GroupModerator + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MareSynchronosShared.Models.Auth", b => + { + b.Property("HashedKey") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("hashed_key"); + + b.Property("UserUID") + .HasColumnType("character varying(10)") + .HasColumnName("user_uid"); + + b.HasKey("HashedKey") + .HasName("pk_auth"); + + b.HasIndex("UserUID") + .HasDatabaseName("ix_auth_user_uid"); + + b.ToTable("auth", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.Banned", b => + { + b.Property("CharacterIdentification") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("character_identification"); + + b.Property("Reason") + .HasColumnType("text") + .HasColumnName("reason"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.HasKey("CharacterIdentification") + .HasName("pk_banned_users"); + + b.ToTable("banned_users", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.BannedRegistrations", b => + { + b.Property("DiscordIdOrLodestoneAuth") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("discord_id_or_lodestone_auth"); + + b.HasKey("DiscordIdOrLodestoneAuth") + .HasName("pk_banned_registrations"); + + b.ToTable("banned_registrations", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b => + { + b.Property("UserUID") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("user_uid"); + + b.Property("OtherUserUID") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("other_user_uid"); + + b.Property("AllowReceivingMessages") + .HasColumnType("boolean") + .HasColumnName("allow_receiving_messages"); + + b.Property("IsPaused") + .HasColumnType("boolean") + .HasColumnName("is_paused"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.HasKey("UserUID", "OtherUserUID") + .HasName("pk_client_pairs"); + + b.HasIndex("OtherUserUID") + .HasDatabaseName("ix_client_pairs_other_user_uid"); + + b.HasIndex("UserUID") + .HasDatabaseName("ix_client_pairs_user_uid"); + + b.ToTable("client_pairs", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b => + { + b.Property("Hash") + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("hash"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.Property("Uploaded") + .HasColumnType("boolean") + .HasColumnName("uploaded"); + + b.Property("UploaderUID") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("uploader_uid"); + + b.HasKey("Hash") + .HasName("pk_file_caches"); + + b.HasIndex("UploaderUID") + .HasDatabaseName("ix_file_caches_uploader_uid"); + + b.ToTable("file_caches", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.ForbiddenUploadEntry", b => + { + b.Property("Hash") + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("hash"); + + b.Property("ForbiddenBy") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("forbidden_by"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.HasKey("Hash") + .HasName("pk_forbidden_upload_entries"); + + b.ToTable("forbidden_upload_entries", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.Group", b => + { + b.Property("GID") + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("gid"); + + b.Property("Alias") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("alias"); + + b.Property("HashedPassword") + .HasColumnType("text") + .HasColumnName("hashed_password"); + + b.Property("InvitesEnabled") + .HasColumnType("boolean") + .HasColumnName("invites_enabled"); + + b.Property("OwnerUID") + .HasColumnType("character varying(10)") + .HasColumnName("owner_uid"); + + b.HasKey("GID") + .HasName("pk_groups"); + + b.HasIndex("OwnerUID") + .HasDatabaseName("ix_groups_owner_uid"); + + b.ToTable("groups", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b => + { + b.Property("GroupGID") + .HasColumnType("character varying(20)") + .HasColumnName("group_gid"); + + b.Property("GroupUserUID") + .HasColumnType("character varying(10)") + .HasColumnName("group_user_uid"); + + b.Property("IsModerator") + .HasColumnType("boolean") + .HasColumnName("is_moderator"); + + b.Property("IsPaused") + .HasColumnType("boolean") + .HasColumnName("is_paused"); + + b.Property("IsPinned") + .HasColumnType("boolean") + .HasColumnName("is_pinned"); + + b.HasKey("GroupGID", "GroupUserUID") + .HasName("pk_group_pairs"); + + b.HasIndex("GroupGID") + .HasDatabaseName("ix_group_pairs_group_gid"); + + b.HasIndex("GroupUserUID") + .HasDatabaseName("ix_group_pairs_group_user_uid"); + + b.ToTable("group_pairs", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b => + { + b.Property("DiscordId") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)") + .HasColumnName("discord_id"); + + b.Property("HashedLodestoneId") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("hashed_lodestone_id"); + + b.Property("LodestoneAuthString") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("lodestone_auth_string"); + + b.Property("StartedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("started_at"); + + b.Property("UserUID") + .HasColumnType("character varying(10)") + .HasColumnName("user_uid"); + + b.HasKey("DiscordId") + .HasName("pk_lodestone_auth"); + + b.HasIndex("UserUID") + .HasDatabaseName("ix_lodestone_auth_user_uid"); + + b.ToTable("lodestone_auth", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.User", b => + { + b.Property("UID") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("uid"); + + b.Property("Alias") + .HasMaxLength(15) + .HasColumnType("character varying(15)") + .HasColumnName("alias"); + + b.Property("IsAdmin") + .HasColumnType("boolean") + .HasColumnName("is_admin"); + + b.Property("IsModerator") + .HasColumnType("boolean") + .HasColumnName("is_moderator"); + + b.Property("LastLoggedIn") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_logged_in"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.HasKey("UID") + .HasName("pk_users"); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.Auth", b => + { + b.HasOne("MareSynchronosShared.Models.User", "User") + .WithMany() + .HasForeignKey("UserUID") + .HasConstraintName("fk_auth_users_user_temp_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b => + { + b.HasOne("MareSynchronosShared.Models.User", "OtherUser") + .WithMany() + .HasForeignKey("OtherUserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_client_pairs_users_other_user_temp_id1"); + + b.HasOne("MareSynchronosShared.Models.User", "User") + .WithMany() + .HasForeignKey("UserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_client_pairs_users_user_temp_id2"); + + b.Navigation("OtherUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b => + { + b.HasOne("MareSynchronosShared.Models.User", "Uploader") + .WithMany() + .HasForeignKey("UploaderUID") + .HasConstraintName("fk_file_caches_users_uploader_uid"); + + b.Navigation("Uploader"); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.Group", b => + { + b.HasOne("MareSynchronosShared.Models.User", "Owner") + .WithMany() + .HasForeignKey("OwnerUID") + .HasConstraintName("fk_groups_users_owner_temp_id5"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b => + { + b.HasOne("MareSynchronosShared.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupGID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_pairs_groups_group_temp_id"); + + b.HasOne("MareSynchronosShared.Models.User", "GroupUser") + .WithMany() + .HasForeignKey("GroupUserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_pairs_users_group_user_temp_id4"); + + b.Navigation("Group"); + + b.Navigation("GroupUser"); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b => + { + b.HasOne("MareSynchronosShared.Models.User", "User") + .WithMany() + .HasForeignKey("UserUID") + .HasConstraintName("fk_lodestone_auth_users_user_uid"); + + b.Navigation("User"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/MareSynchronosServer/MareSynchronosShared/Migrations/20221006115929_GroupModerator.cs b/MareSynchronosServer/MareSynchronosShared/Migrations/20221006115929_GroupModerator.cs new file mode 100644 index 0000000..e0b45c1 --- /dev/null +++ b/MareSynchronosServer/MareSynchronosShared/Migrations/20221006115929_GroupModerator.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MareSynchronosServer.Migrations +{ + public partial class GroupModerator : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "is_moderator", + table: "group_pairs", + type: "boolean", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "is_moderator", + table: "group_pairs"); + } + } +} diff --git a/MareSynchronosServer/MareSynchronosShared/Migrations/20221006122618_groupbans.Designer.cs b/MareSynchronosServer/MareSynchronosShared/Migrations/20221006122618_groupbans.Designer.cs new file mode 100644 index 0000000..9c82ebd --- /dev/null +++ b/MareSynchronosServer/MareSynchronosShared/Migrations/20221006122618_groupbans.Designer.cs @@ -0,0 +1,462 @@ +// +using System; +using MareSynchronosShared.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MareSynchronosServer.Migrations +{ + [DbContext(typeof(MareDbContext))] + [Migration("20221006122618_groupbans")] + partial class groupbans + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MareSynchronosShared.Models.Auth", b => + { + b.Property("HashedKey") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("hashed_key"); + + b.Property("UserUID") + .HasColumnType("character varying(10)") + .HasColumnName("user_uid"); + + b.HasKey("HashedKey") + .HasName("pk_auth"); + + b.HasIndex("UserUID") + .HasDatabaseName("ix_auth_user_uid"); + + b.ToTable("auth", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.Banned", b => + { + b.Property("CharacterIdentification") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("character_identification"); + + b.Property("Reason") + .HasColumnType("text") + .HasColumnName("reason"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.HasKey("CharacterIdentification") + .HasName("pk_banned_users"); + + b.ToTable("banned_users", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.BannedRegistrations", b => + { + b.Property("DiscordIdOrLodestoneAuth") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("discord_id_or_lodestone_auth"); + + b.HasKey("DiscordIdOrLodestoneAuth") + .HasName("pk_banned_registrations"); + + b.ToTable("banned_registrations", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b => + { + b.Property("UserUID") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("user_uid"); + + b.Property("OtherUserUID") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("other_user_uid"); + + b.Property("AllowReceivingMessages") + .HasColumnType("boolean") + .HasColumnName("allow_receiving_messages"); + + b.Property("IsPaused") + .HasColumnType("boolean") + .HasColumnName("is_paused"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.HasKey("UserUID", "OtherUserUID") + .HasName("pk_client_pairs"); + + b.HasIndex("OtherUserUID") + .HasDatabaseName("ix_client_pairs_other_user_uid"); + + b.HasIndex("UserUID") + .HasDatabaseName("ix_client_pairs_user_uid"); + + b.ToTable("client_pairs", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b => + { + b.Property("Hash") + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("hash"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.Property("Uploaded") + .HasColumnType("boolean") + .HasColumnName("uploaded"); + + b.Property("UploaderUID") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("uploader_uid"); + + b.HasKey("Hash") + .HasName("pk_file_caches"); + + b.HasIndex("UploaderUID") + .HasDatabaseName("ix_file_caches_uploader_uid"); + + b.ToTable("file_caches", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.ForbiddenUploadEntry", b => + { + b.Property("Hash") + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("hash"); + + b.Property("ForbiddenBy") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("forbidden_by"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.HasKey("Hash") + .HasName("pk_forbidden_upload_entries"); + + b.ToTable("forbidden_upload_entries", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.Group", b => + { + b.Property("GID") + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("gid"); + + b.Property("Alias") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("alias"); + + b.Property("HashedPassword") + .HasColumnType("text") + .HasColumnName("hashed_password"); + + b.Property("InvitesEnabled") + .HasColumnType("boolean") + .HasColumnName("invites_enabled"); + + b.Property("OwnerUID") + .HasColumnType("character varying(10)") + .HasColumnName("owner_uid"); + + b.HasKey("GID") + .HasName("pk_groups"); + + b.HasIndex("OwnerUID") + .HasDatabaseName("ix_groups_owner_uid"); + + b.ToTable("groups", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b => + { + b.Property("GroupGID") + .HasColumnType("character varying(20)") + .HasColumnName("group_gid"); + + b.Property("BannedUserUID") + .HasColumnType("character varying(10)") + .HasColumnName("banned_user_uid"); + + b.Property("BannedByUID") + .HasColumnType("character varying(10)") + .HasColumnName("banned_by_uid"); + + b.Property("BannedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("banned_on"); + + b.Property("BannedReason") + .HasColumnType("text") + .HasColumnName("banned_reason"); + + b.HasKey("GroupGID", "BannedUserUID") + .HasName("pk_group_bans"); + + b.HasIndex("BannedByUID") + .HasDatabaseName("ix_group_bans_banned_by_uid"); + + b.HasIndex("BannedUserUID") + .HasDatabaseName("ix_group_bans_banned_user_uid"); + + b.HasIndex("GroupGID") + .HasDatabaseName("ix_group_bans_group_gid"); + + b.ToTable("group_bans", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b => + { + b.Property("GroupGID") + .HasColumnType("character varying(20)") + .HasColumnName("group_gid"); + + b.Property("GroupUserUID") + .HasColumnType("character varying(10)") + .HasColumnName("group_user_uid"); + + b.Property("IsModerator") + .HasColumnType("boolean") + .HasColumnName("is_moderator"); + + b.Property("IsPaused") + .HasColumnType("boolean") + .HasColumnName("is_paused"); + + b.Property("IsPinned") + .HasColumnType("boolean") + .HasColumnName("is_pinned"); + + b.HasKey("GroupGID", "GroupUserUID") + .HasName("pk_group_pairs"); + + b.HasIndex("GroupGID") + .HasDatabaseName("ix_group_pairs_group_gid"); + + b.HasIndex("GroupUserUID") + .HasDatabaseName("ix_group_pairs_group_user_uid"); + + b.ToTable("group_pairs", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b => + { + b.Property("DiscordId") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)") + .HasColumnName("discord_id"); + + b.Property("HashedLodestoneId") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("hashed_lodestone_id"); + + b.Property("LodestoneAuthString") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("lodestone_auth_string"); + + b.Property("StartedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("started_at"); + + b.Property("UserUID") + .HasColumnType("character varying(10)") + .HasColumnName("user_uid"); + + b.HasKey("DiscordId") + .HasName("pk_lodestone_auth"); + + b.HasIndex("UserUID") + .HasDatabaseName("ix_lodestone_auth_user_uid"); + + b.ToTable("lodestone_auth", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.User", b => + { + b.Property("UID") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("uid"); + + b.Property("Alias") + .HasMaxLength(15) + .HasColumnType("character varying(15)") + .HasColumnName("alias"); + + b.Property("IsAdmin") + .HasColumnType("boolean") + .HasColumnName("is_admin"); + + b.Property("IsModerator") + .HasColumnType("boolean") + .HasColumnName("is_moderator"); + + b.Property("LastLoggedIn") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_logged_in"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.HasKey("UID") + .HasName("pk_users"); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.Auth", b => + { + b.HasOne("MareSynchronosShared.Models.User", "User") + .WithMany() + .HasForeignKey("UserUID") + .HasConstraintName("fk_auth_users_user_temp_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b => + { + b.HasOne("MareSynchronosShared.Models.User", "OtherUser") + .WithMany() + .HasForeignKey("OtherUserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_client_pairs_users_other_user_temp_id1"); + + b.HasOne("MareSynchronosShared.Models.User", "User") + .WithMany() + .HasForeignKey("UserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_client_pairs_users_user_temp_id2"); + + b.Navigation("OtherUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b => + { + b.HasOne("MareSynchronosShared.Models.User", "Uploader") + .WithMany() + .HasForeignKey("UploaderUID") + .HasConstraintName("fk_file_caches_users_uploader_uid"); + + b.Navigation("Uploader"); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.Group", b => + { + b.HasOne("MareSynchronosShared.Models.User", "Owner") + .WithMany() + .HasForeignKey("OwnerUID") + .HasConstraintName("fk_groups_users_owner_temp_id7"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b => + { + b.HasOne("MareSynchronosShared.Models.User", "BannedBy") + .WithMany() + .HasForeignKey("BannedByUID") + .HasConstraintName("fk_group_bans_users_banned_by_temp_id4"); + + b.HasOne("MareSynchronosShared.Models.User", "BannedUser") + .WithMany() + .HasForeignKey("BannedUserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_bans_users_banned_user_temp_id5"); + + b.HasOne("MareSynchronosShared.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupGID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_bans_groups_group_temp_id"); + + b.Navigation("BannedBy"); + + b.Navigation("BannedUser"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b => + { + b.HasOne("MareSynchronosShared.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupGID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_pairs_groups_group_temp_id1"); + + b.HasOne("MareSynchronosShared.Models.User", "GroupUser") + .WithMany() + .HasForeignKey("GroupUserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_pairs_users_group_user_temp_id6"); + + b.Navigation("Group"); + + b.Navigation("GroupUser"); + }); + + modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b => + { + b.HasOne("MareSynchronosShared.Models.User", "User") + .WithMany() + .HasForeignKey("UserUID") + .HasConstraintName("fk_lodestone_auth_users_user_uid"); + + b.Navigation("User"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/MareSynchronosServer/MareSynchronosShared/Migrations/20221006122618_groupbans.cs b/MareSynchronosServer/MareSynchronosShared/Migrations/20221006122618_groupbans.cs new file mode 100644 index 0000000..8d0834b --- /dev/null +++ b/MareSynchronosServer/MareSynchronosShared/Migrations/20221006122618_groupbans.cs @@ -0,0 +1,136 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MareSynchronosServer.Migrations +{ + public partial class groupbans : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_group_pairs_groups_group_temp_id", + table: "group_pairs"); + + migrationBuilder.DropForeignKey( + name: "fk_group_pairs_users_group_user_temp_id4", + table: "group_pairs"); + + migrationBuilder.DropForeignKey( + name: "fk_groups_users_owner_temp_id5", + table: "groups"); + + migrationBuilder.CreateTable( + name: "group_bans", + columns: table => new + { + group_gid = table.Column(type: "character varying(20)", nullable: false), + banned_user_uid = table.Column(type: "character varying(10)", nullable: false), + banned_by_uid = table.Column(type: "character varying(10)", nullable: true), + banned_on = table.Column(type: "timestamp with time zone", nullable: false), + banned_reason = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_group_bans", x => new { x.group_gid, x.banned_user_uid }); + table.ForeignKey( + name: "fk_group_bans_groups_group_temp_id", + column: x => x.group_gid, + principalTable: "groups", + principalColumn: "gid", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_group_bans_users_banned_by_temp_id4", + column: x => x.banned_by_uid, + principalTable: "users", + principalColumn: "uid"); + table.ForeignKey( + name: "fk_group_bans_users_banned_user_temp_id5", + column: x => x.banned_user_uid, + principalTable: "users", + principalColumn: "uid", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "ix_group_bans_banned_by_uid", + table: "group_bans", + column: "banned_by_uid"); + + migrationBuilder.CreateIndex( + name: "ix_group_bans_banned_user_uid", + table: "group_bans", + column: "banned_user_uid"); + + migrationBuilder.CreateIndex( + name: "ix_group_bans_group_gid", + table: "group_bans", + column: "group_gid"); + + migrationBuilder.AddForeignKey( + name: "fk_group_pairs_groups_group_temp_id1", + table: "group_pairs", + column: "group_gid", + principalTable: "groups", + principalColumn: "gid", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "fk_group_pairs_users_group_user_temp_id6", + table: "group_pairs", + column: "group_user_uid", + principalTable: "users", + principalColumn: "uid", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "fk_groups_users_owner_temp_id7", + table: "groups", + column: "owner_uid", + principalTable: "users", + principalColumn: "uid"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_group_pairs_groups_group_temp_id1", + table: "group_pairs"); + + migrationBuilder.DropForeignKey( + name: "fk_group_pairs_users_group_user_temp_id6", + table: "group_pairs"); + + migrationBuilder.DropForeignKey( + name: "fk_groups_users_owner_temp_id7", + table: "groups"); + + migrationBuilder.DropTable( + name: "group_bans"); + + migrationBuilder.AddForeignKey( + name: "fk_group_pairs_groups_group_temp_id", + table: "group_pairs", + column: "group_gid", + principalTable: "groups", + principalColumn: "gid", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "fk_group_pairs_users_group_user_temp_id4", + table: "group_pairs", + column: "group_user_uid", + principalTable: "users", + principalColumn: "uid", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "fk_groups_users_owner_temp_id5", + table: "groups", + column: "owner_uid", + principalTable: "users", + principalColumn: "uid"); + } + } +} diff --git a/MareSynchronosServer/MareSynchronosShared/Migrations/MareDbContextModelSnapshot.cs b/MareSynchronosServer/MareSynchronosShared/Migrations/MareDbContextModelSnapshot.cs index fb0981e..b303b83 100644 --- a/MareSynchronosServer/MareSynchronosShared/Migrations/MareDbContextModelSnapshot.cs +++ b/MareSynchronosServer/MareSynchronosShared/Migrations/MareDbContextModelSnapshot.cs @@ -204,6 +204,43 @@ namespace MareSynchronosServer.Migrations b.ToTable("groups", (string)null); }); + modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b => + { + b.Property("GroupGID") + .HasColumnType("character varying(20)") + .HasColumnName("group_gid"); + + b.Property("BannedUserUID") + .HasColumnType("character varying(10)") + .HasColumnName("banned_user_uid"); + + b.Property("BannedByUID") + .HasColumnType("character varying(10)") + .HasColumnName("banned_by_uid"); + + b.Property("BannedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("banned_on"); + + b.Property("BannedReason") + .HasColumnType("text") + .HasColumnName("banned_reason"); + + b.HasKey("GroupGID", "BannedUserUID") + .HasName("pk_group_bans"); + + b.HasIndex("BannedByUID") + .HasDatabaseName("ix_group_bans_banned_by_uid"); + + b.HasIndex("BannedUserUID") + .HasDatabaseName("ix_group_bans_banned_user_uid"); + + b.HasIndex("GroupGID") + .HasDatabaseName("ix_group_bans_group_gid"); + + b.ToTable("group_bans", (string)null); + }); + modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b => { b.Property("GroupGID") @@ -214,6 +251,10 @@ namespace MareSynchronosServer.Migrations .HasColumnType("character varying(10)") .HasColumnName("group_user_uid"); + b.Property("IsModerator") + .HasColumnType("boolean") + .HasColumnName("is_moderator"); + b.Property("IsPaused") .HasColumnType("boolean") .HasColumnName("is_paused"); @@ -350,11 +391,39 @@ namespace MareSynchronosServer.Migrations b.HasOne("MareSynchronosShared.Models.User", "Owner") .WithMany() .HasForeignKey("OwnerUID") - .HasConstraintName("fk_groups_users_owner_temp_id5"); + .HasConstraintName("fk_groups_users_owner_temp_id7"); b.Navigation("Owner"); }); + modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b => + { + b.HasOne("MareSynchronosShared.Models.User", "BannedBy") + .WithMany() + .HasForeignKey("BannedByUID") + .HasConstraintName("fk_group_bans_users_banned_by_temp_id4"); + + b.HasOne("MareSynchronosShared.Models.User", "BannedUser") + .WithMany() + .HasForeignKey("BannedUserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_bans_users_banned_user_temp_id5"); + + b.HasOne("MareSynchronosShared.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupGID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_bans_groups_group_temp_id"); + + b.Navigation("BannedBy"); + + b.Navigation("BannedUser"); + + b.Navigation("Group"); + }); + modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b => { b.HasOne("MareSynchronosShared.Models.Group", "Group") @@ -362,14 +431,14 @@ namespace MareSynchronosServer.Migrations .HasForeignKey("GroupGID") .OnDelete(DeleteBehavior.Cascade) .IsRequired() - .HasConstraintName("fk_group_pairs_groups_group_temp_id"); + .HasConstraintName("fk_group_pairs_groups_group_temp_id1"); b.HasOne("MareSynchronosShared.Models.User", "GroupUser") .WithMany() .HasForeignKey("GroupUserUID") .OnDelete(DeleteBehavior.Cascade) .IsRequired() - .HasConstraintName("fk_group_pairs_users_group_user_temp_id4"); + .HasConstraintName("fk_group_pairs_users_group_user_temp_id6"); b.Navigation("Group"); diff --git a/MareSynchronosServer/MareSynchronosShared/Models/GroupBan.cs b/MareSynchronosServer/MareSynchronosShared/Models/GroupBan.cs new file mode 100644 index 0000000..0326bab --- /dev/null +++ b/MareSynchronosServer/MareSynchronosShared/Models/GroupBan.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MareSynchronosShared.Models; + +public class GroupBan +{ + public Group Group { get; set; } + public string GroupGID { get; set; } + public User BannedUser { get; set; } + public string BannedUserUID { get; set; } + public User BannedBy { get; set; } + public string BannedByUID { get; set; } + public DateTime BannedOn { get; set; } + public string BannedReason { get; set; } +} diff --git a/MareSynchronosServer/MareSynchronosShared/Models/GroupPair.cs b/MareSynchronosServer/MareSynchronosShared/Models/GroupPair.cs index d3cdf47..873b1dc 100644 --- a/MareSynchronosServer/MareSynchronosShared/Models/GroupPair.cs +++ b/MareSynchronosServer/MareSynchronosShared/Models/GroupPair.cs @@ -8,4 +8,5 @@ public class GroupPair public User GroupUser { get; set; } public bool IsPaused { get; set; } public bool IsPinned { get; set; } + public bool IsModerator { get; set; } } diff --git a/MareSynchronosServer/MareSynchronosShared/Utils/SharedDbFunctions.cs b/MareSynchronosServer/MareSynchronosShared/Utils/SharedDbFunctions.cs index ed922a9..6597fe2 100644 --- a/MareSynchronosServer/MareSynchronosShared/Utils/SharedDbFunctions.cs +++ b/MareSynchronosServer/MareSynchronosShared/Utils/SharedDbFunctions.cs @@ -22,6 +22,10 @@ public static class SharedDbFunctions if (groupHasMigrated) { newOwner = potentialNewOwner.GroupUserUID; + potentialNewOwner.IsPinned = true; + potentialNewOwner.IsModerator = false; + + await context.SaveChangesAsync().ConfigureAwait(false); break; } }