Added Db stuff

This commit is contained in:
Toastie (DCS Team) 2024-05-14 23:08:36 +12:00
parent 545786e23e
commit 9fff64f951
Signed by: toastie_t0ast
GPG key ID: 27F3B6855AFD40A4
87 changed files with 2881 additions and 0 deletions

View file

@ -0,0 +1,535 @@
#nullable disable
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using EllieBot.Db.Models;
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace EllieBot.Db;
public abstract class EllieContext : DbContext
{
public DbSet<GuildConfig> GuildConfigs { get; set; }
public DbSet<Quote> Quotes { get; set; }
public DbSet<Reminder> Reminders { get; set; }
public DbSet<SelfAssignedRole> SelfAssignableRoles { get; set; }
public DbSet<MusicPlaylist> MusicPlaylists { get; set; }
public DbSet<EllieExpression> Expressions { get; set; }
public DbSet<CurrencyTransaction> CurrencyTransactions { get; set; }
public DbSet<WaifuUpdate> WaifuUpdates { get; set; }
public DbSet<WaifuItem> WaifuItem { get; set; }
public DbSet<Warning> Warnings { get; set; }
public DbSet<UserXpStats> UserXpStats { get; set; }
public DbSet<ClubInfo> Clubs { get; set; }
public DbSet<ClubBans> ClubBans { get; set; }
public DbSet<ClubApplicants> ClubApplicants { get; set; }
//logging
public DbSet<LogSetting> LogSettings { get; set; }
public DbSet<IgnoredVoicePresenceChannel> IgnoredVoicePresenceCHannels { get; set; }
public DbSet<IgnoredLogItem> IgnoredLogChannels { get; set; }
public DbSet<RotatingPlayingStatus> RotatingStatus { get; set; }
public DbSet<BlacklistEntry> Blacklist { get; set; }
public DbSet<AutoCommand> AutoCommands { get; set; }
public DbSet<RewardedUser> RewardedUsers { get; set; }
public DbSet<PlantedCurrency> PlantedCurrency { get; set; }
public DbSet<BanTemplate> BanTemplates { get; set; }
public DbSet<DiscordPermOverride> DiscordPermOverrides { get; set; }
public DbSet<DiscordUser> DiscordUser { get; set; }
public DbSet<MusicPlayerSettings> MusicPlayerSettings { get; set; }
public DbSet<Repeater> Repeaters { get; set; }
public DbSet<WaifuInfo> WaifuInfo { get; set; }
public DbSet<ImageOnlyChannel> ImageOnlyChannels { get; set; }
public DbSet<AutoTranslateChannel> AutoTranslateChannels { get; set; }
public DbSet<AutoTranslateUser> AutoTranslateUsers { get; set; }
public DbSet<Permissionv2> Permissions { get; set; }
public DbSet<BankUser> BankUsers { get; set; }
public DbSet<ReactionRoleV2> ReactionRoles { get; set; }
public DbSet<PatronUser> Patrons { get; set; }
public DbSet<PatronQuota> PatronQuotas { get; set; }
public DbSet<StreamOnlineMessage> StreamOnlineMessages { get; set; }
public DbSet<StickyRole> StickyRoles { get; set; }
public DbSet<TodoModel> Todos { get; set; }
public DbSet<ArchivedTodoListModel> TodosArchive { get; set; }
// todo add guild colors
// public DbSet<GuildColors> 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<Quote>();
quoteEntity.HasIndex(x => x.GuildId);
quoteEntity.HasIndex(x => x.Keyword);
#endregion
#region GuildConfig
var configEntity = modelBuilder.Entity<GuildConfig>();
configEntity.HasIndex(c => c.GuildId)
.IsUnique();
configEntity.Property(x => x.VerboseErrors)
.HasDefaultValue(true);
modelBuilder.Entity<AntiSpamSetting>().HasOne(x => x.GuildConfig).WithOne(x => x.AntiSpamSetting);
modelBuilder.Entity<AntiRaidSetting>().HasOne(x => x.GuildConfig).WithOne(x => x.AntiRaidSetting);
modelBuilder.Entity<GuildConfig>()
.HasOne(x => x.AntiAltSetting)
.WithOne()
.HasForeignKey<AntiAltSetting>(x => x.GuildConfigId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<FeedSub>()
.HasAlternateKey(x => new
{
x.GuildConfigId,
x.Url
});
modelBuilder.Entity<PlantedCurrency>().HasIndex(x => x.MessageId).IsUnique();
modelBuilder.Entity<PlantedCurrency>().HasIndex(x => x.ChannelId);
configEntity.HasIndex(x => x.WarnExpireHours).IsUnique(false);
#endregion
#region streamrole
modelBuilder.Entity<StreamRoleSettings>().HasOne(x => x.GuildConfig).WithOne(x => x.StreamRole);
#endregion
#region Self Assignable Roles
var selfassignableRolesEntity = modelBuilder.Entity<SelfAssignedRole>();
selfassignableRolesEntity.HasIndex(s => new
{
s.GuildId,
s.RoleId
})
.IsUnique();
selfassignableRolesEntity.Property(x => x.Group).HasDefaultValue(0);
#endregion
#region MusicPlaylists
var musicPlaylistEntity = modelBuilder.Entity<MusicPlaylist>();
musicPlaylistEntity.HasMany(p => p.Songs).WithOne().OnDelete(DeleteBehavior.Cascade);
#endregion
#region Waifus
var wi = modelBuilder.Entity<WaifuInfo>();
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<DiscordUser>(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<Warning>(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<UserXpStats>();
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 XpSettings
modelBuilder.Entity<XpSettings>().HasOne(x => x.GuildConfig).WithOne(x => x.XpSettings);
#endregion
#region XpRoleReward
modelBuilder.Entity<XpRoleReward>()
.HasIndex(x => new
{
x.XpSettingsId,
x.Level
})
.IsUnique();
#endregion
#region Club
var ci = modelBuilder.Entity<ClubInfo>();
ci.HasOne(x => x.Owner)
.WithOne()
.HasForeignKey<ClubInfo>(x => x.OwnerId)
.OnDelete(DeleteBehavior.SetNull);
ci.HasIndex(x => new
{
x.Name
})
.IsUnique();
#endregion
#region ClubManytoMany
modelBuilder.Entity<ClubApplicants>()
.HasKey(t => new
{
t.ClubId,
t.UserId
});
modelBuilder.Entity<ClubApplicants>()
.HasOne(pt => pt.User)
.WithMany();
modelBuilder.Entity<ClubApplicants>()
.HasOne(pt => pt.Club)
.WithMany(x => x.Applicants);
modelBuilder.Entity<ClubBans>()
.HasKey(t => new
{
t.ClubId,
t.UserId
});
modelBuilder.Entity<ClubBans>()
.HasOne(pt => pt.User)
.WithMany();
modelBuilder.Entity<ClubBans>()
.HasOne(pt => pt.Club)
.WithMany(x => x.Bans);
#endregion
#region CurrencyTransactions
modelBuilder.Entity<CurrencyTransaction>(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<Reminder>().HasIndex(x => x.When);
#endregion
#region GroupName
modelBuilder.Entity<GroupName>()
.HasIndex(x => new
{
x.GuildConfigId,
x.Number
})
.IsUnique();
modelBuilder.Entity<GroupName>()
.HasOne(x => x.GuildConfig)
.WithMany(x => x.SelfAssignableRoleGroupNames)
.IsRequired();
#endregion
#region BanTemplate
modelBuilder.Entity<BanTemplate>().HasIndex(x => x.GuildId).IsUnique();
modelBuilder.Entity<BanTemplate>()
.Property(x => x.PruneDays)
.HasDefaultValue(null)
.IsRequired(false);
#endregion
#region Perm Override
modelBuilder.Entity<DiscordPermOverride>()
.HasIndex(x => new
{
x.GuildId,
x.Command
})
.IsUnique();
#endregion
#region Music
modelBuilder.Entity<MusicPlayerSettings>().HasIndex(x => x.GuildId).IsUnique();
modelBuilder.Entity<MusicPlayerSettings>().Property(x => x.Volume).HasDefaultValue(100);
#endregion
#region Reaction roles
modelBuilder.Entity<ReactionRoleV2>(rr2 =>
{
rr2.HasIndex(x => x.GuildId)
.IsUnique(false);
rr2.HasIndex(x => new
{
x.MessageId,
x.Emote
})
.IsUnique();
});
#endregion
#region LogSettings
modelBuilder.Entity<LogSetting>(ls => ls.HasIndex(x => x.GuildId).IsUnique());
modelBuilder.Entity<LogSetting>(ls => ls
.HasMany(x => x.LogIgnores)
.WithOne(x => x.LogSetting)
.OnDelete(DeleteBehavior.Cascade));
modelBuilder.Entity<IgnoredLogItem>(ili => ili
.HasIndex(x => new
{
x.LogSettingId,
x.LogItemId,
x.ItemType
})
.IsUnique());
#endregion
modelBuilder.Entity<ImageOnlyChannel>(ioc => ioc.HasIndex(x => x.ChannelId).IsUnique());
var atch = modelBuilder.Entity<AutoTranslateChannel>();
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<AutoTranslateUser>(atu => atu.HasAlternateKey(x => new
{
x.ChannelId,
x.UserId
}));
#region BANK
modelBuilder.Entity<BankUser>(bu => bu.HasIndex(x => x.UserId).IsUnique());
#endregion
#region Patron
// currency rewards
var pr = modelBuilder.Entity<RewardedUser>();
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<PatronUser>(pu =>
{
pu.HasIndex(x => x.UniquePlatformUserId).IsUnique();
pu.HasKey(x => x.UserId);
});
// quotes are per user id
modelBuilder.Entity<PatronQuota>(pq =>
{
pq.HasIndex(x => x.UserId).IsUnique(false);
pq.HasKey(x => new
{
x.UserId,
x.FeatureType,
x.Feature
});
});
#endregion
#region Xp Item Shop
modelBuilder.Entity<XpShopOwnedItem>(
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<AutoPublishChannel>(apc => apc
.HasIndex(x => x.GuildId)
.IsUnique());
#endregion
#region GamblingStats
modelBuilder.Entity<GamblingStats>(gs => gs
.HasIndex(x => x.Feature)
.IsUnique());
#endregion
#region Sticky Roles
modelBuilder.Entity<StickyRole>(sr => sr.HasIndex(x => new
{
x.GuildId,
x.UserId
}).IsUnique());
#endregion
#region Giveaway
modelBuilder.Entity<GiveawayModel>()
.HasMany(x => x.Participants)
.WithOne()
.HasForeignKey(x => x.GiveawayId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<GiveawayUser>(gu => gu
.HasIndex(x => new
{
x.GiveawayId,
x.UserId
})
.IsUnique());
#endregion
#region Todo
modelBuilder.Entity<TodoModel>()
.HasKey(x => x.Id);
modelBuilder.Entity<TodoModel>()
.HasIndex(x => x.UserId)
.IsUnique(false);
modelBuilder.Entity<ArchivedTodoListModel>()
.HasMany(x => x.Items)
.WithOne()
.HasForeignKey(x => x.ArchiveId)
.OnDelete(DeleteBehavior.Cascade);
#endregion
}
#if DEBUG
private static readonly ILoggerFactory _debugLoggerFactory = LoggerFactory.Create(x => x.AddConsole());
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseLoggerFactory(_debugLoggerFactory);
#endif
}

View file

@ -0,0 +1,76 @@
using LinqToDB.Common;
using LinqToDB.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace EllieBot.Db;
public sealed class EllieDbService : DbService
{
private readonly IBotCredsProvider _creds;
// these are props because creds can change at runtime
private string DbType => _creds.GetCreds().Db.Type.ToLowerInvariant().Trim();
private string ConnString => _creds.GetCreds().Db.ConnectionString;
public EllieDbService(IBotCredsProvider creds)
{
LinqToDBForEFTools.Initialize();
Configuration.Linq.DisableQueryCache = true;
_creds = creds;
}
public override async Task SetupAsync()
{
var dbType = DbType;
var connString = ConnString;
await using var context = CreateRawDbContext(dbType, connString);
// make sure sqlite db is in wal journal mode
if (context is SqliteContext)
{
await context.Database.ExecuteSqlRawAsync("PRAGMA journal_mode=WAL");
}
await context.Database.MigrateAsync();
}
public override EllieContext CreateRawDbContext(string dbType, string connString)
{
switch (dbType)
{
case "postgresql":
case "postgres":
case "pgsql":
return new PostgreSqlContext(connString);
case "mysql":
return new MysqlContext(connString);
case "sqlite":
return new SqliteContext(connString);
default:
throw new NotSupportedException($"The database provide type of '{dbType}' is not supported.");
}
}
private EllieContext GetDbContextInternal()
{
var dbType = DbType;
var connString = ConnString;
var context = CreateRawDbContext(dbType, connString);
if (context is SqliteContext)
{
var conn = context.Database.GetDbConnection();
conn.Open();
using var com = conn.CreateCommand();
com.CommandText = "PRAGMA synchronous=OFF";
com.ExecuteNonQuery();
}
return context;
}
public override EllieContext GetDbContext()
=> GetDbContextInternal();
}

View file

@ -0,0 +1,34 @@
#nullable disable
using Microsoft.EntityFrameworkCore;
using EllieBot.Db.Models;
namespace EllieBot.Db;
public static class ClubExtensions
{
private static IQueryable<ClubInfo> Include(this DbSet<ClubInfo> clubs)
=> clubs.Include(x => x.Owner)
.Include(x => x.Applicants)
.ThenInclude(x => x.User)
.Include(x => x.Bans)
.ThenInclude(x => x.User)
.Include(x => x.Members)
.AsQueryable();
public static ClubInfo GetByOwner(this DbSet<ClubInfo> clubs, ulong userId)
=> Include(clubs).FirstOrDefault(c => c.Owner.UserId == userId);
public static ClubInfo GetByOwnerOrAdmin(this DbSet<ClubInfo> clubs, ulong userId)
=> Include(clubs)
.FirstOrDefault(c => c.Owner.UserId == userId || c.Members.Any(u => u.UserId == userId && u.IsClubAdmin));
public static ClubInfo GetByMember(this DbSet<ClubInfo> clubs, ulong userId)
=> Include(clubs).FirstOrDefault(c => c.Members.Any(u => u.UserId == userId));
public static ClubInfo GetByName(this DbSet<ClubInfo> clubs, string name)
=> Include(clubs)
.FirstOrDefault(c => c.Name == name);
public static List<ClubInfo> GetClubLeaderboardPage(this DbSet<ClubInfo> clubs, int page)
=> clubs.AsNoTracking().OrderByDescending(x => x.Xp).Skip(page * 9).Take(9).ToList();
}

View file

@ -0,0 +1,20 @@
#nullable disable
using LinqToDB.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using EllieBot.Db.Models;
namespace EllieBot.Db;
public static class CurrencyTransactionExtensions
{
public static Task<List<CurrencyTransaction>> GetPageFor(
this DbSet<CurrencyTransaction> set,
ulong userId,
int page)
=> set.ToLinqToDBTable()
.Where(x => x.UserId == userId)
.OrderByDescending(x => x.DateAdded)
.Skip(15 * page)
.Take(15)
.ToListAsyncLinqToDB();
}

View file

@ -0,0 +1,12 @@
#nullable disable
using Microsoft.EntityFrameworkCore;
using EllieBot.Db.Models;
namespace EllieBot.Db;
public static class DbExtensions
{
public static T GetById<T>(this DbSet<T> set, int id)
where T : DbEntity
=> set.FirstOrDefault(x => x.Id == id);
}

View file

@ -0,0 +1,125 @@
#nullable disable
using LinqToDB;
using LinqToDB.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using EllieBot.Db.Models;
namespace EllieBot.Db;
public static class DiscordUserExtensions
{
public static Task<DiscordUser> GetByUserIdAsync(
this IQueryable<DiscordUser> set,
ulong userId)
=> set.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId);
public static void EnsureUserCreated(
this DbContext ctx,
ulong userId,
string username,
string discrim,
string avatarId)
=> ctx.GetTable<DiscordUser>()
.InsertOrUpdate(
() => new()
{
UserId = userId,
Username = username,
Discriminator = discrim,
AvatarId = avatarId,
TotalXp = 0,
CurrencyAmount = 0
},
old => new()
{
Username = username,
Discriminator = discrim,
AvatarId = avatarId
},
() => new()
{
UserId = userId
});
public static Task EnsureUserCreatedAsync(
this DbContext ctx,
ulong userId)
=> ctx.GetTable<DiscordUser>()
.InsertOrUpdateAsync(
() => new()
{
UserId = userId,
Username = "Unknown",
Discriminator = "????",
AvatarId = string.Empty,
TotalXp = 0,
CurrencyAmount = 0
},
old => new()
{
},
() => new()
{
UserId = userId
});
//temp is only used in updatecurrencystate, so that i don't overwrite real usernames/discrims with Unknown
public static DiscordUser GetOrCreateUser(
this DbContext ctx,
ulong userId,
string username,
string discrim,
string avatarId,
Func<IQueryable<DiscordUser>, IQueryable<DiscordUser>> includes = null)
{
ctx.EnsureUserCreated(userId, username, discrim, avatarId);
IQueryable<DiscordUser> queryable = ctx.Set<DiscordUser>();
if (includes is not null)
queryable = includes(queryable);
return queryable.First(u => u.UserId == userId);
}
public static int GetUserGlobalRank(this DbSet<DiscordUser> users, ulong id)
=> users.AsQueryable()
.Where(x => x.TotalXp
> users.AsQueryable().Where(y => y.UserId == id).Select(y => y.TotalXp).FirstOrDefault())
.Count()
+ 1;
public static DiscordUser[] GetUsersXpLeaderboardFor(this DbSet<DiscordUser> users, int page, int perPage)
=> users.AsQueryable().OrderByDescending(x => x.TotalXp).Skip(page * perPage).Take(perPage).AsEnumerable()
.ToArray();
public static Task<List<DiscordUser>> GetTopRichest(
this DbSet<DiscordUser> users,
ulong botId,
int page = 0, int perPage = 9)
=> users.AsQueryable()
.Where(c => c.CurrencyAmount > 0 && botId != c.UserId)
.OrderByDescending(c => c.CurrencyAmount)
.Skip(page * perPage)
.Take(perPage)
.ToListAsyncLinqToDB();
public static async Task<long> GetUserCurrencyAsync(this DbSet<DiscordUser> users, ulong userId)
=> (await users.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId))?.CurrencyAmount ?? 0;
public static void RemoveFromMany(this DbSet<DiscordUser> users, IEnumerable<ulong> ids)
{
var items = users.AsQueryable().Where(x => ids.Contains(x.UserId));
foreach (var item in items)
item.CurrencyAmount = 0;
}
public static decimal GetTotalCurrency(this DbSet<DiscordUser> users)
=> users.Sum((Func<DiscordUser, decimal>)(x => x.CurrencyAmount));
public static decimal GetTopOnePercentCurrency(this DbSet<DiscordUser> users, ulong botId)
=> users.AsQueryable()
.Where(x => x.UserId != botId)
.OrderByDescending(x => x.CurrencyAmount)
.Take(users.Count() / 100 == 0 ? 1 : users.Count() / 100)
.Sum(x => x.CurrencyAmount);
}

View file

@ -0,0 +1,15 @@
#nullable disable
using LinqToDB;
using Microsoft.EntityFrameworkCore;
using EllieBot.Db.Models;
namespace EllieBot.Db;
public static class EllieExpressionExtensions
{
public static int ClearFromGuild(this DbSet<EllieExpression> exprs, ulong guildId)
=> exprs.Delete(x => x.GuildId == guildId);
public static IEnumerable<EllieExpression> ForId(this DbSet<EllieExpression> exprs, ulong id)
=> exprs.AsNoTracking().AsQueryable().Where(x => x.GuildId == id).ToList();
}

View file

@ -0,0 +1,227 @@
#nullable disable
using Microsoft.EntityFrameworkCore;
using EllieBot.Db.Models;
namespace EllieBot.Db;
public static class GuildConfigExtensions
{
private static List<WarningPunishment> DefaultWarnPunishments
=> new()
{
new()
{
Count = 3,
Punishment = PunishmentAction.Kick
},
new()
{
Count = 5,
Punishment = PunishmentAction.Ban
}
};
/// <summary>
/// Gets full stream role settings for the guild with the specified id.
/// </summary>
/// <param name="ctx">Db Context</param>
/// <param name="guildId">Id of the guild to get stream role settings for.</param>
/// <returns>Guild'p stream role settings</returns>
public static StreamRoleSettings GetStreamRoleSettings(this DbContext ctx, ulong guildId)
{
var conf = ctx.GuildConfigsForId(guildId,
set => set.Include(y => y.StreamRole)
.Include(y => y.StreamRole.Whitelist)
.Include(y => y.StreamRole.Blacklist));
if (conf.StreamRole is null)
conf.StreamRole = new();
return conf.StreamRole;
}
private static IQueryable<GuildConfig> IncludeEverything(this DbSet<GuildConfig> configs)
=> configs.AsQueryable()
.AsSplitQuery()
.Include(gc => gc.CommandCooldowns)
.Include(gc => gc.FollowedStreams)
.Include(gc => gc.StreamRole)
.Include(gc => gc.XpSettings)
.ThenInclude(x => x.ExclusionList)
.Include(gc => gc.DelMsgOnCmdChannels);
public static IEnumerable<GuildConfig> GetAllGuildConfigs(
this DbSet<GuildConfig> configs,
IReadOnlyList<ulong> availableGuilds)
=> configs.IncludeEverything().AsNoTracking().Where(x => availableGuilds.Contains(x.GuildId)).ToList();
/// <summary>
/// Gets and creates if it doesn't exist a config for a guild.
/// </summary>
/// <param name="ctx">Context</param>
/// <param name="guildId">Id of the guide</param>
/// <param name="includes">Use to manipulate the set however you want. Pass null to include everything</param>
/// <returns>Config for the guild</returns>
public static GuildConfig GuildConfigsForId(
this DbContext ctx,
ulong guildId,
Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes)
{
GuildConfig config;
if (includes is null)
config = ctx.Set<GuildConfig>().IncludeEverything().FirstOrDefault(c => c.GuildId == guildId);
else
{
var set = includes(ctx.Set<GuildConfig>());
config = set.FirstOrDefault(c => c.GuildId == guildId);
}
if (config is null)
{
ctx.Set<GuildConfig>().Add(config = new()
{
GuildId = guildId,
Permissions = Permissionv2.GetDefaultPermlist,
WarningsInitialized = true,
WarnPunishments = DefaultWarnPunishments
});
ctx.SaveChanges();
}
if (!config.WarningsInitialized)
{
config.WarningsInitialized = true;
config.WarnPunishments = DefaultWarnPunishments;
}
return config;
// ctx.GuildConfigs
// .ToLinqToDBTable()
// .InsertOrUpdate(() => new()
// {
// GuildId = guildId,
// Permissions = Permissionv2.GetDefaultPermlist,
// WarningsInitialized = true,
// WarnPunishments = DefaultWarnPunishments
// },
// _ => new(),
// () => new()
// {
// GuildId = guildId
// });
//
// if(includes is null)
// return ctx.GuildConfigs
// .ToLinqToDBTable()
// .First(x => x.GuildId == guildId);
}
public static LogSetting LogSettingsFor(this DbContext ctx, ulong guildId)
{
var logSetting = ctx.Set<LogSetting>()
.AsQueryable()
.Include(x => x.LogIgnores)
.Where(x => x.GuildId == guildId)
.FirstOrDefault();
if (logSetting is null)
{
ctx.Set<LogSetting>()
.Add(logSetting = new()
{
GuildId = guildId
});
ctx.SaveChanges();
}
return logSetting;
}
public static IEnumerable<GuildConfig> PermissionsForAll(this DbSet<GuildConfig> configs, List<ulong> include)
{
var query = configs.AsQueryable().Where(x => include.Contains(x.GuildId)).Include(gc => gc.Permissions);
return query.ToList();
}
public static GuildConfig GcWithPermissionsFor(this DbContext ctx, ulong guildId)
{
var config = ctx.Set<GuildConfig>().AsQueryable()
.Where(gc => gc.GuildId == guildId)
.Include(gc => gc.Permissions)
.FirstOrDefault();
if (config is null) // if there is no guildconfig, create new one
{
ctx.Set<GuildConfig>().Add(config = new()
{
GuildId = guildId,
Permissions = Permissionv2.GetDefaultPermlist
});
ctx.SaveChanges();
}
else if (config.Permissions is null || !config.Permissions.Any()) // if no perms, add default ones
{
config.Permissions = Permissionv2.GetDefaultPermlist;
ctx.SaveChanges();
}
return config;
}
public static IEnumerable<FollowedStream> GetFollowedStreams(this DbSet<GuildConfig> configs)
=> configs.AsQueryable().Include(x => x.FollowedStreams).SelectMany(gc => gc.FollowedStreams).ToArray();
public static IEnumerable<FollowedStream> GetFollowedStreams(this DbSet<GuildConfig> configs, List<ulong> included)
=> configs.AsQueryable()
.Where(gc => included.Contains(gc.GuildId))
.Include(gc => gc.FollowedStreams)
.SelectMany(gc => gc.FollowedStreams)
.ToList();
public static void SetCleverbotEnabled(this DbSet<GuildConfig> configs, ulong id, bool cleverbotEnabled)
{
var conf = configs.FirstOrDefault(gc => gc.GuildId == id);
if (conf is null)
return;
conf.CleverbotEnabled = cleverbotEnabled;
}
public static XpSettings XpSettingsFor(this DbContext ctx, ulong guildId)
{
var gc = ctx.GuildConfigsForId(guildId,
set => set.Include(x => x.XpSettings)
.ThenInclude(x => x.RoleRewards)
.Include(x => x.XpSettings)
.ThenInclude(x => x.CurrencyRewards)
.Include(x => x.XpSettings)
.ThenInclude(x => x.ExclusionList));
if (gc.XpSettings is null)
gc.XpSettings = new();
return gc.XpSettings;
}
public static IEnumerable<GeneratingChannel> GetGeneratingChannels(this DbSet<GuildConfig> configs)
=> configs.AsQueryable()
.Include(x => x.GenerateCurrencyChannelIds)
.Where(x => x.GenerateCurrencyChannelIds.Any())
.SelectMany(x => x.GenerateCurrencyChannelIds)
.Select(x => new GeneratingChannel
{
ChannelId = x.ChannelId,
GuildId = x.GuildConfig.GuildId
})
.ToArray();
public class GeneratingChannel
{
public ulong GuildId { get; set; }
public ulong ChannelId { get; set; }
}
}

View file

@ -0,0 +1,53 @@
#nullable disable
using Microsoft.EntityFrameworkCore;
using EllieBot.Db.Models;
namespace EllieBot.Db;
public static class QuoteExtensions
{
public static IEnumerable<Quote> GetForGuild(this DbSet<Quote> quotes, ulong guildId)
=> quotes.AsQueryable().Where(x => x.GuildId == guildId);
public static IReadOnlyCollection<Quote> GetGroup(
this DbSet<Quote> quotes,
ulong guildId,
int page,
OrderType order)
{
var q = quotes.AsQueryable().Where(x => x.GuildId == guildId);
if (order == OrderType.Keyword)
q = q.OrderBy(x => x.Keyword);
else
q = q.OrderBy(x => x.Id);
return q.Skip(15 * page).Take(15).ToArray();
}
public static async Task<Quote> GetRandomQuoteByKeywordAsync(
this DbSet<Quote> quotes,
ulong guildId,
string keyword)
{
return (await quotes.AsQueryable().Where(q => q.GuildId == guildId && q.Keyword == keyword).ToArrayAsync())
.RandomOrDefault();
}
public static async Task<Quote> SearchQuoteKeywordTextAsync(
this DbSet<Quote> quotes,
ulong guildId,
string keyword,
string text)
{
return (await quotes.AsQueryable()
.Where(q => q.GuildId == guildId
&& (keyword == null || q.Keyword == keyword)
&& (EF.Functions.Like(q.Text.ToUpper(), $"%{text.ToUpper()}%")
|| EF.Functions.Like(q.AuthorName, text)))
.ToArrayAsync())
.RandomOrDefault();
}
public static void RemoveAllByKeyword(this DbSet<Quote> quotes, ulong guildId, string keyword)
=> quotes.RemoveRange(quotes.AsQueryable().Where(x => x.GuildId == guildId && x.Keyword.ToUpper() == keyword));
}

View file

@ -0,0 +1,23 @@
#nullable disable
using Microsoft.EntityFrameworkCore;
using EllieBot.Db.Models;
namespace EllieBot.Db;
public static class ReminderExtensions
{
public static IEnumerable<Reminder> GetIncludedReminders(
this DbSet<Reminder> reminders,
IEnumerable<ulong> guildIds)
=> reminders.AsQueryable().Where(x => guildIds.Contains(x.ServerId) || x.ServerId == 0).ToList();
public static IEnumerable<Reminder> RemindersFor(this DbSet<Reminder> reminders, ulong userId, int page)
=> reminders.AsQueryable().Where(x => x.UserId == userId).OrderBy(x => x.DateAdded).Skip(page * 10).Take(10);
public static IEnumerable<Reminder> RemindersForServer(this DbSet<Reminder> reminders, ulong serverId, int page)
=> reminders.AsQueryable()
.Where(x => x.ServerId == serverId)
.OrderBy(x => x.DateAdded)
.Skip(page * 10)
.Take(10);
}

View file

@ -0,0 +1,22 @@
#nullable disable
using Microsoft.EntityFrameworkCore;
using EllieBot.Db.Models;
namespace EllieBot.Db;
public static class SelfAssignableRolesExtensions
{
public static bool DeleteByGuildAndRoleId(this DbSet<SelfAssignedRole> roles, ulong guildId, ulong roleId)
{
var role = roles.FirstOrDefault(s => s.GuildId == guildId && s.RoleId == roleId);
if (role is null)
return false;
roles.Remove(role);
return true;
}
public static IReadOnlyCollection<SelfAssignedRole> GetFromGuild(this DbSet<SelfAssignedRole> roles, ulong guildId)
=> roles.AsQueryable().Where(s => s.GuildId == guildId).ToArray();
}

View file

@ -0,0 +1,71 @@
#nullable disable
using LinqToDB;
using LinqToDB.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using EllieBot.Db.Models;
namespace EllieBot.Db;
public static class UserXpExtensions
{
public static UserXpStats GetOrCreateUserXpStats(this DbContext ctx, ulong guildId, ulong userId)
{
var usr = ctx.Set<UserXpStats>().FirstOrDefault(x => x.UserId == userId && x.GuildId == guildId);
if (usr is null)
{
ctx.Add(usr = new()
{
Xp = 0,
UserId = userId,
NotifyOnLevelUp = XpNotificationLocation.None,
GuildId = guildId
});
}
return usr;
}
public static List<UserXpStats> GetUsersFor(this DbSet<UserXpStats> xps, ulong guildId, int page)
=> xps.AsQueryable()
.AsNoTracking()
.Where(x => x.GuildId == guildId)
.OrderByDescending(x => x.Xp + x.AwardedXp)
.Skip(page * 9)
.Take(9)
.ToList();
public static List<UserXpStats> GetTopUserXps(this DbSet<UserXpStats> xps, ulong guildId, int count)
=> xps.AsQueryable()
.AsNoTracking()
.Where(x => x.GuildId == guildId)
.OrderByDescending(x => x.Xp + x.AwardedXp)
.Take(count)
.ToList();
public static int GetUserGuildRanking(this DbSet<UserXpStats> xps, ulong userId, ulong guildId)
=> xps.AsQueryable()
.AsNoTracking()
.Where(x => x.GuildId == guildId
&& x.Xp + x.AwardedXp
> xps.AsQueryable()
.Where(y => y.UserId == userId && y.GuildId == guildId)
.Select(y => y.Xp + y.AwardedXp)
.FirstOrDefault())
.Count()
+ 1;
public static void ResetGuildUserXp(this DbSet<UserXpStats> xps, ulong userId, ulong guildId)
=> xps.Delete(x => x.UserId == userId && x.GuildId == guildId);
public static void ResetGuildXp(this DbSet<UserXpStats> xps, ulong guildId)
=> xps.Delete(x => x.GuildId == guildId);
public static async Task<LevelStats> GetLevelDataFor(this ITable<UserXpStats> userXp, ulong guildId, ulong userId)
=> await userXp
.Where(x => x.GuildId == guildId && x.UserId == userId)
.FirstOrDefaultAsyncLinqToDB() is UserXpStats uxs
? new(uxs.Xp + uxs.AwardedXp)
: new(0);
}

View file

@ -0,0 +1,60 @@
#nullable disable
using Microsoft.EntityFrameworkCore;
using EllieBot.Db.Models;
namespace EllieBot.Db;
public static class WarningExtensions
{
public static Warning[] ForId(this DbSet<Warning> warnings, ulong guildId, ulong userId)
{
var query = warnings.AsQueryable()
.Where(x => x.GuildId == guildId && x.UserId == userId)
.OrderByDescending(x => x.DateAdded);
return query.ToArray();
}
public static bool Forgive(
this DbSet<Warning> warnings,
ulong guildId,
ulong userId,
string mod,
int index)
{
if (index < 0)
throw new ArgumentOutOfRangeException(nameof(index));
var warn = warnings.AsQueryable()
.Where(x => x.GuildId == guildId && x.UserId == userId)
.OrderByDescending(x => x.DateAdded)
.Skip(index)
.FirstOrDefault();
if (warn is null || warn.Forgiven)
return false;
warn.Forgiven = true;
warn.ForgivenBy = mod;
return true;
}
public static async Task ForgiveAll(
this DbSet<Warning> warnings,
ulong guildId,
ulong userId,
string mod)
=> await warnings.AsQueryable()
.Where(x => x.GuildId == guildId && x.UserId == userId)
.ForEachAsync(x =>
{
if (x.Forgiven != true)
{
x.Forgiven = true;
x.ForgivenBy = mod;
}
});
public static Warning[] GetForGuild(this DbSet<Warning> warnings, ulong id)
=> warnings.AsQueryable().Where(x => x.GuildId == id).ToArray();
}

View file

@ -0,0 +1,22 @@
namespace EllieBot.Db;
public enum DbActivityType
{
/// <summary>The user is playing a game.</summary>
Playing,
/// <summary>The user is streaming online.</summary>
Streaming,
/// <summary>The user is listening to a song.</summary>
Listening,
/// <summary>The user is watching some form of media.</summary>
Watching,
/// <summary>The user has set a custom status.</summary>
CustomStatus,
/// <summary>The user is competing in a game.</summary>
Competing,
}

View file

@ -0,0 +1,47 @@
namespace EllieBot.Db;
[Flags]
public enum GuildPerm : ulong
{
CreateInstantInvite = 1,
KickMembers = 2,
BanMembers = 4,
Administrator = 8,
ManageChannels = 16, // 0x0000000000000010
ManageGuild = 32, // 0x0000000000000020
ViewGuildInsights = 524288, // 0x0000000000080000
AddReactions = 64, // 0x0000000000000040
ViewAuditLog = 128, // 0x0000000000000080
ViewChannel = 1024, // 0x0000000000000400
SendMessages = 2048, // 0x0000000000000800
SendTTSMessages = 4096, // 0x0000000000001000
ManageMessages = 8192, // 0x0000000000002000
EmbedLinks = 16384, // 0x0000000000004000
AttachFiles = 32768, // 0x0000000000008000
ReadMessageHistory = 65536, // 0x0000000000010000
MentionEveryone = 131072, // 0x0000000000020000
UseExternalEmojis = 262144, // 0x0000000000040000
Connect = 1048576, // 0x0000000000100000
Speak = 2097152, // 0x0000000000200000
MuteMembers = 4194304, // 0x0000000000400000
DeafenMembers = 8388608, // 0x0000000000800000
MoveMembers = 16777216, // 0x0000000001000000
UseVAD = 33554432, // 0x0000000002000000
PrioritySpeaker = 256, // 0x0000000000000100
Stream = 512, // 0x0000000000000200
ChangeNickname = 67108864, // 0x0000000004000000
ManageNicknames = 134217728, // 0x0000000008000000
ManageRoles = 268435456, // 0x0000000010000000
ManageWebhooks = 536870912, // 0x0000000020000000
ManageEmojisAndStickers = 1073741824, // 0x0000000040000000
UseApplicationCommands = 2147483648, // 0x0000000080000000
RequestToSpeak = 4294967296, // 0x0000000100000000
ManageEvents = 8589934592, // 0x0000000200000000
ManageThreads = 17179869184, // 0x0000000400000000
CreatePublicThreads = 34359738368, // 0x0000000800000000
CreatePrivateThreads = 68719476736, // 0x0000001000000000
UseExternalStickers = 137438953472, // 0x0000002000000000
SendMessagesInThreads = 274877906944, // 0x0000004000000000
StartEmbeddedActivities = 549755813888, // 0x0000008000000000
ModerateMembers = 1099511627776, // 0x0000010000000000
}

View file

@ -0,0 +1,40 @@
#nullable disable
namespace EllieBot.Db;
public readonly struct LevelStats
{
public const int XP_REQUIRED_LVL_1 = 36;
public long Level { get; }
public long LevelXp { get; }
public long RequiredXp { get; }
public long TotalXp { get; }
public LevelStats(long xp)
{
if (xp < 0)
xp = 0;
TotalXp = xp;
const int baseXp = XP_REQUIRED_LVL_1;
var required = baseXp;
var totalXp = 0;
var lvl = 1;
while (true)
{
required = (int)(baseXp + (baseXp / 4.0 * (lvl - 1)));
if (required + totalXp > xp)
break;
totalXp += required;
lvl++;
}
Level = lvl - 1;
LevelXp = xp - totalXp;
RequiredXp = required;
}
}

View file

@ -0,0 +1,14 @@
#nullable disable
namespace EllieBot.Db.Models;
public class AutoCommand : DbEntity
{
public string CommandText { get; set; }
public ulong ChannelId { get; set; }
public string ChannelName { get; set; }
public ulong? GuildId { get; set; }
public string GuildName { get; set; }
public ulong? VoiceChannelId { get; set; }
public string VoiceChannelName { get; set; }
public int Interval { get; set; }
}

View file

@ -0,0 +1,7 @@
namespace EllieBot.Db.Models;
public class AutoPublishChannel : DbEntity
{
public ulong GuildId { get; set; }
public ulong ChannelId { get; set; }
}

View file

@ -0,0 +1,10 @@
#nullable disable
namespace EllieBot.Db.Models;
public class AutoTranslateChannel : DbEntity
{
public ulong GuildId { get; set; }
public ulong ChannelId { get; set; }
public bool AutoDelete { get; set; }
public IList<AutoTranslateUser> Users { get; set; } = new List<AutoTranslateUser>();
}

View file

@ -0,0 +1,11 @@
#nullable disable
namespace EllieBot.Db.Models;
public class AutoTranslateUser : DbEntity
{
public int ChannelId { get; set; }
public AutoTranslateChannel Channel { get; set; }
public ulong UserId { get; set; }
public string Source { get; set; }
public string Target { get; set; }
}

View file

@ -0,0 +1,15 @@
#nullable disable
namespace EllieBot.Db.Models;
public class BlacklistEntry : DbEntity
{
public ulong ItemId { get; set; }
public BlacklistType Type { get; set; }
}
public enum BlacklistType
{
Server,
Channel,
User
}

View file

@ -0,0 +1,8 @@
#nullable disable
namespace EllieBot.Db.Models;
public class CommandAlias : DbEntity
{
public string Trigger { get; set; }
public string Mapping { get; set; }
}

View file

@ -0,0 +1,8 @@
#nullable disable
namespace EllieBot.Db.Models;
public class CommandCooldown : DbEntity
{
public int Seconds { get; set; }
public string CommandName { get; set; }
}

View file

@ -0,0 +1,12 @@
#nullable disable
namespace EllieBot.Db.Models;
public class CurrencyTransaction : DbEntity
{
public long Amount { get; set; }
public string Note { get; set; }
public ulong UserId { get; set; }
public string Type { get; set; }
public string Extra { get; set; }
public ulong? OtherId { get; set; }
}

View file

@ -0,0 +1,12 @@
#nullable disable
using System.ComponentModel.DataAnnotations;
namespace EllieBot.Db.Models;
public class DbEntity
{
[Key]
public int Id { get; set; }
public DateTime? DateAdded { get; set; } = DateTime.UtcNow;
}

View file

@ -0,0 +1,14 @@
#nullable disable
namespace EllieBot.Db.Models;
public class DelMsgOnCmdChannel : DbEntity
{
public ulong ChannelId { get; set; }
public bool State { get; set; }
public override int GetHashCode()
=> ChannelId.GetHashCode();
public override bool Equals(object obj)
=> obj is DelMsgOnCmdChannel x && x.ChannelId == ChannelId;
}

View file

@ -0,0 +1,10 @@
#nullable disable
namespace EllieBot.Db.Models;
public class DiscordPermOverride : DbEntity
{
public GuildPerm Perm { get; set; }
public ulong? GuildId { get; set; }
public string Command { get; set; }
}

View file

@ -0,0 +1,35 @@
#nullable disable
namespace EllieBot.Db.Models;
// FUTURE remove LastLevelUp from here and UserXpStats
public class DiscordUser : DbEntity
{
public ulong UserId { get; set; }
public string Username { get; set; }
public string Discriminator { get; set; }
public string AvatarId { get; set; }
public int? ClubId { get; set; }
public ClubInfo Club { get; set; }
public bool IsClubAdmin { get; set; }
public long TotalXp { get; set; }
public XpNotificationLocation NotifyOnLevelUp { get; set; }
public long CurrencyAmount { get; set; }
public override bool Equals(object obj)
=> obj is DiscordUser du ? du.UserId == UserId : false;
public override int GetHashCode()
=> UserId.GetHashCode();
public override string ToString()
{
if (string.IsNullOrWhiteSpace(Discriminator) || Discriminator == "0000")
return Username;
return Username + "#" + Discriminator;
}
}

View file

@ -0,0 +1,49 @@
#nullable disable
namespace EllieBot.Db.Models;
public class CurrencyEvent
{
public enum Type
{
Reaction,
GameStatus
//NotRaid,
}
public ulong ServerId { get; set; }
public ulong ChannelId { get; set; }
public ulong MessageId { get; set; }
public Type EventType { get; set; }
/// <summary>
/// Amount of currency that the user will be rewarded.
/// </summary>
public long Amount { get; set; }
/// <summary>
/// Maximum amount of currency that can be handed out.
/// </summary>
public long PotSize { get; set; }
public List<AwardedUser> AwardedUsers { get; set; }
/// <summary>
/// Used as extra data storage for events which need it.
/// </summary>
public ulong ExtraId { get; set; }
/// <summary>
/// May be used for some future event.
/// </summary>
public ulong ExtraId2 { get; set; }
/// <summary>
/// May be used for some future event.
/// </summary>
public string ExtraString { get; set; }
}
public class AwardedUser
{
}

View file

@ -0,0 +1,19 @@
#nullable disable
namespace EllieBot.Db.Models;
public class FeedSub : DbEntity
{
public int GuildConfigId { get; set; }
public GuildConfig GuildConfig { get; set; }
public ulong ChannelId { get; set; }
public string Url { get; set; }
public string Message { get; set; }
public override int GetHashCode()
=> Url.GetHashCode(StringComparison.InvariantCulture) ^ GuildConfigId.GetHashCode();
public override bool Equals(object obj)
=> obj is FeedSub s && s.Url.ToLower() == Url.ToLower() && s.GuildConfigId == GuildConfigId;
}

View file

@ -0,0 +1,33 @@
#nullable disable
namespace EllieBot.Db.Models;
public class FollowedStream : DbEntity
{
public enum FType
{
Twitch = 0,
Picarto = 3,
Youtube = 4,
Facebook = 5,
Trovo = 6
}
public ulong GuildId { get; set; }
public ulong ChannelId { get; set; }
public string Username { get; set; }
public FType Type { get; set; }
public string Message { get; set; }
protected bool Equals(FollowedStream other)
=> ChannelId == other.ChannelId
&& Username.Trim().ToUpperInvariant() == other.Username.Trim().ToUpperInvariant()
&& Type == other.Type;
public override int GetHashCode()
=> HashCode.Combine(ChannelId, Username, (int)Type);
public override bool Equals(object obj)
=> obj is FollowedStream fs && Equals(fs);
}

View file

@ -0,0 +1,14 @@
#nullable disable
namespace EllieBot.Db.Models;
public class GCChannelId : DbEntity
{
public GuildConfig GuildConfig { get; set; }
public ulong ChannelId { get; set; }
public override bool Equals(object obj)
=> obj is GCChannelId gc && gc.ChannelId == ChannelId;
public override int GetHashCode()
=> ChannelId.GetHashCode();
}

View file

@ -0,0 +1,9 @@
#nullable disable
namespace EllieBot.Db.Models;
public class GamblingStats : DbEntity
{
public string Feature { get; set; }
public decimal Bet { get; set; }
public decimal PaidOut { get; set; }
}

View file

@ -0,0 +1,11 @@
#nullable disable
namespace EllieBot.Db.Models;
public class GroupName : DbEntity
{
public int GuildConfigId { get; set; }
public GuildConfig GuildConfig { get; set; }
public int Number { get; set; }
public string Name { get; set; }
}

View file

@ -0,0 +1,18 @@
using System.ComponentModel.DataAnnotations;
namespace EllieBot.Db.Models;
public class GuildColors
{
[Key]
public ulong GuildId { get; set; }
[Length(0, 9)]
public string? OkColor { get; set; }
[Length(0, 9)]
public string? ErrorColor { get; set; }
[Length(0, 9)]
public string? PendingColor { get; set; }
}

View file

@ -0,0 +1,107 @@
#nullable disable
namespace EllieBot.Db.Models;
public class GuildConfig : DbEntity
{
public ulong GuildId { get; set; }
public string Prefix { get; set; }
public bool DeleteMessageOnCommand { get; set; }
public HashSet<DelMsgOnCmdChannel> DelMsgOnCmdChannels { get; set; } = new();
public string AutoAssignRoleIds { get; set; }
//greet stuff
public int AutoDeleteGreetMessagesTimer { get; set; } = 30;
public int AutoDeleteByeMessagesTimer { get; set; } = 30;
public ulong GreetMessageChannelId { get; set; }
public ulong ByeMessageChannelId { get; set; }
public bool SendDmGreetMessage { get; set; }
public string DmGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!";
public bool SendChannelGreetMessage { get; set; }
public string ChannelGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!";
public bool SendChannelByeMessage { get; set; }
public string ChannelByeMessageText { get; set; } = "%user% has left!";
//self assignable roles
public bool ExclusiveSelfAssignedRoles { get; set; }
public bool AutoDeleteSelfAssignedRoleMessages { get; set; }
//stream notifications
public HashSet<FollowedStream> FollowedStreams { get; set; } = new();
//currencyGeneration
public HashSet<GCChannelId> GenerateCurrencyChannelIds { get; set; } = new();
public List<Permissionv2> Permissions { get; set; }
public bool VerbosePermissions { get; set; } = true;
public string PermissionRole { get; set; }
public HashSet<CommandCooldown> CommandCooldowns { get; set; } = new();
//filtering
public bool FilterInvites { get; set; }
public bool FilterLinks { get; set; }
public HashSet<FilterChannelId> FilterInvitesChannelIds { get; set; } = new();
public HashSet<FilterLinksChannelId> FilterLinksChannelIds { get; set; } = new();
//public bool FilterLinks { get; set; }
//public HashSet<FilterLinksChannelId> FilterLinksChannels { get; set; } = new HashSet<FilterLinksChannelId>();
public bool FilterWords { get; set; }
public HashSet<FilteredWord> FilteredWords { get; set; } = new();
public HashSet<FilterWordsChannelId> FilterWordsChannelIds { get; set; } = new();
public HashSet<MutedUserId> MutedUsers { get; set; } = new();
public string MuteRoleName { get; set; }
public bool CleverbotEnabled { get; set; }
public AntiRaidSetting AntiRaidSetting { get; set; }
public AntiSpamSetting AntiSpamSetting { get; set; }
public AntiAltSetting AntiAltSetting { get; set; }
public string Locale { get; set; }
public string TimeZoneId { get; set; }
public HashSet<UnmuteTimer> UnmuteTimers { get; set; } = new();
public HashSet<UnbanTimer> UnbanTimer { get; set; } = new();
public HashSet<UnroleTimer> UnroleTimer { get; set; } = new();
public HashSet<VcRoleInfo> VcRoleInfos { get; set; }
public HashSet<CommandAlias> CommandAliases { get; set; } = new();
public List<WarningPunishment> WarnPunishments { get; set; } = new();
public bool WarningsInitialized { get; set; }
public HashSet<SlowmodeIgnoredUser> SlowmodeIgnoredUsers { get; set; }
public HashSet<SlowmodeIgnoredRole> SlowmodeIgnoredRoles { get; set; }
public List<ShopEntry> ShopEntries { get; set; }
public ulong? GameVoiceChannel { get; set; }
public bool VerboseErrors { get; set; } = true;
public StreamRoleSettings StreamRole { get; set; }
public XpSettings XpSettings { get; set; }
public List<FeedSub> FeedSubs { get; set; } = new();
public bool NotifyStreamOffline { get; set; }
public bool DeleteStreamOnlineMessage { get; set; }
public List<GroupName> SelfAssignableRoleGroupNames { get; set; }
public int WarnExpireHours { get; set; }
public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear;
public bool DisableGlobalExpressions { get; set; } = false;
#region Boost Message
public bool SendBoostMessage { get; set; }
public string BoostMessage { get; set; } = "%user% just boosted this server!";
public ulong BoostMessageChannelId { get; set; }
public int BoostMessageDeleteAfter { get; set; }
public bool StickyRoles { get; set; }
#endregion
}

View file

@ -0,0 +1,16 @@
#nullable disable
namespace EllieBot.Db.Models;
public class IgnoredLogItem : DbEntity
{
public int LogSettingId { get; set; }
public LogSetting LogSetting { get; set; }
public ulong LogItemId { get; set; }
public IgnoredItemType ItemType { get; set; }
}
public enum IgnoredItemType
{
Channel,
User
}

View file

@ -0,0 +1,8 @@
#nullable disable
namespace EllieBot.Db.Models;
public class IgnoredVoicePresenceChannel : DbEntity
{
public LogSetting LogSetting { get; set; }
public ulong ChannelId { get; set; }
}

View file

@ -0,0 +1,15 @@
#nullable disable
namespace EllieBot.Db.Models;
public class ImageOnlyChannel : DbEntity
{
public ulong GuildId { get; set; }
public ulong ChannelId { get; set; }
public OnlyChannelType Type { get; set; }
}
public enum OnlyChannelType
{
Image,
Link
}

View file

@ -0,0 +1,38 @@
#nullable disable
namespace EllieBot.Db.Models;
public class LogSetting : DbEntity
{
public List<IgnoredLogItem> LogIgnores { get; set; } = new();
public ulong GuildId { get; set; }
public ulong? LogOtherId { get; set; }
public ulong? MessageUpdatedId { get; set; }
public ulong? MessageDeletedId { get; set; }
public ulong? UserJoinedId { get; set; }
public ulong? UserLeftId { get; set; }
public ulong? UserBannedId { get; set; }
public ulong? UserUnbannedId { get; set; }
public ulong? UserUpdatedId { get; set; }
public ulong? ChannelCreatedId { get; set; }
public ulong? ChannelDestroyedId { get; set; }
public ulong? ChannelUpdatedId { get; set; }
public ulong? ThreadDeletedId { get; set; }
public ulong? ThreadCreatedId { get; set; }
public ulong? UserMutedId { get; set; }
//userpresence
public ulong? LogUserPresenceId { get; set; }
//voicepresence
public ulong? LogVoicePresenceId { get; set; }
public ulong? LogVoicePresenceTTSId { get; set; }
public ulong? LogWarnsId { get; set; }
}

View file

@ -0,0 +1,55 @@
#nullable disable
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics;
namespace EllieBot.Db.Models;
[DebuggerDisplay("{PrimaryTarget}{SecondaryTarget} {SecondaryTargetName} {State} {PrimaryTargetId}")]
public class Permissionv2 : DbEntity, IIndexed
{
public int? GuildConfigId { get; set; }
public int Index { get; set; }
public PrimaryPermissionType PrimaryTarget { get; set; }
public ulong PrimaryTargetId { get; set; }
public SecondaryPermissionType SecondaryTarget { get; set; }
public string SecondaryTargetName { get; set; }
public bool IsCustomCommand { get; set; }
public bool State { get; set; }
[NotMapped]
public static Permissionv2 AllowAllPerm
=> new()
{
PrimaryTarget = PrimaryPermissionType.Server,
PrimaryTargetId = 0,
SecondaryTarget = SecondaryPermissionType.AllModules,
SecondaryTargetName = "*",
State = true,
Index = 0
};
public static List<Permissionv2> GetDefaultPermlist
=> new()
{
AllowAllPerm
};
}
public enum PrimaryPermissionType
{
User,
Channel,
Role,
Server
}
public enum SecondaryPermissionType
{
Module,
Command,
AllModules
}

View file

@ -0,0 +1,12 @@
#nullable disable
namespace EllieBot.Db.Models;
public class PlantedCurrency : DbEntity
{
public long Amount { get; set; }
public string Password { get; set; }
public ulong GuildId { get; set; }
public ulong ChannelId { get; set; }
public ulong UserId { get; set; }
public ulong MessageId { get; set; }
}

View file

@ -0,0 +1,18 @@
#nullable disable
namespace EllieBot.Db.Models;
public class PlaylistSong : DbEntity
{
public string Provider { get; set; }
public MusicType ProviderType { get; set; }
public string Title { get; set; }
public string Uri { get; set; }
public string Query { get; set; }
}
public enum MusicType
{
Radio,
YouTube,
Local,
}

View file

@ -0,0 +1,19 @@
#nullable disable
namespace EllieBot.Db.Models;
public class Reminder : DbEntity
{
public DateTime When { get; set; }
public ulong ChannelId { get; set; }
public ulong ServerId { get; set; }
public ulong UserId { get; set; }
public string Message { get; set; }
public bool IsPrivate { get; set; }
public ReminderType Type { get; set; }
}
public enum ReminderType
{
User,
Timely
}

View file

@ -0,0 +1,15 @@
#nullable disable
namespace EllieBot.Db.Models;
public class Repeater
{
public int Id { get; set; }
public ulong GuildId { get; set; }
public ulong ChannelId { get; set; }
public ulong? LastMessageId { get; set; }
public string Message { get; set; }
public TimeSpan Interval { get; set; }
public TimeSpan? StartTimeOfDay { get; set; }
public bool NoRedundant { get; set; }
public DateTime DateAdded { get; set; }
}

View file

@ -0,0 +1,8 @@
#nullable disable
namespace EllieBot.Db.Models;
public class RotatingPlayingStatus : DbEntity
{
public string Status { get; set; }
public DbActivityType Type { get; set; }
}

View file

@ -0,0 +1,46 @@
#nullable disable
namespace EllieBot.Db.Models;
public enum ShopEntryType
{
Role,
List,
Command
}
public class ShopEntry : DbEntity, IIndexed
{
public int Index { get; set; }
public int Price { get; set; }
public string Name { get; set; }
public ulong AuthorId { get; set; }
public ShopEntryType Type { get; set; }
//role
public string RoleName { get; set; }
public ulong RoleId { get; set; }
//list
public HashSet<ShopEntryItem> Items { get; set; } = new();
public ulong? RoleRequirement { get; set; }
// command
public string Command { get; set; }
}
public class ShopEntryItem : DbEntity
{
public string Text { get; set; }
public override bool Equals(object obj)
{
if (obj is null || GetType() != obj.GetType())
return false;
return ((ShopEntryItem)obj).Text == Text;
}
public override int GetHashCode()
=> Text.GetHashCode(StringComparison.InvariantCulture);
}

View file

@ -0,0 +1,11 @@
#nullable disable
namespace EllieBot.Db.Models;
public class StreamOnlineMessage : DbEntity
{
public ulong ChannelId { get; set; }
public ulong MessageId { get; set; }
public FollowedStream.FType Type { get; set; }
public string Name { get; set; }
}

View file

@ -0,0 +1,68 @@
#nullable disable
namespace EllieBot.Db.Models;
public class StreamRoleSettings : DbEntity
{
public int GuildConfigId { get; set; }
public GuildConfig GuildConfig { get; set; }
/// <summary>
/// Whether the feature is enabled in the guild.
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// Id of the role to give to the users in the role 'FromRole' when they start streaming
/// </summary>
public ulong AddRoleId { get; set; }
/// <summary>
/// Id of the role whose users are eligible to get the 'AddRole'
/// </summary>
public ulong FromRoleId { get; set; }
/// <summary>
/// If set, feature will only apply to users who have this keyword in their streaming status.
/// </summary>
public string Keyword { get; set; }
/// <summary>
/// A collection of whitelisted users' IDs. Whitelisted users don't require 'keyword' in
/// order to get the stream role.
/// </summary>
public HashSet<StreamRoleWhitelistedUser> Whitelist { get; set; } = new();
/// <summary>
/// A collection of blacklisted users' IDs. Blacklisted useres will never get the stream role.
/// </summary>
public HashSet<StreamRoleBlacklistedUser> Blacklist { get; set; } = new();
}
public class StreamRoleBlacklistedUser : DbEntity
{
public ulong UserId { get; set; }
public string Username { get; set; }
public override bool Equals(object obj)
{
if (obj is not StreamRoleBlacklistedUser x)
return false;
return x.UserId == UserId;
}
public override int GetHashCode()
=> UserId.GetHashCode();
}
public class StreamRoleWhitelistedUser : DbEntity
{
public ulong UserId { get; set; }
public string Username { get; set; }
public override bool Equals(object obj)
=> obj is StreamRoleWhitelistedUser x ? x.UserId == UserId : false;
public override int GetHashCode()
=> UserId.GetHashCode();
}

View file

@ -0,0 +1,8 @@
#nullable disable
namespace EllieBot.Db.Models;
public class VcRoleInfo : DbEntity
{
public ulong VoiceChannelId { get; set; }
public ulong RoleId { get; set; }
}

View file

@ -0,0 +1,75 @@
#nullable disable
using EllieBot.Db.Models;
namespace EllieBot.Services.Database.Models;
public class WaifuInfo : DbEntity
{
public int WaifuId { get; set; }
public DiscordUser Waifu { get; set; }
public int? ClaimerId { get; set; }
public DiscordUser Claimer { get; set; }
public int? AffinityId { get; set; }
public DiscordUser Affinity { get; set; }
public long Price { get; set; }
public List<WaifuItem> Items { get; set; } = new();
public override string ToString()
{
var status = string.Empty;
var waifuUsername = Waifu.ToString().TrimTo(20);
var claimer = Claimer?.ToString().TrimTo(20)
?? "no one";
var affinity = Affinity?.ToString().TrimTo(20);
if (AffinityId is null)
status = $"... but {waifuUsername}'s heart is empty";
else if (AffinityId == ClaimerId)
status = $"... and {waifuUsername} likes {claimer} too <3";
else
{
status =
$"... but {waifuUsername}'s heart belongs to {affinity}";
}
return $"**{waifuUsername}** - claimed by **{claimer}**\n\t{status}";
}
}
public class WaifuLbResult
{
public string Username { get; set; }
public string Discrim { get; set; }
public string Claimer { get; set; }
public string ClaimerDiscrim { get; set; }
public string Affinity { get; set; }
public string AffinityDiscrim { get; set; }
public long Price { get; set; }
public override string ToString()
{
var claimer = "no one";
var status = string.Empty;
var waifuUsername = Username.TrimTo(20);
var claimerUsername = Claimer?.TrimTo(20);
if (Claimer is not null)
claimer = $"{claimerUsername}#{ClaimerDiscrim}";
if (Affinity is null)
status = $"... but {waifuUsername}'s heart is empty";
else if (Affinity + AffinityDiscrim == Claimer + ClaimerDiscrim)
status = $"... and {waifuUsername} likes {claimerUsername} too <3";
else
status = $"... but {waifuUsername}'s heart belongs to {Affinity.TrimTo(20)}#{AffinityDiscrim}";
return $"**{waifuUsername}#{Discrim}** - claimed by **{claimer}**\n\t{status}";
}
}

View file

@ -0,0 +1,11 @@
namespace EllieBot.Db.Models;
public class AntiAltSetting
{
public int Id { get; set; }
public int GuildConfigId { get; set; }
public TimeSpan MinAge { get; set; }
public PunishmentAction Action { get; set; }
public int ActionDurationMinutes { get; set; }
public ulong? RoleId { get; set; }
}

View file

@ -0,0 +1,19 @@
#nullable disable
namespace EllieBot.Db.Models;
public class AntiRaidSetting : DbEntity
{
public int GuildConfigId { get; set; }
public GuildConfig GuildConfig { get; set; }
public int UserThreshold { get; set; }
public int Seconds { get; set; }
public PunishmentAction Action { get; set; }
/// <summary>
/// Duration of the punishment, in minutes. This works only for supported Actions, like:
/// Mute, Chatmute, Voicemute, etc...
/// </summary>
public int PunishDuration { get; set; }
}

View file

@ -0,0 +1,12 @@
namespace EllieBot.Db.Models;
public class AntiSpamIgnore : DbEntity
{
public ulong ChannelId { get; set; }
public override int GetHashCode()
=> ChannelId.GetHashCode();
public override bool Equals(object? obj)
=> obj is AntiSpamIgnore inst && inst.ChannelId == ChannelId;
}

View file

@ -0,0 +1,14 @@
namespace EllieBot.Db.Models;
#nullable disable
public class AntiSpamSetting : DbEntity
{
public int GuildConfigId { get; set; }
public GuildConfig GuildConfig { get; set; }
public PunishmentAction Action { get; set; }
public int MessageThreshold { get; set; } = 3;
public int MuteTime { get; set; }
public ulong? RoleId { get; set; }
public HashSet<AntiSpamIgnore> IgnoredChannels { get; set; } = new();
}

View file

@ -0,0 +1,41 @@
#nullable disable
using System.ComponentModel.DataAnnotations;
namespace EllieBot.Db.Models;
public class ClubInfo : DbEntity
{
[MaxLength(20)]
public string Name { get; set; }
public string Description { get; set; }
public string ImageUrl { get; set; } = string.Empty;
public int Xp { get; set; } = 0;
public int? OwnerId { get; set; }
public DiscordUser Owner { get; set; }
public List<DiscordUser> Members { get; set; } = new();
public List<ClubApplicants> Applicants { get; set; } = new();
public List<ClubBans> Bans { get; set; } = new();
public override string ToString()
=> Name;
}
public class ClubApplicants
{
public int ClubId { get; set; }
public ClubInfo Club { get; set; }
public int UserId { get; set; }
public DiscordUser User { get; set; }
}
public class ClubBans
{
public int ClubId { get; set; }
public ClubInfo Club { get; set; }
public int UserId { get; set; }
public DiscordUser User { get; set; }
}

View file

@ -0,0 +1,7 @@
namespace EllieBot.Db.Models;
public class BankUser : DbEntity
{
public ulong UserId { get; set; }
public long Balance { get; set; }
}

View file

@ -0,0 +1,27 @@
#nullable disable
namespace EllieBot.Db.Models;
public class EllieExpression : DbEntity
{
public ulong? GuildId { get; set; }
public string Response { get; set; }
public string Trigger { get; set; }
public bool AutoDeleteTrigger { get; set; }
public bool DmResponse { get; set; }
public bool ContainsAnywhere { get; set; }
public bool AllowTarget { get; set; }
public string Reactions { get; set; }
public string[] GetReactions()
=> string.IsNullOrWhiteSpace(Reactions) ? Array.Empty<string>() : Reactions.Split("@@@");
public bool IsGlobal()
=> GuildId is null or 0;
}
public class ReactionResponse : DbEntity
{
public bool OwnerOnly { get; set; }
public string Text { get; set; }
}

View file

@ -0,0 +1,26 @@
#nullable disable
using System.ComponentModel.DataAnnotations;
namespace EllieBot.Db.Models;
public class Quote : DbEntity
{
public ulong GuildId { get; set; }
[Required]
public string Keyword { get; set; }
[Required]
public string AuthorName { get; set; }
public ulong AuthorId { get; set; }
[Required]
public string Text { get; set; }
}
public enum OrderType
{
Id = -1,
Keyword = -2
}

View file

@ -0,0 +1,30 @@
#nullable disable
namespace EllieBot.Db.Models;
public class FilterChannelId : DbEntity
{
public ulong ChannelId { get; set; }
public bool Equals(FilterChannelId other)
=> ChannelId == other.ChannelId;
public override bool Equals(object obj)
=> obj is FilterChannelId fci && Equals(fci);
public override int GetHashCode()
=> ChannelId.GetHashCode();
}
public class FilterWordsChannelId : DbEntity
{
public ulong ChannelId { get; set; }
public bool Equals(FilterWordsChannelId other)
=> ChannelId == other.ChannelId;
public override bool Equals(object obj)
=> obj is FilterWordsChannelId fci && Equals(fci);
public override int GetHashCode()
=> ChannelId.GetHashCode();
}

View file

@ -0,0 +1,13 @@
#nullable disable
namespace EllieBot.Db.Models;
public class FilterLinksChannelId : DbEntity
{
public ulong ChannelId { get; set; }
public override bool Equals(object obj)
=> obj is FilterLinksChannelId f && f.ChannelId == ChannelId;
public override int GetHashCode()
=> ChannelId.GetHashCode();
}

View file

@ -0,0 +1,7 @@
#nullable disable
namespace EllieBot.Db.Models;
public class FilteredWord : DbEntity
{
public string Word { get; set; }
}

View file

@ -0,0 +1,14 @@
namespace EllieBot.Db.Models;
#nullable disable
public sealed class GiveawayModel
{
public int Id { get; set; }
public ulong GuildId { get; set; }
public ulong MessageId { get; set; }
public ulong ChannelId { get; set; }
public string Message { get; set; }
public IList<GiveawayUser> Participants { get; set; } = new List<GiveawayUser>();
public DateTime EndsAt { get; set; }
}

View file

@ -0,0 +1,10 @@
namespace EllieBot.Db.Models;
#nullable disable
public sealed class GiveawayUser
{
public int Id { get; set; }
public int GiveawayId { get; set; }
public ulong UserId { get; set; }
public string Name { get; set; }
}

View file

@ -0,0 +1,9 @@
#nullable disable
namespace EllieBot.Db.Models;
public class BanTemplate : DbEntity
{
public ulong GuildId { get; set; }
public string Text { get; set; }
public int? PruneDays { get; set; }
}

View file

@ -0,0 +1,13 @@
#nullable disable
namespace EllieBot.Db.Models;
public class MutedUserId : DbEntity
{
public ulong UserId { get; set; }
public override int GetHashCode()
=> UserId.GetHashCode();
public override bool Equals(object obj)
=> obj is MutedUserId mui ? mui.UserId == UserId : false;
}

View file

@ -0,0 +1,15 @@
namespace EllieBot.Db.Models;
public enum PunishmentAction
{
Mute,
Kick,
Ban,
Softban,
RemoveRoles,
ChatMute,
VoiceMute,
AddRole,
Warn,
TimeOut
}

View file

@ -0,0 +1,8 @@
#nullable disable
namespace EllieBot.Db.Models;
public enum WarnExpireAction
{
Clear,
Delete
}

View file

@ -0,0 +1,13 @@
#nullable disable
namespace EllieBot.Db.Models;
public class Warning : DbEntity
{
public ulong GuildId { get; set; }
public ulong UserId { get; set; }
public string Reason { get; set; }
public bool Forgiven { get; set; }
public string ForgivenBy { get; set; }
public string Moderator { get; set; }
public long Weight { get; set; }
}

View file

@ -0,0 +1,10 @@
#nullable disable
namespace EllieBot.Db.Models;
public class WarningPunishment : DbEntity
{
public int Count { get; set; }
public PunishmentAction Punishment { get; set; }
public int Time { get; set; }
public ulong? RoleId { get; set; }
}

View file

@ -0,0 +1,18 @@
#nullable disable
using System.ComponentModel.DataAnnotations;
namespace EllieBot.Db.Models;
public class ReactionRoleV2 : DbEntity
{
public ulong GuildId { get; set; }
public ulong ChannelId { get; set; }
public ulong MessageId { get; set; }
[MaxLength(100)]
public string Emote { get; set; }
public ulong RoleId { get; set; }
public int Group { get; set; }
public int LevelReq { get; set; }
}

View file

@ -0,0 +1,11 @@
#nullable disable
namespace EllieBot.Db.Models;
public class SelfAssignedRole : DbEntity
{
public ulong GuildId { get; set; }
public ulong RoleId { get; set; }
public int Group { get; set; }
public int LevelRequirement { get; set; }
}

View file

@ -0,0 +1,14 @@
namespace EllieBot.Db.Models;
#nullable disable
public class StickyRole : DbEntity
{
public ulong GuildId { get; set; }
public string RoleIds { get; set; }
public ulong UserId { get; set; }
public ulong[] GetRoleIds()
=> string.IsNullOrWhiteSpace(RoleIds)
? []
: RoleIds.Split(',').Select(ulong.Parse).ToArray();
}

View file

@ -0,0 +1,20 @@
#nullable disable
namespace EllieBot.Db.Models;
public class SlowmodeIgnoredRole : DbEntity
{
public ulong RoleId { get; set; }
// override object.Equals
public override bool Equals(object obj)
{
if (obj is null || GetType() != obj.GetType())
return false;
return ((SlowmodeIgnoredRole)obj).RoleId == RoleId;
}
// override object.GetHashCode
public override int GetHashCode()
=> RoleId.GetHashCode();
}

View file

@ -0,0 +1,20 @@
#nullable disable
namespace EllieBot.Db.Models;
public class SlowmodeIgnoredUser : DbEntity
{
public ulong UserId { get; set; }
// override object.Equals
public override bool Equals(object obj)
{
if (obj is null || GetType() != obj.GetType())
return false;
return ((SlowmodeIgnoredUser)obj).UserId == UserId;
}
// override object.GetHashCode
public override int GetHashCode()
=> UserId.GetHashCode();
}

View file

@ -0,0 +1,48 @@
#nullable disable
namespace EllieBot.Db.Models;
/// <summary>
/// Contains data about usage of Patron-Only commands per user
/// in order to provide support for quota limitations
/// (allow user x who is pledging amount y to use the specified command only
/// x amount of times in the specified time period)
/// </summary>
public class PatronQuota
{
public ulong UserId { get; set; }
public FeatureType FeatureType { get; set; }
public string Feature { get; set; }
public uint HourlyCount { get; set; }
public uint DailyCount { get; set; }
public uint MonthlyCount { get; set; }
}
public enum FeatureType
{
Command,
Group,
Module,
Limit
}
public class PatronUser
{
public string UniquePlatformUserId { get; set; }
public ulong UserId { get; set; }
public int AmountCents { get; set; }
public DateTime LastCharge { get; set; }
// Date Only component
public DateTime ValidThru { get; set; }
public PatronUser Clone()
=> new PatronUser()
{
UniquePlatformUserId = this.UniquePlatformUserId,
UserId = this.UserId,
AmountCents = this.AmountCents,
LastCharge = this.LastCharge,
ValidThru = this.ValidThru
};
}

View file

@ -0,0 +1,10 @@
#nullable disable
namespace EllieBot.Db.Models;
public class RewardedUser : DbEntity
{
public ulong UserId { get; set; }
public string PlatformUserId { get; set; }
public long AmountRewardedThisMonth { get; set; }
public DateTime LastReward { get; set; }
}

View file

@ -0,0 +1,10 @@
namespace EllieBot.Db.Models;
#nullable disable
public sealed class ArchivedTodoListModel
{
public int Id { get; set; }
public ulong UserId { get; set; }
public string Name { get; set; }
public List<TodoModel> Items { get; set; }
}

View file

@ -0,0 +1,13 @@
namespace EllieBot.Db.Models;
#nullable disable
public sealed class TodoModel
{
public int Id { get; set; }
public ulong UserId { get; set; }
public string Todo { get; set; }
public DateTime DateAdded { get; set; }
public bool IsDone { get; set; }
public int? ArchiveId { get; set; }
}

View file

@ -0,0 +1,14 @@
#nullable disable
namespace EllieBot.Db.Models;
public class UnbanTimer : DbEntity
{
public ulong UserId { get; set; }
public DateTime UnbanAt { get; set; }
public override int GetHashCode()
=> UserId.GetHashCode();
public override bool Equals(object obj)
=> obj is UnbanTimer ut ? ut.UserId == UserId : false;
}

View file

@ -0,0 +1,14 @@
#nullable disable
namespace EllieBot.Db.Models;
public class UnmuteTimer : DbEntity
{
public ulong UserId { get; set; }
public DateTime UnmuteAt { get; set; }
public override int GetHashCode()
=> UserId.GetHashCode();
public override bool Equals(object obj)
=> obj is UnmuteTimer ut ? ut.UserId == UserId : false;
}

View file

@ -0,0 +1,15 @@
#nullable disable
namespace EllieBot.Db.Models;
public class UnroleTimer : DbEntity
{
public ulong UserId { get; set; }
public ulong RoleId { get; set; }
public DateTime UnbanAt { get; set; }
public override int GetHashCode()
=> UserId.GetHashCode() ^ RoleId.GetHashCode();
public override bool Equals(object obj)
=> obj is UnroleTimer ut ? ut.UserId == UserId && ut.RoleId == RoleId : false;
}

View file

@ -0,0 +1,13 @@
#nullable disable
namespace EllieBot.Db.Models;
public class UserXpStats : DbEntity
{
public ulong UserId { get; set; }
public ulong GuildId { get; set; }
public long Xp { get; set; }
public long AwardedXp { get; set; }
public XpNotificationLocation NotifyOnLevelUp { get; set; }
}
public enum XpNotificationLocation { None, Dm, Channel }

View file

@ -0,0 +1,62 @@
#nullable disable
namespace EllieBot.Db.Models;
public class XpSettings : DbEntity
{
public int GuildConfigId { get; set; }
public GuildConfig GuildConfig { get; set; }
public HashSet<XpRoleReward> RoleRewards { get; set; } = new();
public HashSet<XpCurrencyReward> CurrencyRewards { get; set; } = new();
public HashSet<ExcludedItem> ExclusionList { get; set; } = new();
public bool ServerExcluded { get; set; }
}
public enum ExcludedItemType { Channel, Role }
public class XpRoleReward : DbEntity
{
public int XpSettingsId { get; set; }
public XpSettings XpSettings { get; set; }
public int Level { get; set; }
public ulong RoleId { get; set; }
/// <summary>
/// Whether the role should be removed (true) or added (false)
/// </summary>
public bool Remove { get; set; }
public override int GetHashCode()
=> Level.GetHashCode() ^ XpSettingsId.GetHashCode();
public override bool Equals(object obj)
=> obj is XpRoleReward xrr && xrr.Level == Level && xrr.XpSettingsId == XpSettingsId;
}
public class XpCurrencyReward : DbEntity
{
public int XpSettingsId { get; set; }
public XpSettings XpSettings { get; set; }
public int Level { get; set; }
public int Amount { get; set; }
public override int GetHashCode()
=> Level.GetHashCode() ^ XpSettingsId.GetHashCode();
public override bool Equals(object obj)
=> obj is XpCurrencyReward xrr && xrr.Level == Level && xrr.XpSettingsId == XpSettingsId;
}
public class ExcludedItem : DbEntity
{
public ulong ItemId { get; set; }
public ExcludedItemType ItemType { get; set; }
public override int GetHashCode()
=> ItemId.GetHashCode() ^ ItemType.GetHashCode();
public override bool Equals(object obj)
=> obj is ExcludedItem ei && ei.ItemId == ItemId && ei.ItemType == ItemType;
}

View file

@ -0,0 +1,38 @@
using Microsoft.EntityFrameworkCore;
using EllieBot.Db.Models;
namespace EllieBot.Db;
public sealed class MysqlContext : EllieContext
{
private readonly string _connStr;
private readonly string _version;
protected override string CurrencyTransactionOtherIdDefaultValue
=> "NULL";
public MysqlContext(string connStr = "Server=localhost", string version = "8.0")
{
_connStr = connStr;
_version = version;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder
.UseLowerCaseNamingConvention()
.UseMySql(_connStr, ServerVersion.Parse(_version));
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// mysql is case insensitive by default
// we can set binary collation to change that
modelBuilder.Entity<ClubInfo>()
.Property(x => x.Name)
.UseCollation("utf8mb4_bin");
}
}

View file

@ -0,0 +1,26 @@
using Microsoft.EntityFrameworkCore;
namespace EllieBot.Db;
public sealed class PostgreSqlContext : EllieContext
{
private readonly string _connStr;
protected override string CurrencyTransactionOtherIdDefaultValue
=> "NULL";
public PostgreSqlContext(string connStr = "Host=localhost")
{
_connStr = connStr;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
base.OnConfiguring(optionsBuilder);
optionsBuilder
.UseLowerCaseNamingConvention()
.UseNpgsql(_connStr);
}
}

View file

@ -0,0 +1,26 @@
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
namespace EllieBot.Db;
public sealed class SqliteContext : EllieContext
{
private readonly string _connectionString;
protected override string CurrencyTransactionOtherIdDefaultValue
=> "NULL";
public SqliteContext(string connectionString = "Data Source=data/EllieBot.db", int commandTimeout = 60)
{
_connectionString = connectionString;
Database.SetCommandTimeout(commandTimeout);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
var builder = new SqliteConnectionStringBuilder(_connectionString);
builder.DataSource = Path.Combine(AppContext.BaseDirectory, builder.DataSource);
optionsBuilder.UseSqlite(builder.ToString());
}
}