#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using NadekoBot.Db.Models; // ReSharper disable UnusedAutoPropertyAccessor.Global namespace NadekoBot.Db; public abstract class NadekoContext : DbContext { public DbSet GuildConfigs { get; set; } public DbSet GreetSettings { get; set; } public DbSet Quotes { get; set; } public DbSet Reminders { get; set; } public DbSet SelfAssignableRoles { get; set; } public DbSet MusicPlaylists { get; set; } public DbSet Expressions { get; set; } public DbSet CurrencyTransactions { get; set; } public DbSet WaifuUpdates { get; set; } public DbSet WaifuItem { get; set; } public DbSet Warnings { get; set; } public DbSet UserXpStats { get; set; } public DbSet Clubs { get; set; } public DbSet ClubBans { get; set; } public DbSet ClubApplicants { get; set; } //logging public DbSet LogSettings { get; set; } public DbSet IgnoredLogChannels { get; set; } public DbSet RotatingStatus { get; set; } public DbSet Blacklist { get; set; } public DbSet AutoCommands { get; set; } public DbSet RewardedUsers { get; set; } public DbSet PlantedCurrency { get; set; } public DbSet BanTemplates { get; set; } public DbSet DiscordPermOverrides { get; set; } public DbSet DiscordUser { get; set; } public DbSet MusicPlayerSettings { get; set; } public DbSet Repeaters { get; set; } public DbSet WaifuInfo { get; set; } public DbSet ImageOnlyChannels { get; set; } public DbSet AutoTranslateChannels { get; set; } public DbSet AutoTranslateUsers { get; set; } public DbSet Permissions { get; set; } public DbSet BankUsers { get; set; } public DbSet ReactionRoles { get; set; } public DbSet Patrons { get; set; } public DbSet StreamOnlineMessages { get; set; } public DbSet StickyRoles { get; set; } public DbSet Todos { get; set; } public DbSet TodosArchive { get; set; } public DbSet HoneyPotChannels { get; set; } // todo add guild colors // public DbSet GuildColors { get; set; } #region Mandatory Provider-Specific Values protected abstract string CurrencyTransactionOtherIdDefaultValue { get; } #endregion protected override void OnModelCreating(ModelBuilder modelBuilder) { #region QUOTES var quoteEntity = modelBuilder.Entity(); quoteEntity.HasIndex(x => x.GuildId); quoteEntity.HasIndex(x => x.Keyword); #endregion #region GuildConfig var configEntity = modelBuilder.Entity(); configEntity.HasIndex(c => c.GuildId) .IsUnique(); configEntity.Property(x => x.VerboseErrors) .HasDefaultValue(true); modelBuilder.Entity() .HasMany(x => x.DelMsgOnCmdChannels) .WithOne() .HasForeignKey(x => x.GuildConfigId) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.FollowedStreams) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.GenerateCurrencyChannelIds) .WithOne(x => x.GuildConfig) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.Permissions) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.CommandCooldowns) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.FilterInvitesChannelIds) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.FilterLinksChannelIds) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.FilteredWords) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.FilterWordsChannelIds) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.MutedUsers) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasOne(x => x.AntiRaidSetting) .WithOne() .HasForeignKey(x => x.GuildConfigId) .OnDelete(DeleteBehavior.Cascade); // start antispam modelBuilder.Entity() .HasOne(x => x.AntiSpamSetting) .WithOne() .HasForeignKey(x => x.GuildConfigId) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.IgnoredChannels) .WithOne() .OnDelete(DeleteBehavior.Cascade); // end antispam modelBuilder.Entity() .HasOne(x => x.AntiAltSetting) .WithOne() .HasForeignKey(x => x.GuildConfigId) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.UnmuteTimers) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.UnbanTimer) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.UnroleTimer) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.VcRoleInfos) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.CommandAliases) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.WarnPunishments) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.SlowmodeIgnoredRoles) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.SlowmodeIgnoredUsers) .WithOne() .OnDelete(DeleteBehavior.Cascade); // start shop modelBuilder.Entity() .HasMany(x => x.ShopEntries) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.Items) .WithOne() .OnDelete(DeleteBehavior.Cascade); // end shop // start streamrole modelBuilder.Entity() .HasOne(x => x.StreamRole) .WithOne(x => x.GuildConfig) .HasForeignKey(x => x.GuildConfigId) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.Whitelist) .WithOne(x => x.StreamRoleSettings) .HasForeignKey(x => x.StreamRoleSettingsId) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.Blacklist) .WithOne(x => x.StreamRoleSettings) .HasForeignKey(x => x.StreamRoleSettingsId) .OnDelete(DeleteBehavior.Cascade); // end streamrole modelBuilder.Entity() .HasOne(x => x.XpSettings) .WithOne(x => x.GuildConfig) .HasForeignKey(x => x.GuildConfigId) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.FeedSubs) .WithOne(x => x.GuildConfig) .HasForeignKey(x => x.GuildConfigId) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.SelfAssignableRoleGroupNames) .WithOne() .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasAlternateKey(x => new { x.GuildConfigId, x.Url }); modelBuilder.Entity().HasIndex(x => x.MessageId).IsUnique(); modelBuilder.Entity().HasIndex(x => x.ChannelId); configEntity.HasIndex(x => x.WarnExpireHours).IsUnique(false); #endregion #region Self Assignable Roles var selfassignableRolesEntity = modelBuilder.Entity(); selfassignableRolesEntity.HasIndex(s => new { s.GuildId, s.RoleId }) .IsUnique(); selfassignableRolesEntity.Property(x => x.Group).HasDefaultValue(0); #endregion #region MusicPlaylists var musicPlaylistEntity = modelBuilder.Entity(); musicPlaylistEntity.HasMany(p => p.Songs).WithOne().OnDelete(DeleteBehavior.Cascade); #endregion #region Waifus var wi = modelBuilder.Entity(); wi.HasOne(x => x.Waifu).WithOne(); wi.HasIndex(x => x.Price); wi.HasIndex(x => x.ClaimerId); // wi.HasMany(x => x.Items) // .WithOne() // .OnDelete(DeleteBehavior.Cascade); #endregion #region DiscordUser modelBuilder.Entity(du => { du.Property(x => x.IsClubAdmin) .HasDefaultValue(false); du.Property(x => x.NotifyOnLevelUp) .HasDefaultValue(XpNotificationLocation.None); du.Property(x => x.TotalXp) .HasDefaultValue(0); du.Property(x => x.CurrencyAmount) .HasDefaultValue(0); du.HasAlternateKey(w => w.UserId); du.HasOne(x => x.Club) .WithMany(x => x.Members) .IsRequired(false) .OnDelete(DeleteBehavior.NoAction); du.HasIndex(x => x.TotalXp); du.HasIndex(x => x.CurrencyAmount); du.HasIndex(x => x.UserId); }); #endregion #region Warnings modelBuilder.Entity(warn => { warn.HasIndex(x => x.GuildId); warn.HasIndex(x => x.UserId); warn.HasIndex(x => x.DateAdded); warn.Property(x => x.Weight).HasDefaultValue(1); }); #endregion #region XpStats var xps = modelBuilder.Entity(); xps.HasIndex(x => new { x.UserId, x.GuildId }) .IsUnique(); xps.HasIndex(x => x.UserId); xps.HasIndex(x => x.GuildId); xps.HasIndex(x => x.Xp); xps.HasIndex(x => x.AwardedXp); #endregion #region XpRoleReward modelBuilder.Entity() .HasIndex(x => new { x.XpSettingsId, x.Level }) .IsUnique(); modelBuilder.Entity() .HasMany(x => x.RoleRewards) .WithOne(x => x.XpSettings) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.CurrencyRewards) .WithOne(x => x.XpSettings) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() .HasMany(x => x.ExclusionList) .WithOne(x => x.XpSettings) .OnDelete(DeleteBehavior.Cascade); #endregion #region Club var ci = modelBuilder.Entity(); ci.HasOne(x => x.Owner) .WithOne() .HasForeignKey(x => x.OwnerId) .OnDelete(DeleteBehavior.SetNull); ci.HasIndex(x => new { x.Name }) .IsUnique(); #endregion #region ClubManytoMany modelBuilder.Entity() .HasKey(t => new { t.ClubId, t.UserId }); modelBuilder.Entity() .HasOne(pt => pt.User) .WithMany(); modelBuilder.Entity() .HasOne(pt => pt.Club) .WithMany(x => x.Applicants); modelBuilder.Entity() .HasKey(t => new { t.ClubId, t.UserId }); modelBuilder.Entity() .HasOne(pt => pt.User) .WithMany(); modelBuilder.Entity() .HasOne(pt => pt.Club) .WithMany(x => x.Bans); #endregion #region CurrencyTransactions modelBuilder.Entity(e => { e.HasIndex(x => x.UserId) .IsUnique(false); e.Property(x => x.OtherId) .HasDefaultValueSql(CurrencyTransactionOtherIdDefaultValue); e.Property(x => x.Type) .IsRequired(); e.Property(x => x.Extra) .IsRequired(); }); #endregion #region Reminders modelBuilder.Entity().HasIndex(x => x.When); #endregion #region GroupName modelBuilder.Entity() .HasIndex(x => new { x.GuildConfigId, x.Number }) .IsUnique(); modelBuilder.Entity() .HasOne(x => x.GuildConfig) .WithMany(x => x.SelfAssignableRoleGroupNames) .IsRequired(); #endregion #region BanTemplate modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); modelBuilder.Entity() .Property(x => x.PruneDays) .HasDefaultValue(null) .IsRequired(false); #endregion #region Perm Override modelBuilder.Entity() .HasIndex(x => new { x.GuildId, x.Command }) .IsUnique(); #endregion #region Music modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); modelBuilder.Entity().Property(x => x.Volume).HasDefaultValue(100); #endregion #region Reaction roles modelBuilder.Entity(rr2 => { rr2.HasIndex(x => x.GuildId) .IsUnique(false); rr2.HasIndex(x => new { x.MessageId, x.Emote }) .IsUnique(); }); #endregion #region LogSettings modelBuilder.Entity(ls => ls.HasIndex(x => x.GuildId).IsUnique()); modelBuilder.Entity(ls => ls .HasMany(x => x.LogIgnores) .WithOne(x => x.LogSetting) .OnDelete(DeleteBehavior.Cascade)); modelBuilder.Entity(ili => ili .HasIndex(x => new { x.LogSettingId, x.LogItemId, x.ItemType }) .IsUnique()); #endregion modelBuilder.Entity(ioc => ioc.HasIndex(x => x.ChannelId).IsUnique()); var atch = modelBuilder.Entity(); atch.HasIndex(x => x.GuildId).IsUnique(false); atch.HasIndex(x => x.ChannelId).IsUnique(); atch.HasMany(x => x.Users).WithOne(x => x.Channel).OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity(atu => atu.HasAlternateKey(x => new { x.ChannelId, x.UserId })); #region BANK modelBuilder.Entity(bu => bu.HasIndex(x => x.UserId).IsUnique()); #endregion #region Patron // currency rewards var pr = modelBuilder.Entity(); pr.HasIndex(x => x.PlatformUserId).IsUnique(); // patrons // patrons are not identified by their user id, but by their platform user id // as multiple accounts (even maybe on different platforms) could have // the same account connected to them modelBuilder.Entity(pu => { pu.HasIndex(x => x.UniquePlatformUserId).IsUnique(); pu.HasKey(x => x.UserId); }); // quotes are per user id #endregion #region Xp Item Shop modelBuilder.Entity( x => { // user can own only one of each item x.HasIndex(model => new { model.UserId, model.ItemType, model.ItemKey }) .IsUnique(); }); #endregion #region AutoPublish modelBuilder.Entity(apc => apc .HasIndex(x => x.GuildId) .IsUnique()); #endregion #region GamblingStats modelBuilder.Entity(gs => gs .HasIndex(x => x.Feature) .IsUnique()); #endregion #region Sticky Roles modelBuilder.Entity(sr => sr.HasIndex(x => new { x.GuildId, x.UserId }) .IsUnique()); #endregion #region Giveaway modelBuilder.Entity() .HasMany(x => x.Participants) .WithOne() .HasForeignKey(x => x.GiveawayId) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity(gu => gu .HasIndex(x => new { x.GiveawayId, x.UserId }) .IsUnique()); #endregion #region Todo modelBuilder.Entity() .HasKey(x => x.Id); modelBuilder.Entity() .HasIndex(x => x.UserId) .IsUnique(false); modelBuilder.Entity() .HasMany(x => x.Items) .WithOne() .HasForeignKey(x => x.ArchiveId) .OnDelete(DeleteBehavior.Cascade); #endregion #region GreetSettings modelBuilder .Entity(gs => gs.HasIndex(x => new { x.GuildId, x.GreetType }) .IsUnique()); modelBuilder.Entity(gs => { gs .Property(x => x.IsEnabled) .HasDefaultValue(false); gs .Property(x => x.AutoDeleteTimer) .HasDefaultValue(0); }); #endregion } #if DEBUG private static readonly ILoggerFactory _debugLoggerFactory = LoggerFactory.Create(x => x.AddConsole()); protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseLoggerFactory(_debugLoggerFactory); #endif }