diff --git a/src/GrillBot.App/Actions/Api/V1/User/GetUserList.cs b/src/GrillBot.App/Actions/Api/V1/User/GetUserList.cs index a1c9805f..27cf4e92 100644 --- a/src/GrillBot.App/Actions/Api/V1/User/GetUserList.cs +++ b/src/GrillBot.App/Actions/Api/V1/User/GetUserList.cs @@ -1,4 +1,6 @@ -using GrillBot.Common.Models; +using GrillBot.Common.Extensions; +using GrillBot.Common.Managers.Localization; +using GrillBot.Common.Models; using GrillBot.Core.Extensions; using GrillBot.Core.Infrastructure.Actions; using GrillBot.Core.Models.Pagination; @@ -10,17 +12,22 @@ public class GetUserList : ApiAction { private GrillBotDatabaseBuilder DatabaseBuilder { get; } private IDiscordClient DiscordClient { get; } + private ITextsManager Texts { get; } - public GetUserList(ApiRequestContext apiContext, GrillBotDatabaseBuilder databaseBuilder, IDiscordClient discordClient) : base(apiContext) + public GetUserList(ApiRequestContext apiContext, GrillBotDatabaseBuilder databaseBuilder, IDiscordClient discordClient, + ITextsManager texts) : base(apiContext) { DatabaseBuilder = databaseBuilder; DiscordClient = discordClient; + Texts = texts; } public override async Task ProcessAsync() { var parameters = (GetUserListParams)Parameters[0]!; - parameters.FixStatus(); + + FixStatus(parameters); + ValidateParameters(parameters); await using var repository = DatabaseBuilder.CreateRepository(); @@ -55,4 +62,23 @@ private async Task MapItemAsync(Database.Entity.User entity) return result; } + + public void FixStatus(GetUserListParams parameters) + { + parameters.Status = parameters.Status switch + { + UserStatus.Invisible => UserStatus.Offline, + UserStatus.AFK => UserStatus.Idle, + _ => parameters.Status + }; + } + + private void ValidateParameters(GetUserListParams parameters) + { + if (parameters.HideLeftUsers && string.IsNullOrEmpty(parameters.GuildId)) + { + throw new ValidationException(Texts["User/Validation/CannotHideMissingGuildId", ApiContext.Language]) + .ToBadRequestValidation(parameters.HideLeftUsers, nameof(parameters.HideLeftUsers), nameof(parameters.GuildId)); + } + } } diff --git a/src/GrillBot.App/Handlers/Ready/UserInitSynchronizationHandler.cs b/src/GrillBot.App/Handlers/Ready/UserInitSynchronizationHandler.cs index bfdb0fab..80f1e67a 100644 --- a/src/GrillBot.App/Handlers/Ready/UserInitSynchronizationHandler.cs +++ b/src/GrillBot.App/Handlers/Ready/UserInitSynchronizationHandler.cs @@ -35,6 +35,8 @@ private async Task ProcessMemberSynchronizationAsync() foreach (var user in users.Where(o => o.GuildId == guild.Id.ToString())) { user.User!.Status = UserStatus.Offline; + user.IsInGuild = false; + if (!members.TryGetValue(user.UserId.ToUlong(), out var guildUser)) continue; diff --git a/src/GrillBot.Data/Models/API/Users/GetUserListParams.cs b/src/GrillBot.Data/Models/API/Users/GetUserListParams.cs index 601fccdd..a572693e 100644 --- a/src/GrillBot.Data/Models/API/Users/GetUserListParams.cs +++ b/src/GrillBot.Data/Models/API/Users/GetUserListParams.cs @@ -24,6 +24,11 @@ public class GetUserListParams : IQueryableModel, IDiction [DiscordId] public string? GuildId { get; set; } + /// + /// Hide non-guild users. Works only if is filled. Otherwise validation error will show. + /// + public bool HideLeftUsers { get; set; } + /// /// Selected flags from UserFlags enum. /// @@ -62,9 +67,14 @@ public class GetUserListParams : IQueryableModel, IDiction } if (!string.IsNullOrEmpty(GuildId)) - query = query.Where(o => o.Guilds.Any(x => x.GuildId == GuildId)); + { + if (!HideLeftUsers) + query = query.Where(o => o.Guilds.Any(x => x.GuildId == GuildId)); + else + query = query.Where(o => o.Guilds.Any(x => GuildId == x.GuildId && x.IsInGuild)); + } - if (Flags != null) + if (Flags != null && Flags > 0) query = query.Where(o => (o.Flags & Flags) == Flags); if (HaveBirthday) @@ -88,16 +98,6 @@ public class GetUserListParams : IQueryableModel, IDiction }; } - public void FixStatus() - { - Status = Status switch - { - UserStatus.Invisible => UserStatus.Offline, - UserStatus.AFK => UserStatus.Idle, - _ => Status - }; - } - public Dictionary ToDictionary() { var result = new Dictionary @@ -107,6 +107,7 @@ public void FixStatus() { nameof(Flags), (Flags ?? 0).ToString() }, { nameof(HaveBirthday), HaveBirthday.ToString() }, { nameof(UsedInviteCode), UsedInviteCode }, + { nameof(HideLeftUsers), HideLeftUsers.ToString() } }; if (Status != null) diff --git a/src/GrillBot.Data/Resources/Localization/messages.cs.json b/src/GrillBot.Data/Resources/Localization/messages.cs.json index 717fb7b8..b8a62202 100644 --- a/src/GrillBot.Data/Resources/Localization/messages.cs.json +++ b/src/GrillBot.Data/Resources/Localization/messages.cs.json @@ -497,6 +497,9 @@ "Unverify": "Unverify", "Timeout": "Dočasné umlčení", "MemberWarning": "Varování" + }, + "Validation": { + "CannotHideMissingGuildId": "Nelze skrýt uživatele, kteří nejsou na serveru. Nejprve vyplň filtr serveru." } }, "Emojization": { diff --git a/src/GrillBot.Data/Resources/Localization/messages.en-US.json b/src/GrillBot.Data/Resources/Localization/messages.en-US.json index f4730230..f1ccc4bf 100644 --- a/src/GrillBot.Data/Resources/Localization/messages.en-US.json +++ b/src/GrillBot.Data/Resources/Localization/messages.en-US.json @@ -497,6 +497,9 @@ "Unverify": "Unverify", "Timeout": "Timeout", "MemberWarning": "Warning" + }, + "Validation": { + "CannotHideMissingGuildId": "Cannot hide users who are not on the server. First, fill in the server filter." } }, "Emojization": { diff --git a/src/GrillBot.Database/Entity/GuildUser.cs b/src/GrillBot.Database/Entity/GuildUser.cs index 9a3637e0..59adccd8 100644 --- a/src/GrillBot.Database/Entity/GuildUser.cs +++ b/src/GrillBot.Database/Entity/GuildUser.cs @@ -45,6 +45,8 @@ public class GuildUser [MinLength(2)] public string? Nickname { get; set; } + public bool IsInGuild { get; set; } + public ISet Channels { get; set; } public ISet EmoteStatistics { get; set; } public ISet Nicknames { get; set; } @@ -76,6 +78,7 @@ public static GuildUser FromDiscord(IGuild guild, IGuildUser user) public void Update(IGuildUser user) { Nickname = user.IsUser() ? user.Nickname : user.Nickname?.Cut(32, true); + IsInGuild = true; User?.Update(user); } } diff --git a/src/GrillBot.Database/Migrations/20240202092511_GuildUser_IsInGuild.Designer.cs b/src/GrillBot.Database/Migrations/20240202092511_GuildUser_IsInGuild.Designer.cs new file mode 100644 index 00000000..983900f9 --- /dev/null +++ b/src/GrillBot.Database/Migrations/20240202092511_GuildUser_IsInGuild.Designer.cs @@ -0,0 +1,915 @@ +// +using System; +using System.Collections.Generic; +using GrillBot.Database.Entity; +using GrillBot.Database.Services; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace GrillBot.Database.Migrations +{ + [DbContext(typeof(GrillBotContext))] + [Migration("20240202092511_GuildUser_IsInGuild")] + partial class GuildUser_IsInGuild + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("GrillBot.Database.Entity.ApiClient", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property>("AllowedMethods") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Disabled") + .HasColumnType("boolean"); + + b.Property("LastUse") + .HasColumnType("timestamp without time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("UseCount") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("ApiClients"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.AutoReplyItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Flags") + .HasColumnType("bigint"); + + b.Property("Reply") + .IsRequired() + .HasColumnType("text"); + + b.Property("Template") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("AutoReplies"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.EmoteStatisticItem", b => + { + b.Property("EmoteId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("UserId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("GuildId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("FirstOccurence") + .HasColumnType("timestamp without time zone"); + + b.Property("IsEmoteSupported") + .HasColumnType("boolean"); + + b.Property("LastOccurence") + .HasColumnType("timestamp without time zone"); + + b.Property("UseCount") + .HasColumnType("bigint"); + + b.HasKey("EmoteId", "UserId", "GuildId"); + + b.HasIndex("GuildId", "UserId"); + + b.ToTable("Emotes"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.EmoteSuggestion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApprovedForVote") + .HasColumnType("boolean"); + + b.Property("CommunityApproved") + .HasColumnType("boolean"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("DownVotes") + .HasColumnType("integer"); + + b.Property("EmoteName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Filename") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("FromUserId") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("GuildId") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ImageData") + .IsRequired() + .HasColumnType("bytea"); + + b.Property("SuggestionMessageId") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("UpVotes") + .HasColumnType("integer"); + + b.Property("VoteEndsAt") + .HasColumnType("timestamp without time zone"); + + b.Property("VoteFinished") + .HasColumnType("boolean"); + + b.Property("VoteMessageId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "FromUserId"); + + b.ToTable("EmoteSuggestions"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.Guild", b => + { + b.Property("Id") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("AdminChannelId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("BoosterRoleId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("BotRoomChannelId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("EmoteSuggestionChannelId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("EmoteSuggestionsFrom") + .HasColumnType("timestamp without time zone"); + + b.Property("EmoteSuggestionsTo") + .HasColumnType("timestamp without time zone"); + + b.Property("MuteRoleId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("VoteChannelId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.HasKey("Id"); + + b.ToTable("Guilds"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.GuildChannel", b => + { + b.Property("GuildId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ChannelId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ChannelType") + .HasColumnType("integer"); + + b.Property("Flags") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ParentChannelId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("PinCount") + .HasColumnType("integer"); + + b.Property("RolePermissionsCount") + .HasColumnType("integer"); + + b.Property("UserPermissionsCount") + .HasColumnType("integer"); + + b.HasKey("GuildId", "ChannelId"); + + b.HasIndex("GuildId", "ParentChannelId"); + + b.ToTable("Channels"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.GuildUser", b => + { + b.Property("GuildId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("UserId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("GivenReactions") + .HasColumnType("bigint"); + + b.Property("IsInGuild") + .HasColumnType("boolean"); + + b.Property("Nickname") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("ObtainedReactions") + .HasColumnType("bigint"); + + b.Property("UsedInviteCode") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.HasKey("GuildId", "UserId"); + + b.HasIndex("UsedInviteCode"); + + b.HasIndex("UserId"); + + b.ToTable("GuildUsers"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.GuildUserChannel", b => + { + b.Property("GuildId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ChannelId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("UserId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Count") + .HasColumnType("bigint"); + + b.Property("FirstMessageAt") + .HasColumnType("timestamp without time zone"); + + b.Property("LastMessageAt") + .HasColumnType("timestamp without time zone"); + + b.HasKey("GuildId", "ChannelId", "UserId"); + + b.HasIndex("UserId"); + + b.HasIndex("GuildId", "UserId"); + + b.ToTable("UserChannels"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.Invite", b => + { + b.Property("Code") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatorId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("GuildId") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.HasKey("Code"); + + b.HasIndex("GuildId", "CreatorId"); + + b.ToTable("Invites"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.Nickname", b => + { + b.Property("GuildId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("UserId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("NicknameValue") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.HasKey("GuildId", "UserId", "Id"); + + b.ToTable("Nicknames"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.RemindMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("At") + .HasColumnType("timestamp without time zone"); + + b.Property("FromUserId") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Language") + .IsRequired() + .HasColumnType("text"); + + b.Property("Message") + .IsRequired() + .HasColumnType("text"); + + b.Property("OriginalMessageId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Postpone") + .HasColumnType("integer"); + + b.Property("RemindMessageId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ToUserId") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.HasKey("Id"); + + b.HasIndex("FromUserId"); + + b.HasIndex("ToUserId"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.SearchItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("GuildId") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("MessageContent") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("UserId") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("GuildId", "ChannelId"); + + b.ToTable("SearchItems"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.SelfunverifyKeepable", b => + { + b.Property("GroupName") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("GroupName", "Name"); + + b.ToTable("SelfunverifyKeepables"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.Unverify", b => + { + b.Property("GuildId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("UserId") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property>("Channels") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("EndAt") + .HasColumnType("timestamp without time zone"); + + b.Property("Reason") + .HasColumnType("text"); + + b.Property>("Roles") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("SetOperationId") + .HasColumnType("bigint"); + + b.Property("StartAt") + .HasColumnType("timestamp without time zone"); + + b.HasKey("GuildId", "UserId"); + + b.HasIndex("SetOperationId") + .IsUnique(); + + b.ToTable("Unverifies"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.UnverifyLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("FromUserId") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("GuildId") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Operation") + .HasColumnType("integer"); + + b.Property("ToUserId") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "FromUserId"); + + b.HasIndex("GuildId", "ToUserId"); + + b.ToTable("UnverifyLogs"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.User", b => + { + b.Property("Id") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("AvatarUrl") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("Birthday") + .HasColumnType("timestamp without time zone"); + + b.Property("Flags") + .HasColumnType("integer"); + + b.Property("GlobalAlias") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("Language") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("SelfUnverifyMinimalTime") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.EmoteStatisticItem", b => + { + b.HasOne("GrillBot.Database.Entity.Guild", "Guild") + .WithMany("EmoteStatistics") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.GuildUser", "User") + .WithMany("EmoteStatistics") + .HasForeignKey("GuildId", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Guild"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.EmoteSuggestion", b => + { + b.HasOne("GrillBot.Database.Entity.Guild", "Guild") + .WithMany() + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.GuildUser", "FromUser") + .WithMany() + .HasForeignKey("GuildId", "FromUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FromUser"); + + b.Navigation("Guild"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.GuildChannel", b => + { + b.HasOne("GrillBot.Database.Entity.Guild", "Guild") + .WithMany("Channels") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.GuildChannel", "ParentChannel") + .WithMany() + .HasForeignKey("GuildId", "ParentChannelId"); + + b.Navigation("Guild"); + + b.Navigation("ParentChannel"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.GuildUser", b => + { + b.HasOne("GrillBot.Database.Entity.Guild", "Guild") + .WithMany("Users") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.Invite", "UsedInvite") + .WithMany("UsedUsers") + .HasForeignKey("UsedInviteCode"); + + b.HasOne("GrillBot.Database.Entity.User", "User") + .WithMany("Guilds") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Guild"); + + b.Navigation("UsedInvite"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.GuildUserChannel", b => + { + b.HasOne("GrillBot.Database.Entity.Guild", "Guild") + .WithMany() + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.User", null) + .WithMany("Channels") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.GuildChannel", "Channel") + .WithMany("Users") + .HasForeignKey("GuildId", "ChannelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.GuildUser", "User") + .WithMany("Channels") + .HasForeignKey("GuildId", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Channel"); + + b.Navigation("Guild"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.Invite", b => + { + b.HasOne("GrillBot.Database.Entity.Guild", "Guild") + .WithMany("Invites") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.GuildUser", "Creator") + .WithMany("CreatedInvites") + .HasForeignKey("GuildId", "CreatorId"); + + b.Navigation("Creator"); + + b.Navigation("Guild"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.Nickname", b => + { + b.HasOne("GrillBot.Database.Entity.GuildUser", "User") + .WithMany("Nicknames") + .HasForeignKey("GuildId", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.RemindMessage", b => + { + b.HasOne("GrillBot.Database.Entity.User", "FromUser") + .WithMany("OutgoingReminders") + .HasForeignKey("FromUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.User", "ToUser") + .WithMany("IncomingReminders") + .HasForeignKey("ToUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FromUser"); + + b.Navigation("ToUser"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.SearchItem", b => + { + b.HasOne("GrillBot.Database.Entity.Guild", "Guild") + .WithMany("Searches") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.User", "User") + .WithMany("SearchItems") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.GuildChannel", "Channel") + .WithMany("SearchItems") + .HasForeignKey("GuildId", "ChannelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Channel"); + + b.Navigation("Guild"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.Unverify", b => + { + b.HasOne("GrillBot.Database.Entity.Guild", "Guild") + .WithMany("Unverifies") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.UnverifyLog", "UnverifyLog") + .WithOne("Unverify") + .HasForeignKey("GrillBot.Database.Entity.Unverify", "SetOperationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.GuildUser", "GuildUser") + .WithOne("Unverify") + .HasForeignKey("GrillBot.Database.Entity.Unverify", "GuildId", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Guild"); + + b.Navigation("GuildUser"); + + b.Navigation("UnverifyLog"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.UnverifyLog", b => + { + b.HasOne("GrillBot.Database.Entity.Guild", "Guild") + .WithMany("UnverifyLogs") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.GuildUser", "FromUser") + .WithMany() + .HasForeignKey("GuildId", "FromUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GrillBot.Database.Entity.GuildUser", "ToUser") + .WithMany() + .HasForeignKey("GuildId", "ToUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FromUser"); + + b.Navigation("Guild"); + + b.Navigation("ToUser"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.Guild", b => + { + b.Navigation("Channels"); + + b.Navigation("EmoteStatistics"); + + b.Navigation("Invites"); + + b.Navigation("Searches"); + + b.Navigation("Unverifies"); + + b.Navigation("UnverifyLogs"); + + b.Navigation("Users"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.GuildChannel", b => + { + b.Navigation("SearchItems"); + + b.Navigation("Users"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.GuildUser", b => + { + b.Navigation("Channels"); + + b.Navigation("CreatedInvites"); + + b.Navigation("EmoteStatistics"); + + b.Navigation("Nicknames"); + + b.Navigation("Unverify"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.Invite", b => + { + b.Navigation("UsedUsers"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.UnverifyLog", b => + { + b.Navigation("Unverify"); + }); + + modelBuilder.Entity("GrillBot.Database.Entity.User", b => + { + b.Navigation("Channels"); + + b.Navigation("Guilds"); + + b.Navigation("IncomingReminders"); + + b.Navigation("OutgoingReminders"); + + b.Navigation("SearchItems"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/GrillBot.Database/Migrations/20240202092511_GuildUser_IsInGuild.cs b/src/GrillBot.Database/Migrations/20240202092511_GuildUser_IsInGuild.cs new file mode 100644 index 00000000..a2967e5b --- /dev/null +++ b/src/GrillBot.Database/Migrations/20240202092511_GuildUser_IsInGuild.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GrillBot.Database.Migrations +{ + /// + public partial class GuildUser_IsInGuild : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsInGuild", + table: "GuildUsers", + type: "boolean", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsInGuild", + table: "GuildUsers"); + } + } +} diff --git a/src/GrillBot.Database/Migrations/GrillBotContextModelSnapshot.cs b/src/GrillBot.Database/Migrations/GrillBotContextModelSnapshot.cs index 5d39ba35..d110d895 100644 --- a/src/GrillBot.Database/Migrations/GrillBotContextModelSnapshot.cs +++ b/src/GrillBot.Database/Migrations/GrillBotContextModelSnapshot.cs @@ -282,6 +282,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("GivenReactions") .HasColumnType("bigint"); + b.Property("IsInGuild") + .HasColumnType("boolean"); + b.Property("Nickname") .HasMaxLength(32) .HasColumnType("character varying(32)");