mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-04 00:34:26 -05:00 
			
		
		
		
	Restructured folders and project names, ci should be fixed
This commit is contained in:
		
							
								
								
									
										448
									
								
								src/NadekoBot/Services/CommandHandler.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										448
									
								
								src/NadekoBot/Services/CommandHandler.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,448 @@
 | 
			
		||||
using Discord;
 | 
			
		||||
using Discord.Commands;
 | 
			
		||||
using Discord.Net;
 | 
			
		||||
using Discord.WebSocket;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using NadekoBot.Common.Collections;
 | 
			
		||||
using NadekoBot.Common.ModuleBehaviors;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Collections.Immutable;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using NadekoBot.Core.Common.Configs;
 | 
			
		||||
using NadekoBot.Core.Services.Impl;
 | 
			
		||||
using Serilog;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services
 | 
			
		||||
{
 | 
			
		||||
    public class GuildUserComparer : IEqualityComparer<IGuildUser>
 | 
			
		||||
    {
 | 
			
		||||
        public bool Equals(IGuildUser x, IGuildUser y) => x.Id == y.Id;
 | 
			
		||||
 | 
			
		||||
        public int GetHashCode(IGuildUser obj) => obj.Id.GetHashCode();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class CommandHandler : INService
 | 
			
		||||
    {
 | 
			
		||||
        public const int GlobalCommandsCooldown = 750;
 | 
			
		||||
 | 
			
		||||
        private readonly DiscordSocketClient _client;
 | 
			
		||||
        private readonly CommandService _commandService;
 | 
			
		||||
        private readonly BotConfigService _bss;
 | 
			
		||||
        private readonly NadekoBot _bot;
 | 
			
		||||
        private IServiceProvider _services;
 | 
			
		||||
        private IEnumerable<IEarlyBehavior> _earlyBehaviors;
 | 
			
		||||
        private IEnumerable<IInputTransformer> _inputTransformers;
 | 
			
		||||
        private IEnumerable<ILateBlocker> _lateBlockers;
 | 
			
		||||
        private IEnumerable<ILateExecutor> _lateExecutors;
 | 
			
		||||
        
 | 
			
		||||
        private ConcurrentDictionary<ulong, string> _prefixes { get; } = new ConcurrentDictionary<ulong, string>();
 | 
			
		||||
 | 
			
		||||
        public event Func<IUserMessage, CommandInfo, Task> CommandExecuted = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<CommandInfo, ITextChannel, string, Task> CommandErrored = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<IUserMessage, Task> OnMessageNoTrigger = delegate { return Task.CompletedTask; };
 | 
			
		||||
 | 
			
		||||
        //userid/msg count
 | 
			
		||||
        public ConcurrentDictionary<ulong, uint> UserMessagesSent { get; } = new ConcurrentDictionary<ulong, uint>();
 | 
			
		||||
 | 
			
		||||
        public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
 | 
			
		||||
        private readonly Timer _clearUsersOnShortCooldown;
 | 
			
		||||
 | 
			
		||||
        public CommandHandler(DiscordSocketClient client, DbService db, CommandService commandService,
 | 
			
		||||
            BotConfigService bss, NadekoBot bot, IServiceProvider services)
 | 
			
		||||
        {
 | 
			
		||||
            _client = client;
 | 
			
		||||
            _commandService = commandService;
 | 
			
		||||
            _bss = bss;
 | 
			
		||||
            _bot = bot;
 | 
			
		||||
            _db = db;
 | 
			
		||||
            _services = services;
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            _clearUsersOnShortCooldown = new Timer(_ =>
 | 
			
		||||
            {
 | 
			
		||||
                UsersOnShortCooldown.Clear();
 | 
			
		||||
            }, null, GlobalCommandsCooldown, GlobalCommandsCooldown);
 | 
			
		||||
            
 | 
			
		||||
            _prefixes = bot.AllGuildConfigs
 | 
			
		||||
                .Where(x => x.Prefix != null)
 | 
			
		||||
                .ToDictionary(x => x.GuildId, x => x.Prefix)
 | 
			
		||||
                .ToConcurrent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string GetPrefix(IGuild guild) => GetPrefix(guild?.Id);
 | 
			
		||||
 | 
			
		||||
        public string GetPrefix(ulong? id = null)
 | 
			
		||||
        {
 | 
			
		||||
            if (id is null || !_prefixes.TryGetValue(id.Value, out var prefix))
 | 
			
		||||
                return _bss.Data.Prefix;
 | 
			
		||||
 | 
			
		||||
            return prefix;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string SetDefaultPrefix(string prefix)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(prefix))
 | 
			
		||||
                throw new ArgumentNullException(nameof(prefix));
 | 
			
		||||
 | 
			
		||||
            _bss.ModifyConfig(bs =>
 | 
			
		||||
            {
 | 
			
		||||
                bs.Prefix = prefix;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return prefix;
 | 
			
		||||
        }
 | 
			
		||||
        public string SetPrefix(IGuild guild, string prefix)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(prefix))
 | 
			
		||||
                throw new ArgumentNullException(nameof(prefix));
 | 
			
		||||
            if (guild == null)
 | 
			
		||||
                throw new ArgumentNullException(nameof(guild));
 | 
			
		||||
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var gc = uow.GuildConfigs.ForId(guild.Id, set => set);
 | 
			
		||||
                gc.Prefix = prefix;
 | 
			
		||||
                uow.SaveChanges();
 | 
			
		||||
            }
 | 
			
		||||
            _prefixes.AddOrUpdate(guild.Id, prefix, (key, old) => prefix);
 | 
			
		||||
 | 
			
		||||
            return prefix;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public void AddServices(IServiceCollection services)
 | 
			
		||||
        {
 | 
			
		||||
            _lateBlockers = services.Where(x => x.ImplementationType?.GetInterfaces().Contains(typeof(ILateBlocker)) ?? false)
 | 
			
		||||
                .Select(x => _services.GetService(x.ImplementationType) as ILateBlocker)
 | 
			
		||||
                .OrderByDescending(x => x.Priority)
 | 
			
		||||
                .ToArray();
 | 
			
		||||
 | 
			
		||||
            _lateExecutors = services.Where(x => x.ImplementationType?.GetInterfaces().Contains(typeof(ILateExecutor)) ?? false)
 | 
			
		||||
                .Select(x => _services.GetService(x.ImplementationType) as ILateExecutor)
 | 
			
		||||
                .ToArray();
 | 
			
		||||
 | 
			
		||||
            _inputTransformers = services.Where(x => x.ImplementationType?.GetInterfaces().Contains(typeof(IInputTransformer)) ?? false)
 | 
			
		||||
                .Select(x => _services.GetService(x.ImplementationType) as IInputTransformer)
 | 
			
		||||
                .ToArray();
 | 
			
		||||
 | 
			
		||||
            _earlyBehaviors = services.Where(x => x.ImplementationType?.GetInterfaces().Contains(typeof(IEarlyBehavior)) ?? false)
 | 
			
		||||
                .Select(x => _services.GetService(x.ImplementationType) as IEarlyBehavior)
 | 
			
		||||
                .ToArray();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task ExecuteExternal(ulong? guildId, ulong channelId, string commandText)
 | 
			
		||||
        {
 | 
			
		||||
            if (guildId != null)
 | 
			
		||||
            {
 | 
			
		||||
                var guild = _client.GetGuild(guildId.Value);
 | 
			
		||||
                if (!(guild?.GetChannel(channelId) is SocketTextChannel channel))
 | 
			
		||||
                {
 | 
			
		||||
                    Log.Warning("Channel for external execution not found.");
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    IUserMessage msg = await channel.SendMessageAsync(commandText).ConfigureAwait(false);
 | 
			
		||||
                    msg = (IUserMessage)await channel.GetMessageAsync(msg.Id).ConfigureAwait(false);
 | 
			
		||||
                    await TryRunCommand(guild, channel, msg).ConfigureAwait(false);
 | 
			
		||||
                    //msg.DeleteAfter(5);
 | 
			
		||||
                }
 | 
			
		||||
                catch { }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Task StartHandling()
 | 
			
		||||
        {
 | 
			
		||||
            _client.MessageReceived += (msg) => { var _ = Task.Run(() => MessageReceivedHandler(msg)); return Task.CompletedTask; };
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private const float _oneThousandth = 1.0f / 1000;
 | 
			
		||||
        private readonly DbService _db;
 | 
			
		||||
 | 
			
		||||
        private Task LogSuccessfulExecution(IUserMessage usrMsg, ITextChannel channel, params int[] execPoints)
 | 
			
		||||
        {
 | 
			
		||||
            var bss = _services.GetService<BotConfigService>();
 | 
			
		||||
            if (bss.Data.ConsoleOutputType == ConsoleOutputType.Normal)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Information($"Command Executed after " + string.Join("/", execPoints.Select(x => (x * _oneThousandth).ToString("F3"))) + "s\n\t" +
 | 
			
		||||
                        "User: {0}\n\t" +
 | 
			
		||||
                        "Server: {1}\n\t" +
 | 
			
		||||
                        "Channel: {2}\n\t" +
 | 
			
		||||
                        "Message: {3}",
 | 
			
		||||
                        usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
 | 
			
		||||
                        (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
 | 
			
		||||
                        (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
 | 
			
		||||
                        usrMsg.Content // {3}
 | 
			
		||||
                        );
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                Log.Information("Succ | g:{0} | c: {1} | u: {2} | msg: {3}",
 | 
			
		||||
                    channel?.Guild.Id.ToString() ?? "-",
 | 
			
		||||
                    channel?.Id.ToString() ?? "-",
 | 
			
		||||
                    usrMsg.Author.Id,
 | 
			
		||||
                    usrMsg.Content.TrimTo(10));
 | 
			
		||||
            }
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void LogErroredExecution(string errorMessage, IUserMessage usrMsg, ITextChannel channel, params int[] execPoints)
 | 
			
		||||
        {
 | 
			
		||||
            var bss = _services.GetService<BotConfigService>();
 | 
			
		||||
            if (bss.Data.ConsoleOutputType == ConsoleOutputType.Normal)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning($"Command Errored after " + string.Join("/", execPoints.Select(x => (x * _oneThousandth).ToString("F3"))) + "s\n\t" +
 | 
			
		||||
                            "User: {0}\n\t" +
 | 
			
		||||
                            "Server: {1}\n\t" +
 | 
			
		||||
                            "Channel: {2}\n\t" +
 | 
			
		||||
                            "Message: {3}\n\t" +
 | 
			
		||||
                            "Error: {4}",
 | 
			
		||||
                            usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
 | 
			
		||||
                            (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
 | 
			
		||||
                            (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
 | 
			
		||||
                            usrMsg.Content,// {3}
 | 
			
		||||
                            errorMessage
 | 
			
		||||
                            //exec.Result.ErrorReason // {4}
 | 
			
		||||
                            );
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning("Err | g:{0} | c: {1} | u: {2} | msg: {3}\n\tErr: {4}",
 | 
			
		||||
                    channel?.Guild.Id.ToString() ?? "-",
 | 
			
		||||
                    channel?.Id.ToString() ?? "-",
 | 
			
		||||
                    usrMsg.Author.Id,
 | 
			
		||||
                    usrMsg.Content.TrimTo(10),
 | 
			
		||||
                    errorMessage);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task MessageReceivedHandler(SocketMessage msg)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                if (msg.Author.IsBot || !_bot.Ready.Task.IsCompleted) //no bots, wait until bot connected and initialized
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                if (!(msg is SocketUserMessage usrMsg))
 | 
			
		||||
                    return;
 | 
			
		||||
#if !GLOBAL_NADEKO
 | 
			
		||||
                // track how many messagges each user is sending
 | 
			
		||||
                UserMessagesSent.AddOrUpdate(usrMsg.Author.Id, 1, (key, old) => ++old);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
                var channel = msg.Channel as ISocketMessageChannel;
 | 
			
		||||
                var guild = (msg.Channel as SocketTextChannel)?.Guild;
 | 
			
		||||
 | 
			
		||||
                await TryRunCommand(guild, channel, usrMsg).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning(ex, "Error in CommandHandler");
 | 
			
		||||
                if (ex.InnerException != null)
 | 
			
		||||
                {
 | 
			
		||||
                    Log.Warning(ex.InnerException, "Inner Exception of the error in CommandHandler");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task TryRunCommand(SocketGuild guild, ISocketMessageChannel channel, IUserMessage usrMsg)
 | 
			
		||||
        {
 | 
			
		||||
            var execTime = Environment.TickCount;
 | 
			
		||||
 | 
			
		||||
            //its nice to have early blockers and early blocking executors separate, but
 | 
			
		||||
            //i could also have one interface with priorities, and just put early blockers on
 | 
			
		||||
            //highest priority. :thinking:
 | 
			
		||||
            foreach (var beh in _earlyBehaviors)
 | 
			
		||||
            {
 | 
			
		||||
                if (await beh.RunBehavior(_client, guild, usrMsg).ConfigureAwait(false))
 | 
			
		||||
                {
 | 
			
		||||
                    if (beh.BehaviorType == ModuleBehaviorType.Blocker)
 | 
			
		||||
                    {
 | 
			
		||||
                        Log.Information("Blocked User: [{0}] Message: [{1}] Service: [{2}]", usrMsg.Author,
 | 
			
		||||
                            usrMsg.Content, beh.GetType().Name);
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (beh.BehaviorType == ModuleBehaviorType.Executor)
 | 
			
		||||
                    {
 | 
			
		||||
                        Log.Information("User [{0}] executed [{1}] in [{2}]", usrMsg.Author, usrMsg.Content,
 | 
			
		||||
                            beh.GetType().Name);
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var exec2 = Environment.TickCount - execTime;
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            string messageContent = usrMsg.Content;
 | 
			
		||||
            foreach (var exec in _inputTransformers)
 | 
			
		||||
            {
 | 
			
		||||
                string newContent;
 | 
			
		||||
                if ((newContent = await exec.TransformInput(guild, usrMsg.Channel, usrMsg.Author, messageContent)
 | 
			
		||||
                    .ConfigureAwait(false)) != messageContent.ToLowerInvariant())
 | 
			
		||||
                {
 | 
			
		||||
                    messageContent = newContent;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            var prefix = GetPrefix(guild?.Id);
 | 
			
		||||
            var isPrefixCommand = messageContent.StartsWith(".prefix", StringComparison.InvariantCultureIgnoreCase);
 | 
			
		||||
            // execute the command and measure the time it took
 | 
			
		||||
            if (messageContent.StartsWith(prefix, StringComparison.InvariantCulture) || isPrefixCommand)
 | 
			
		||||
            {
 | 
			
		||||
                var (Success, Error, Info) = await ExecuteCommandAsync(new CommandContext(_client, usrMsg), messageContent, isPrefixCommand ? 1 : prefix.Length, _services, MultiMatchHandling.Best).ConfigureAwait(false);
 | 
			
		||||
                execTime = Environment.TickCount - execTime;
 | 
			
		||||
 | 
			
		||||
                if (Success)
 | 
			
		||||
                {
 | 
			
		||||
                    await LogSuccessfulExecution(usrMsg, channel as ITextChannel, exec2, execTime).ConfigureAwait(false);
 | 
			
		||||
                    await CommandExecuted(usrMsg, Info).ConfigureAwait(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                else if (Error != null)
 | 
			
		||||
                {
 | 
			
		||||
                    LogErroredExecution(Error, usrMsg, channel as ITextChannel, exec2, execTime);
 | 
			
		||||
                    if (guild != null)
 | 
			
		||||
                        await CommandErrored(Info, channel as ITextChannel, Error).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await OnMessageNoTrigger(usrMsg).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach (var exec in _lateExecutors)
 | 
			
		||||
            {
 | 
			
		||||
                await exec.LateExecute(_client, guild, usrMsg).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Task<(bool Success, string Error, CommandInfo Info)> ExecuteCommandAsync(CommandContext context, string input, int argPos, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
 | 
			
		||||
            => ExecuteCommand(context, input.Substring(argPos), serviceProvider, multiMatchHandling);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public async Task<(bool Success, string Error, CommandInfo Info)> ExecuteCommand(CommandContext context, string input, IServiceProvider services, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
 | 
			
		||||
        {
 | 
			
		||||
            var searchResult = _commandService.Search(context, input);
 | 
			
		||||
            if (!searchResult.IsSuccess)
 | 
			
		||||
                return (false, null, null);
 | 
			
		||||
 | 
			
		||||
            var commands = searchResult.Commands;
 | 
			
		||||
            var preconditionResults = new Dictionary<CommandMatch, PreconditionResult>();
 | 
			
		||||
 | 
			
		||||
            foreach (var match in commands)
 | 
			
		||||
            {
 | 
			
		||||
                preconditionResults[match] = await match.Command.CheckPreconditionsAsync(context, services).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var successfulPreconditions = preconditionResults
 | 
			
		||||
                .Where(x => x.Value.IsSuccess)
 | 
			
		||||
                .ToArray();
 | 
			
		||||
 | 
			
		||||
            if (successfulPreconditions.Length == 0)
 | 
			
		||||
            {
 | 
			
		||||
                //All preconditions failed, return the one from the highest priority command
 | 
			
		||||
                var bestCandidate = preconditionResults
 | 
			
		||||
                    .OrderByDescending(x => x.Key.Command.Priority)
 | 
			
		||||
                    .FirstOrDefault(x => !x.Value.IsSuccess);
 | 
			
		||||
                return (false, bestCandidate.Value.ErrorReason, commands[0].Command);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var parseResultsDict = new Dictionary<CommandMatch, ParseResult>();
 | 
			
		||||
            foreach (var pair in successfulPreconditions)
 | 
			
		||||
            {
 | 
			
		||||
                var parseResult = await pair.Key.ParseAsync(context, searchResult, pair.Value, services).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                if (parseResult.Error == CommandError.MultipleMatches)
 | 
			
		||||
                {
 | 
			
		||||
                    IReadOnlyList<TypeReaderValue> argList, paramList;
 | 
			
		||||
                    switch (multiMatchHandling)
 | 
			
		||||
                    {
 | 
			
		||||
                        case MultiMatchHandling.Best:
 | 
			
		||||
                            argList = parseResult.ArgValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray();
 | 
			
		||||
                            paramList = parseResult.ParamValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray();
 | 
			
		||||
                            parseResult = ParseResult.FromSuccess(argList, paramList);
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                parseResultsDict[pair.Key] = parseResult;
 | 
			
		||||
            }
 | 
			
		||||
            // Calculates the 'score' of a command given a parse result
 | 
			
		||||
            float CalculateScore(CommandMatch match, ParseResult parseResult)
 | 
			
		||||
            {
 | 
			
		||||
                float argValuesScore = 0, paramValuesScore = 0;
 | 
			
		||||
 | 
			
		||||
                if (match.Command.Parameters.Count > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    var argValuesSum = parseResult.ArgValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0;
 | 
			
		||||
                    var paramValuesSum = parseResult.ParamValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0;
 | 
			
		||||
 | 
			
		||||
                    argValuesScore = argValuesSum / match.Command.Parameters.Count;
 | 
			
		||||
                    paramValuesScore = paramValuesSum / match.Command.Parameters.Count;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var totalArgsScore = (argValuesScore + paramValuesScore) / 2;
 | 
			
		||||
                return match.Command.Priority + totalArgsScore * 0.99f;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Order the parse results by their score so that we choose the most likely result to execute
 | 
			
		||||
            var parseResults = parseResultsDict
 | 
			
		||||
                .OrderByDescending(x => CalculateScore(x.Key, x.Value));
 | 
			
		||||
 | 
			
		||||
            var successfulParses = parseResults
 | 
			
		||||
                .Where(x => x.Value.IsSuccess)
 | 
			
		||||
                .ToArray();
 | 
			
		||||
 | 
			
		||||
            if (successfulParses.Length == 0)
 | 
			
		||||
            {
 | 
			
		||||
                //All parses failed, return the one from the highest priority command, using score as a tie breaker
 | 
			
		||||
                var bestMatch = parseResults
 | 
			
		||||
                    .FirstOrDefault(x => !x.Value.IsSuccess);
 | 
			
		||||
                return (false, bestMatch.Value.ErrorReason, commands[0].Command);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var cmd = successfulParses[0].Key.Command;
 | 
			
		||||
 | 
			
		||||
            // Bot will ignore commands which are ran more often than what specified by
 | 
			
		||||
            // GlobalCommandsCooldown constant (miliseconds)
 | 
			
		||||
            if (!UsersOnShortCooldown.Add(context.Message.Author.Id))
 | 
			
		||||
                return (false, null, cmd);
 | 
			
		||||
            //return SearchResult.FromError(CommandError.Exception, "You are on a global cooldown.");
 | 
			
		||||
 | 
			
		||||
            var commandName = cmd.Aliases.First();
 | 
			
		||||
            foreach (var exec in _lateBlockers)
 | 
			
		||||
            {
 | 
			
		||||
                if (await exec.TryBlockLate(_client, context, cmd.Module.GetTopLevelModule().Name, cmd)
 | 
			
		||||
                    .ConfigureAwait(false))
 | 
			
		||||
                {
 | 
			
		||||
                    Log.Information("Late blocking User [{0}] Command: [{1}] in [{2}]", context.User, commandName,
 | 
			
		||||
                        exec.GetType().Name);
 | 
			
		||||
                    return (false, null, cmd);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //If we get this far, at least one parse was successful. Execute the most likely overload.
 | 
			
		||||
            var chosenOverload = successfulParses[0];
 | 
			
		||||
            var execResult = (ExecuteResult)await chosenOverload.Key.ExecuteAsync(context, chosenOverload.Value, services).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
            if (execResult.Exception != null && (!(execResult.Exception is HttpException he) || he.DiscordCode != 50013))
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning(execResult.Exception, "Command Error");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (true, null, cmd);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								src/NadekoBot/Services/Common/GreetGrouper.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/NadekoBot/Services/Common/GreetGrouper.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services
 | 
			
		||||
{
 | 
			
		||||
    public class GreetGrouper<T>
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Dictionary<ulong, HashSet<T>> group;
 | 
			
		||||
        private readonly object locker = new object();
 | 
			
		||||
 | 
			
		||||
        public GreetGrouper()
 | 
			
		||||
        {
 | 
			
		||||
            group = new Dictionary<ulong, HashSet<T>>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Creates a group, if group already exists, adds the specified user
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="guildId">Id of the server for which to create group for</param>
 | 
			
		||||
        /// <param name="toAddIfExists">User to add if group already exists</param>
 | 
			
		||||
        /// <returns></returns>
 | 
			
		||||
        public bool CreateOrAdd(ulong guildId, T toAddIfExists)
 | 
			
		||||
        {
 | 
			
		||||
            lock (locker)
 | 
			
		||||
            {
 | 
			
		||||
                if (group.TryGetValue(guildId, out var list))
 | 
			
		||||
                {
 | 
			
		||||
                    list.Add(toAddIfExists);
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                group[guildId] = new HashSet<T>();
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Remove the specified amount of items from the group. If all items are removed, group will be removed.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="guildId">Id of the group</param>
 | 
			
		||||
        /// <param name="count">Maximum number of items to retrieve</param>
 | 
			
		||||
        /// <param name="items">Items retrieved</param>
 | 
			
		||||
        /// <returns>Whether the group has no more items left and is deleted</returns>
 | 
			
		||||
        public bool ClearGroup(ulong guildId, int count, out IEnumerable<T> items)
 | 
			
		||||
        {
 | 
			
		||||
            lock (locker)
 | 
			
		||||
            {
 | 
			
		||||
                if (group.TryGetValue(guildId, out var set))
 | 
			
		||||
                {
 | 
			
		||||
                    // if we want more than there are, return everything
 | 
			
		||||
                    if (count >= set.Count)
 | 
			
		||||
                    {
 | 
			
		||||
                        items = set;
 | 
			
		||||
                        group.Remove(guildId);
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // if there are more in the group than what's needed
 | 
			
		||||
                    // take the requested number, remove them from the set
 | 
			
		||||
                    // and return them
 | 
			
		||||
                    var toReturn = set.TakeWhile(item => count-- != 0).ToList();
 | 
			
		||||
                    foreach (var item in toReturn)
 | 
			
		||||
                        set.Remove(item);
 | 
			
		||||
 | 
			
		||||
                    items = toReturn;
 | 
			
		||||
                    // returning falsemeans group is not yet deleted
 | 
			
		||||
                    // because there are items left
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                items = Enumerable.Empty<T>();
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										141
									
								
								src/NadekoBot/Services/Common/ImageLoader.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/NadekoBot/Services/Common/ImageLoader.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,141 @@
 | 
			
		||||
using Newtonsoft.Json.Linq;
 | 
			
		||||
using StackExchange.Redis;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Serilog;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Common
 | 
			
		||||
{
 | 
			
		||||
    public class ImageLoader
 | 
			
		||||
    {
 | 
			
		||||
        private readonly HttpClient _http;
 | 
			
		||||
        private readonly ConnectionMultiplexer _con;
 | 
			
		||||
 | 
			
		||||
        public Func<string, RedisKey> GetKey { get; }
 | 
			
		||||
 | 
			
		||||
        private IDatabase _db => _con.GetDatabase();
 | 
			
		||||
 | 
			
		||||
        private readonly List<Task<KeyValuePair<RedisKey, RedisValue>>> uriTasks = new List<Task<KeyValuePair<RedisKey, RedisValue>>>();
 | 
			
		||||
 | 
			
		||||
        public ImageLoader(HttpClient http, ConnectionMultiplexer con, Func<string, RedisKey> getKey)
 | 
			
		||||
        {
 | 
			
		||||
            _http = http;
 | 
			
		||||
            _con = con;
 | 
			
		||||
            GetKey = getKey;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<byte[]> GetImageData(Uri uri)
 | 
			
		||||
        {
 | 
			
		||||
            if (uri.IsFile)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var bytes = await File.ReadAllBytesAsync(uri.LocalPath);
 | 
			
		||||
                    return bytes;
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    Log.Warning(ex, "Failed reading image bytes");
 | 
			
		||||
                    return null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                return await _http.GetByteArrayAsync(uri);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        async Task HandleJArray(JArray arr, string key)
 | 
			
		||||
        {
 | 
			
		||||
            var tasks = arr.Where(x => x.Type == JTokenType.String)
 | 
			
		||||
                .Select(async x =>
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        return await GetImageData((Uri)x).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch
 | 
			
		||||
                    {
 | 
			
		||||
                        Log.Error("Error retreiving image for key {Key}: {Data}", key, x);
 | 
			
		||||
                        return null;
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            byte[][] vals = Array.Empty<byte[]>();
 | 
			
		||||
            vals = await Task.WhenAll(tasks).ConfigureAwait(false);
 | 
			
		||||
            if (vals.Any(x => x == null))
 | 
			
		||||
                vals = vals.Where(x => x != null).ToArray();
 | 
			
		||||
 | 
			
		||||
            await _db.KeyDeleteAsync(GetKey(key)).ConfigureAwait(false);
 | 
			
		||||
            await _db.ListRightPushAsync(GetKey(key),
 | 
			
		||||
                vals.Where(x => x != null)
 | 
			
		||||
                    .Select(x => (RedisValue)x)
 | 
			
		||||
                    .ToArray()).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
            if (arr.Count != vals.Length)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Information("{2}/{1} URIs for the key '{0}' have been loaded. Some of the supplied URIs are either unavailable or invalid.", key, arr.Count, vals.Count());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        async Task<KeyValuePair<RedisKey, RedisValue>> HandleUri(Uri uri, string key)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                RedisValue data = await GetImageData(uri).ConfigureAwait(false);
 | 
			
		||||
                return new KeyValuePair<RedisKey, RedisValue>(GetKey(key), data);
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                Log.Information("Setting '{0}' image failed. The URI you provided is either unavailable or invalid.", key.ToLowerInvariant());
 | 
			
		||||
                return new KeyValuePair<RedisKey, RedisValue>("", "");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Task HandleJObject(JObject obj, string parent = "")
 | 
			
		||||
        {
 | 
			
		||||
            string GetParentString()
 | 
			
		||||
            {
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(parent))
 | 
			
		||||
                    return "";
 | 
			
		||||
                else
 | 
			
		||||
                    return parent + "_";
 | 
			
		||||
            }
 | 
			
		||||
            List<Task> tasks = new List<Task>();
 | 
			
		||||
            Task t;
 | 
			
		||||
            // go through all of the kvps in the object
 | 
			
		||||
            foreach (var kvp in obj)
 | 
			
		||||
            {
 | 
			
		||||
                // if it's a JArray, resole it using jarray method which will
 | 
			
		||||
                // return task<byte[][]> aka an array of all images' bytes
 | 
			
		||||
                if (kvp.Value.Type == JTokenType.Array)
 | 
			
		||||
                {
 | 
			
		||||
                    t = HandleJArray((JArray)kvp.Value, GetParentString() + kvp.Key);
 | 
			
		||||
                    tasks.Add(t);
 | 
			
		||||
                }
 | 
			
		||||
                else if (kvp.Value.Type == JTokenType.String)
 | 
			
		||||
                {
 | 
			
		||||
                    var uriTask = HandleUri((Uri)kvp.Value, GetParentString() + kvp.Key);
 | 
			
		||||
                    uriTasks.Add(uriTask);
 | 
			
		||||
                }
 | 
			
		||||
                else if (kvp.Value.Type == JTokenType.Object)
 | 
			
		||||
                {
 | 
			
		||||
                    t = HandleJObject((JObject)kvp.Value, GetParentString() + kvp.Key);
 | 
			
		||||
                    tasks.Add(t);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return Task.WhenAll(tasks);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task LoadAsync(JObject obj)
 | 
			
		||||
        {
 | 
			
		||||
            await HandleJObject(obj).ConfigureAwait(false);
 | 
			
		||||
            var results = await Task.WhenAll(uriTasks).ConfigureAwait(false);
 | 
			
		||||
            await _db.StringSetAsync(results.Where(x => x.Key != "").ToArray()).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								src/NadekoBot/Services/Common/RedisImageArray.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/NadekoBot/Services/Common/RedisImageArray.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
using StackExchange.Redis;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Common
 | 
			
		||||
{
 | 
			
		||||
    public sealed class RedisImageArray : IReadOnlyList<byte[]>
 | 
			
		||||
    {
 | 
			
		||||
        public byte[] this[int index]
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                if (index < 0)
 | 
			
		||||
                    throw new ArgumentOutOfRangeException(nameof(index));
 | 
			
		||||
 | 
			
		||||
                return _con.GetDatabase().ListGetByIndex(_key, index);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int Count => _data.IsValueCreated
 | 
			
		||||
            ? _data.Value.Length
 | 
			
		||||
            : (int)_con.GetDatabase().ListLength(_key);
 | 
			
		||||
 | 
			
		||||
        private readonly ConnectionMultiplexer _con;
 | 
			
		||||
        private readonly string _key;
 | 
			
		||||
 | 
			
		||||
        private readonly Lazy<byte[][]> _data;
 | 
			
		||||
 | 
			
		||||
        public RedisImageArray(string key, ConnectionMultiplexer con)
 | 
			
		||||
        {
 | 
			
		||||
            _con = con;
 | 
			
		||||
            _key = key;
 | 
			
		||||
            _data = new Lazy<byte[][]>(() => _con.GetDatabase().ListRange(_key).Select(x => (byte[])x).ToArray(), true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerator<byte[]> GetEnumerator()
 | 
			
		||||
        {
 | 
			
		||||
            var actualData = _data.Value;
 | 
			
		||||
            for (int i = 0; i < actualData.Length; i++)
 | 
			
		||||
            {
 | 
			
		||||
                yield return actualData[i];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        IEnumerator IEnumerable.GetEnumerator()
 | 
			
		||||
        {
 | 
			
		||||
            return _data.Value.GetEnumerator();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								src/NadekoBot/Services/Database/IUnitOfWork.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/NadekoBot/Services/Database/IUnitOfWork.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Repositories;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database
 | 
			
		||||
{
 | 
			
		||||
    public interface IUnitOfWork : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        NadekoContext _context { get; }
 | 
			
		||||
 | 
			
		||||
        IQuoteRepository Quotes { get; }
 | 
			
		||||
        IGuildConfigRepository GuildConfigs { get; }
 | 
			
		||||
        IReminderRepository Reminders { get; }
 | 
			
		||||
        ISelfAssignedRolesRepository SelfAssignedRoles { get; }
 | 
			
		||||
        ICustomReactionRepository CustomReactions { get; }
 | 
			
		||||
        IMusicPlaylistRepository MusicPlaylists { get; }
 | 
			
		||||
        IWaifuRepository Waifus { get; }
 | 
			
		||||
        IDiscordUserRepository DiscordUsers { get; }
 | 
			
		||||
        IWarningsRepository Warnings { get; }
 | 
			
		||||
        IXpRepository Xp { get; }
 | 
			
		||||
        IClubRepository Clubs { get; }
 | 
			
		||||
        IPollsRepository Polls { get; }
 | 
			
		||||
        IPlantedCurrencyRepository PlantedCurrency { get; }
 | 
			
		||||
 | 
			
		||||
        int SaveChanges();
 | 
			
		||||
        Task<int> SaveChangesAsync();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								src/NadekoBot/Services/Database/Models/AntiProtection.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/NadekoBot/Services/Database/Models/AntiProtection.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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; } = 0;
 | 
			
		||||
        public ulong? RoleId { get; set; }
 | 
			
		||||
        public HashSet<AntiSpamIgnore> IgnoredChannels { get; set; } = new HashSet<AntiSpamIgnore>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public enum PunishmentAction
 | 
			
		||||
    {
 | 
			
		||||
        Mute,
 | 
			
		||||
        Kick,
 | 
			
		||||
        Ban,
 | 
			
		||||
        Softban,
 | 
			
		||||
        RemoveRoles,
 | 
			
		||||
        ChatMute,
 | 
			
		||||
        VoiceMute,
 | 
			
		||||
        AddRole
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class AntiSpamIgnore : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong ChannelId { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode() => ChannelId.GetHashCode();
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is AntiSpamIgnore inst
 | 
			
		||||
                ? inst.ChannelId == ChannelId
 | 
			
		||||
                : false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								src/NadekoBot/Services/Database/Models/AutoCommand.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/NadekoBot/Services/Database/Models/AutoCommand.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								src/NadekoBot/Services/Database/Models/BanTemplate.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/NadekoBot/Services/Database/Models/BanTemplate.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class BanTemplate : DbEntity 
 | 
			
		||||
    {
 | 
			
		||||
        public ulong GuildId { get; set; }
 | 
			
		||||
        public string Text { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								src/NadekoBot/Services/Database/Models/BlacklistEntry.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/NadekoBot/Services/Database/Models/BlacklistEntry.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class BlacklistEntry : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong ItemId { get; set; }
 | 
			
		||||
        public BlacklistType Type { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public enum BlacklistType
 | 
			
		||||
    {
 | 
			
		||||
        Server,
 | 
			
		||||
        Channel,
 | 
			
		||||
        User
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								src/NadekoBot/Services/Database/Models/ClubInfo.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/NadekoBot/Services/Database/Models/ClubInfo.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class ClubInfo : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        [MaxLength(20)]
 | 
			
		||||
        public string Name { get; set; }
 | 
			
		||||
        public int Discrim { get; set; }
 | 
			
		||||
 | 
			
		||||
        public string ImageUrl { get; set; } = "";
 | 
			
		||||
        public int MinimumLevelReq { get; set; } = 5;
 | 
			
		||||
        public int Xp { get; set; } = 0;
 | 
			
		||||
        
 | 
			
		||||
        public int OwnerId { get; set; }
 | 
			
		||||
        public DiscordUser Owner { get; set; }
 | 
			
		||||
 | 
			
		||||
        public List<DiscordUser> Users { get; set; } = new List<DiscordUser>();
 | 
			
		||||
 | 
			
		||||
        public List<ClubApplicants> Applicants { get; set; } = new List<ClubApplicants>();
 | 
			
		||||
        public List<ClubBans> Bans { get; set; } = new List<ClubBans>();
 | 
			
		||||
        public string Description { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override string ToString()
 | 
			
		||||
        {
 | 
			
		||||
            return Name + "#" + Discrim;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								src/NadekoBot/Services/Database/Models/CommandAlias.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/NadekoBot/Services/Database/Models/CommandAlias.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class CommandAlias : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public string Trigger { get; set; }
 | 
			
		||||
        public string Mapping { get; set; }
 | 
			
		||||
 | 
			
		||||
        //// override object.Equals
 | 
			
		||||
        //public override bool Equals(object obj)
 | 
			
		||||
        //{
 | 
			
		||||
        //    if (obj == null || GetType() != obj.GetType())
 | 
			
		||||
        //    {
 | 
			
		||||
        //        return false;
 | 
			
		||||
        //    }
 | 
			
		||||
 | 
			
		||||
        //    return ((CommandAlias)obj).Trigger.Trim().ToLowerInvariant() == Trigger.Trim().ToLowerInvariant();
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
        //// override object.GetHashCode
 | 
			
		||||
        //public override int GetHashCode()
 | 
			
		||||
        //{
 | 
			
		||||
        //    return Trigger.Trim().ToLowerInvariant().GetHashCode();
 | 
			
		||||
        //}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class CommandCooldown : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public int Seconds { get; set; }
 | 
			
		||||
        public string CommandName { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,16 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class CurrencyTransaction : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public long Amount { get; set; }
 | 
			
		||||
        public string Reason { get; set; }
 | 
			
		||||
        public ulong UserId { get; set; }
 | 
			
		||||
 | 
			
		||||
        public CurrencyTransaction Clone() => new CurrencyTransaction
 | 
			
		||||
        {
 | 
			
		||||
            Amount = Amount,
 | 
			
		||||
            Reason = Reason,
 | 
			
		||||
            UserId = UserId,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								src/NadekoBot/Services/Database/Models/CustomReaction.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/NadekoBot/Services/Database/Models/CustomReaction.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel.DataAnnotations.Schema;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class CustomReaction : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        #region Unused
 | 
			
		||||
        
 | 
			
		||||
        [Obsolete]
 | 
			
		||||
        [NotMapped]
 | 
			
		||||
        public Regex Regex { get; set; }
 | 
			
		||||
        [Obsolete]
 | 
			
		||||
        public ulong UseCount { get; set; }
 | 
			
		||||
        [Obsolete]
 | 
			
		||||
        public bool IsRegex { get; set; }
 | 
			
		||||
        [Obsolete]
 | 
			
		||||
        public bool OwnerOnly { get; set; }
 | 
			
		||||
        
 | 
			
		||||
        #endregion
 | 
			
		||||
        
 | 
			
		||||
        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 || GuildId == 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class ReactionResponse : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public bool OwnerOnly { get; set; }
 | 
			
		||||
        public string Text { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								src/NadekoBot/Services/Database/Models/DbEntity.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/NadekoBot/Services/Database/Models/DbEntity.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        [Key]
 | 
			
		||||
        public int Id { get; set; }
 | 
			
		||||
        public DateTime? DateAdded { get; set; } = DateTime.UtcNow;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								src/NadekoBot/Services/Database/Models/DelMsgOnCmdChannel.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/NadekoBot/Services/Database/Models/DelMsgOnCmdChannel.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class DelMsgOnCmdChannel : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong ChannelId { get; set; }
 | 
			
		||||
        public bool State { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return ChannelId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is DelMsgOnCmdChannel x
 | 
			
		||||
                && x.ChannelId == ChannelId;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								src/NadekoBot/Services/Database/Models/DiscordPemOverride.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/NadekoBot/Services/Database/Models/DiscordPemOverride.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
using Discord;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class DiscordPermOverride : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public GuildPerm Perm { get; set; }
 | 
			
		||||
        
 | 
			
		||||
        public ulong? GuildId { get; set; }
 | 
			
		||||
        public string Command { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								src/NadekoBot/Services/Database/Models/DiscordUser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/NadekoBot/Services/Database/Models/DiscordUser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    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 ClubInfo Club { get; set; }
 | 
			
		||||
        public bool IsClubAdmin { get; set; }
 | 
			
		||||
 | 
			
		||||
        public int TotalXp { get; set; }
 | 
			
		||||
        public DateTime LastLevelUp { get; set; } = DateTime.UtcNow;
 | 
			
		||||
        public DateTime LastXpGain { get; set; } = DateTime.MinValue;
 | 
			
		||||
        public XpNotificationLocation NotifyOnLevelUp { get; set; }
 | 
			
		||||
 | 
			
		||||
        public long CurrencyAmount { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is DiscordUser du
 | 
			
		||||
                ? du.UserId == UserId
 | 
			
		||||
                : false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return UserId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override string ToString() => 
 | 
			
		||||
            Username + "#" + Discriminator;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								src/NadekoBot/Services/Database/Models/Event.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/NadekoBot/Services/Database/Models/Event.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								src/NadekoBot/Services/Database/Models/FeedSub.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/NadekoBot/Services/Database/Models/FeedSub.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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 override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return Url.GetHashCode(StringComparison.InvariantCulture) ^ GuildConfigId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is FeedSub s
 | 
			
		||||
                && s.Url.ToLower() == Url.ToLower()
 | 
			
		||||
                && s.GuildConfigId == GuildConfigId;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								src/NadekoBot/Services/Database/Models/FilterChannelId.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/NadekoBot/Services/Database/Models/FilterChannelId.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class FilterChannelId : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong ChannelId { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is FilterChannelId f
 | 
			
		||||
                ? f.ChannelId == ChannelId
 | 
			
		||||
                : false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return ChannelId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,19 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class FilterLinksChannelId : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong ChannelId { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is FilterLinksChannelId f
 | 
			
		||||
                ? f.ChannelId == ChannelId
 | 
			
		||||
                : false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return ChannelId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/NadekoBot/Services/Database/Models/FilteredWord.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/NadekoBot/Services/Database/Models/FilteredWord.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class FilteredWord : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public string Word { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								src/NadekoBot/Services/Database/Models/FollowedStream.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/NadekoBot/Services/Database/Models/FollowedStream.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
using System;
 | 
			
		||||
using NadekoBot.Core.Modules.Searches.Common;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class FollowedStream : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        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; }
 | 
			
		||||
 | 
			
		||||
        public enum FType
 | 
			
		||||
        {
 | 
			
		||||
            Twitch = 0,
 | 
			
		||||
            [Obsolete("No longer supported.")]
 | 
			
		||||
            Smashcast = 1,
 | 
			
		||||
            [Obsolete("No longer supported.")]
 | 
			
		||||
            Mixer = 2,
 | 
			
		||||
            Picarto = 3,
 | 
			
		||||
            Youtube = 4,
 | 
			
		||||
            Facebook = 5,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected bool Equals(FollowedStream other)
 | 
			
		||||
        {
 | 
			
		||||
            return ChannelId == other.ChannelId 
 | 
			
		||||
                   && Username.Trim().ToUpperInvariant() == other.Username.Trim().ToUpperInvariant() 
 | 
			
		||||
                   && Type == other.Type;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return HashCode.Combine(ChannelId, Username, (int) Type);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            if (ReferenceEquals(null, obj)) return false;
 | 
			
		||||
            if (ReferenceEquals(this, obj)) return true;
 | 
			
		||||
            if (obj.GetType() != this.GetType()) return false;
 | 
			
		||||
            return Equals((FollowedStream) obj);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public StreamDataKey CreateKey() =>
 | 
			
		||||
            new StreamDataKey(Type, Username.ToLower());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								src/NadekoBot/Services/Database/Models/GCChannelId.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/NadekoBot/Services/Database/Models/GCChannelId.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class GCChannelId : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public GuildConfig GuildConfig { get; set; }
 | 
			
		||||
        public ulong ChannelId { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is GCChannelId gc
 | 
			
		||||
                ? gc.ChannelId == ChannelId
 | 
			
		||||
                : false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode() =>
 | 
			
		||||
            this.ChannelId.GetHashCode();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								src/NadekoBot/Services/Database/Models/GroupName.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/NadekoBot/Services/Database/Models/GroupName.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								src/NadekoBot/Services/Database/Models/GuildConfig.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/NadekoBot/Services/Database/Models/GuildConfig.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
			
		||||
using System;
 | 
			
		||||
using NadekoBot.Common.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class GuildConfig : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong GuildId { get; set; }
 | 
			
		||||
 | 
			
		||||
        public string Prefix { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
        public bool DeleteMessageOnCommand { get; set; }
 | 
			
		||||
        public HashSet<DelMsgOnCmdChannel> DelMsgOnCmdChannels { get; set; } = new HashSet<DelMsgOnCmdChannel>();
 | 
			
		||||
        [Obsolete("Use autoassignroleids")]
 | 
			
		||||
        public ulong AutoAssignRoleId { get; set; }
 | 
			
		||||
        public string AutoAssignRoleIds { get; set; }
 | 
			
		||||
        //greet stuff
 | 
			
		||||
        public bool AutoDeleteGreetMessages { get; set; } //unused
 | 
			
		||||
        public bool AutoDeleteByeMessages { get; set; } // unused
 | 
			
		||||
        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!";
 | 
			
		||||
 | 
			
		||||
        public LogSetting LogSetting { get; set; } = new LogSetting();
 | 
			
		||||
 | 
			
		||||
        //self assignable roles
 | 
			
		||||
        public bool ExclusiveSelfAssignedRoles { get; set; }
 | 
			
		||||
        public bool AutoDeleteSelfAssignedRoleMessages { get; set; }
 | 
			
		||||
        public float DefaultMusicVolume { get; set; } = 1.0f;
 | 
			
		||||
        public bool VoicePlusTextEnabled { get; set; }
 | 
			
		||||
 | 
			
		||||
        //stream notifications
 | 
			
		||||
        public HashSet<FollowedStream> FollowedStreams { get; set; } = new HashSet<FollowedStream>();
 | 
			
		||||
 | 
			
		||||
        //currencyGeneration
 | 
			
		||||
        public HashSet<GCChannelId> GenerateCurrencyChannelIds { get; set; } = new HashSet<GCChannelId>();
 | 
			
		||||
 | 
			
		||||
        //permissions
 | 
			
		||||
        public Permission RootPermission { get; set; } = null;
 | 
			
		||||
        public List<Permissionv2> Permissions { get; set; }
 | 
			
		||||
        public bool VerbosePermissions { get; set; } = true;
 | 
			
		||||
        public string PermissionRole { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
        public HashSet<CommandCooldown> CommandCooldowns { get; set; } = new HashSet<CommandCooldown>();
 | 
			
		||||
 | 
			
		||||
        //filtering
 | 
			
		||||
        public bool FilterInvites { get; set; }
 | 
			
		||||
        public bool FilterLinks { get; set; }
 | 
			
		||||
        public HashSet<FilterChannelId> FilterInvitesChannelIds { get; set; } = new HashSet<FilterChannelId>();
 | 
			
		||||
        public HashSet<FilterLinksChannelId> FilterLinksChannelIds { get; set; } = new HashSet<FilterLinksChannelId>();
 | 
			
		||||
 | 
			
		||||
        //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 HashSet<FilteredWord>();
 | 
			
		||||
        public HashSet<FilterChannelId> FilterWordsChannelIds { get; set; } = new HashSet<FilterChannelId>();
 | 
			
		||||
 | 
			
		||||
        public HashSet<MutedUserId> MutedUsers { get; set; } = new HashSet<MutedUserId>();
 | 
			
		||||
 | 
			
		||||
        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; } = null;
 | 
			
		||||
        public string TimeZoneId { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
        public HashSet<UnmuteTimer> UnmuteTimers { get; set; } = new HashSet<UnmuteTimer>();
 | 
			
		||||
        public HashSet<UnbanTimer> UnbanTimer { get; set; } = new HashSet<UnbanTimer>();
 | 
			
		||||
        public HashSet<UnroleTimer> UnroleTimer { get; set; } = new HashSet<UnroleTimer>();
 | 
			
		||||
        public HashSet<VcRoleInfo> VcRoleInfos { get; set; }
 | 
			
		||||
        public HashSet<CommandAlias> CommandAliases { get; set; } = new HashSet<CommandAlias>();
 | 
			
		||||
        public List<WarningPunishment> WarnPunishments { get; set; } = new List<WarningPunishment>();
 | 
			
		||||
        public bool WarningsInitialized { get; set; }
 | 
			
		||||
        public HashSet<SlowmodeIgnoredUser> SlowmodeIgnoredUsers { get; set; }
 | 
			
		||||
        public HashSet<SlowmodeIgnoredRole> SlowmodeIgnoredRoles { get; set; }
 | 
			
		||||
        public HashSet<NsfwBlacklitedTag> NsfwBlacklistedTags { get; set; } = new HashSet<NsfwBlacklitedTag>();
 | 
			
		||||
 | 
			
		||||
        public List<ShopEntry> ShopEntries { get; set; }
 | 
			
		||||
        public ulong? GameVoiceChannel { get; set; } = null;
 | 
			
		||||
        public bool VerboseErrors { get; set; } = false;
 | 
			
		||||
 | 
			
		||||
        public StreamRoleSettings StreamRole { get; set; }
 | 
			
		||||
 | 
			
		||||
        public XpSettings XpSettings { get; set; }
 | 
			
		||||
        public List<FeedSub> FeedSubs { get; set; } = new List<FeedSub>();
 | 
			
		||||
        public bool AutoDcFromVc { get; set; }
 | 
			
		||||
        public IndexedCollection<ReactionRoleMessage> ReactionRoleMessages { get; set; } = new IndexedCollection<ReactionRoleMessage>();
 | 
			
		||||
        public bool NotifyStreamOffline { get; set; }
 | 
			
		||||
        public List<GroupName> SelfAssignableRoleGroupNames { get; set; }
 | 
			
		||||
        public int WarnExpireHours { get; set; } = 0;
 | 
			
		||||
        public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class IgnoredLogChannel : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public LogSetting LogSetting { get; set; }
 | 
			
		||||
        public ulong ChannelId { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class IgnoredVoicePresenceChannel : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public LogSetting LogSetting { get; set; }
 | 
			
		||||
        public ulong ChannelId { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										105
									
								
								src/NadekoBot/Services/Database/Models/LogSetting.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								src/NadekoBot/Services/Database/Models/LogSetting.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    public class LogSetting : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public HashSet<IgnoredLogChannel> IgnoredChannels { get; set; } = new HashSet<IgnoredLogChannel>();
 | 
			
		||||
        public HashSet<IgnoredVoicePresenceChannel> IgnoredVoicePresenceChannelIds { get; set; } = new HashSet<IgnoredVoicePresenceChannel>();
 | 
			
		||||
 | 
			
		||||
        public ulong? LogOtherId { get; set; } = null;
 | 
			
		||||
        public ulong? MessageUpdatedId { get; set; } = null;
 | 
			
		||||
        public ulong? MessageDeletedId { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
        public ulong? UserJoinedId { get; set; } = null;
 | 
			
		||||
        public ulong? UserLeftId { get; set; } = null;
 | 
			
		||||
        public ulong? UserBannedId { get; set; } = null;
 | 
			
		||||
        public ulong? UserUnbannedId { get; set; } = null;
 | 
			
		||||
        public ulong? UserUpdatedId { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
        public ulong? ChannelCreatedId { get; set; } = null;
 | 
			
		||||
        public ulong? ChannelDestroyedId { get; set; } = null;
 | 
			
		||||
        public ulong? ChannelUpdatedId { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
        public ulong? UserMutedId { get; set; }
 | 
			
		||||
 | 
			
		||||
        //userpresence
 | 
			
		||||
        public ulong? LogUserPresenceId { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
        //voicepresence
 | 
			
		||||
 | 
			
		||||
        public ulong? LogVoicePresenceId { get; set; } = null;
 | 
			
		||||
        public ulong? LogVoicePresenceTTSId { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        //-------------------DO NOT USE----------------
 | 
			
		||||
        // these old fields are here because sqlite doesn't support drop column operation
 | 
			
		||||
        // will be removed after bot moves to another database provider
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool IsLogging { get; set; }
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public ulong ChannelId { get; set; }
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool MessageUpdated { get; set; } = true;
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool MessageDeleted { get; set; } = true;
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool UserJoined { get; set; } = true;
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool UserLeft { get; set; } = true;
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool UserBanned { get; set; } = true;
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool UserUnbanned { get; set; } = true;
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool UserUpdated { get; set; } = true;
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool ChannelCreated { get; set; } = true;
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool ChannelDestroyed { get; set; } = true;
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool ChannelUpdated { get; set; } = true;
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool LogUserPresence { get; set; } = false;
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public ulong UserPresenceChannelId { get; set; }
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool LogVoicePresence { get; set; } = false;
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// DON'T USE
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public ulong VoicePresenceChannelId { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								src/NadekoBot/Services/Database/Models/MusicPlaylist.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/NadekoBot/Services/Database/Models/MusicPlaylist.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class MusicPlaylist : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public string Name { get; set; }
 | 
			
		||||
        public string Author { get; set; }
 | 
			
		||||
        public ulong AuthorId { get; set; }
 | 
			
		||||
        public List<PlaylistSong> Songs { get; set; } = new List<PlaylistSong>();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										56
									
								
								src/NadekoBot/Services/Database/Models/MusicSettings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/NadekoBot/Services/Database/Models/MusicSettings.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class MusicPlayerSettings
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Auto generated Id 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public int Id { get; set; }
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Id of the guild
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public ulong GuildId { get; set; }
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Queue repeat type
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public PlayerRepeatType PlayerRepeat { get; set; } = PlayerRepeatType.Queue;
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Channel id the bot will always try to send track related messages to
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public ulong? MusicChannelId { get; set; } = null;
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Default volume player will be created with
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public int Volume { get; set; } = 100;
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Whether the bot should auto disconnect from the voice channel once the queue is done
 | 
			
		||||
        /// This only has effect if 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool AutoDisconnect { get; set; } = false;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Selected quality preset for the music player 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public QualityPreset QualityPreset { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public enum QualityPreset
 | 
			
		||||
    {
 | 
			
		||||
        Highest,
 | 
			
		||||
        High,
 | 
			
		||||
        Medium,
 | 
			
		||||
        Low
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public enum PlayerRepeatType
 | 
			
		||||
    {
 | 
			
		||||
        None,
 | 
			
		||||
        Track,
 | 
			
		||||
        Queue
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								src/NadekoBot/Services/Database/Models/MutedUserId.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/NadekoBot/Services/Database/Models/MutedUserId.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class MutedUserId : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong UserId { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return UserId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is MutedUserId mui
 | 
			
		||||
                ? mui.UserId == UserId
 | 
			
		||||
                : false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								src/NadekoBot/Services/Database/Models/NsfwBlacklitedTag.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/NadekoBot/Services/Database/Models/NsfwBlacklitedTag.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class NsfwBlacklitedTag : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public string Tag { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return Tag.GetHashCode(StringComparison.InvariantCulture);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is NsfwBlacklitedTag x
 | 
			
		||||
                ? x.Tag == Tag
 | 
			
		||||
                : false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										85
									
								
								src/NadekoBot/Services/Database/Models/Permission.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/NadekoBot/Services/Database/Models/Permission.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel.DataAnnotations.Schema;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    [DebuggerDisplay("{global::NadekoBot.Modules.Permissions.PermissionExtensions.GetCommand(this)}", Target = typeof(Permission))]
 | 
			
		||||
    public class Permission : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public Permission Previous { get; set; } = null;
 | 
			
		||||
        public Permission Next { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
        public PrimaryPermissionType PrimaryTarget { get; set; }
 | 
			
		||||
        public ulong PrimaryTargetId { get; set; }
 | 
			
		||||
 | 
			
		||||
        public SecondaryPermissionType SecondaryTarget { get; set; }
 | 
			
		||||
        public string SecondaryTargetName { get; set; }
 | 
			
		||||
 | 
			
		||||
        public bool State { get; set; }
 | 
			
		||||
 | 
			
		||||
        public Permissionv2 Tov2() =>
 | 
			
		||||
            new Permissionv2()
 | 
			
		||||
            {
 | 
			
		||||
                PrimaryTarget = PrimaryTarget,
 | 
			
		||||
                PrimaryTargetId = PrimaryTargetId,
 | 
			
		||||
                SecondaryTarget = SecondaryTarget,
 | 
			
		||||
                SecondaryTargetName = SecondaryTargetName,
 | 
			
		||||
                State = State,
 | 
			
		||||
            };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface IIndexed
 | 
			
		||||
    {
 | 
			
		||||
        int Index { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [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 Permissionv2()
 | 
			
		||||
        {
 | 
			
		||||
            PrimaryTarget = PrimaryPermissionType.Server,
 | 
			
		||||
            PrimaryTargetId = 0,
 | 
			
		||||
            SecondaryTarget = SecondaryPermissionType.AllModules,
 | 
			
		||||
            SecondaryTargetName = "*",
 | 
			
		||||
            State = true,
 | 
			
		||||
            Index = 0,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static List<Permissionv2> GetDefaultPermlist =>
 | 
			
		||||
            new List<Permissionv2>
 | 
			
		||||
            {
 | 
			
		||||
                AllowAllPerm
 | 
			
		||||
            };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public enum PrimaryPermissionType
 | 
			
		||||
    {
 | 
			
		||||
        User,
 | 
			
		||||
        Channel,
 | 
			
		||||
        Role,
 | 
			
		||||
        Server
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public enum SecondaryPermissionType
 | 
			
		||||
    {
 | 
			
		||||
        Module,
 | 
			
		||||
        Command,
 | 
			
		||||
        AllModules
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								src/NadekoBot/Services/Database/Models/PlantedCurrency.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/NadekoBot/Services/Database/Models/PlantedCurrency.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								src/NadekoBot/Services/Database/Models/PlaylistSong.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/NadekoBot/Services/Database/Models/PlaylistSong.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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,
 | 
			
		||||
        Soundcloud
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								src/NadekoBot/Services/Database/Models/Poll.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/NadekoBot/Services/Database/Models/Poll.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
using NadekoBot.Common.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class Poll : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong GuildId { get; set; }
 | 
			
		||||
        public ulong ChannelId { get; set; }
 | 
			
		||||
        public string Question { get; set; }
 | 
			
		||||
        public IndexedCollection<PollAnswer> Answers { get; set; }
 | 
			
		||||
        public HashSet<PollVote> Votes { get; set; } = new HashSet<PollVote>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class PollAnswer : DbEntity, IIndexed
 | 
			
		||||
    {
 | 
			
		||||
        public int Index { get; set; }
 | 
			
		||||
        public string Text { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								src/NadekoBot/Services/Database/Models/PollVote.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/NadekoBot/Services/Database/Models/PollVote.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class PollVote : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong UserId { get; set; }
 | 
			
		||||
        public int VoteIndex { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return UserId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is PollVote p
 | 
			
		||||
                ? p.UserId == UserId
 | 
			
		||||
                : false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								src/NadekoBot/Services/Database/Models/Quote.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/NadekoBot/Services/Database/Models/Quote.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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 ulong UseCount { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public enum OrderType
 | 
			
		||||
    {
 | 
			
		||||
        Id = -1,
 | 
			
		||||
        Keyword = -2
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								src/NadekoBot/Services/Database/Models/ReactionRole.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/NadekoBot/Services/Database/Models/ReactionRole.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class ReactionRoleMessage : DbEntity, IIndexed
 | 
			
		||||
    {
 | 
			
		||||
        public int Index { get; set; }
 | 
			
		||||
 | 
			
		||||
        public int GuildConfigId { get; set; }
 | 
			
		||||
        public GuildConfig GuildConfig { get; set; }
 | 
			
		||||
 | 
			
		||||
        public ulong ChannelId { get; set; }
 | 
			
		||||
        public ulong MessageId { get; set; }
 | 
			
		||||
 | 
			
		||||
        public List<ReactionRole> ReactionRoles { get; set; }
 | 
			
		||||
        public bool Exclusive { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class ReactionRole : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public string EmoteName { get; set; }
 | 
			
		||||
        public ulong RoleId { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								src/NadekoBot/Services/Database/Models/Reminder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/NadekoBot/Services/Database/Models/Reminder.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								src/NadekoBot/Services/Database/Models/Repeater.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/NadekoBot/Services/Database/Models/Repeater.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								src/NadekoBot/Services/Database/Models/RewardedUser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/NadekoBot/Services/Database/Models/RewardedUser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class RewardedUser : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong UserId { get; set; }
 | 
			
		||||
        public string PatreonUserId { get; set; }
 | 
			
		||||
        public int AmountRewardedThisMonth { get; set; }
 | 
			
		||||
        public DateTime LastReward { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
using Discord;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class RotatingPlayingStatus : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public string Status { get; set; }
 | 
			
		||||
        public ActivityType Type { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								src/NadekoBot/Services/Database/Models/SelfAssignableRole.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/NadekoBot/Services/Database/Models/SelfAssignableRole.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								src/NadekoBot/Services/Database/Models/ShopEntry.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/NadekoBot/Services/Database/Models/ShopEntry.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public enum ShopEntryType
 | 
			
		||||
    {
 | 
			
		||||
        Role,
 | 
			
		||||
        List,
 | 
			
		||||
        //Infinite_List,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 HashSet<ShopEntryItem>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class ShopEntryItem : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public string Text { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            if (obj == null || GetType() != obj.GetType())
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            return ((ShopEntryItem)obj).Text == Text;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode() =>
 | 
			
		||||
            Text.GetHashCode(StringComparison.InvariantCulture);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,24 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class SlowmodeIgnoredRole : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong RoleId { get; set; }
 | 
			
		||||
 | 
			
		||||
        // override object.Equals
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            if (obj == null || GetType() != obj.GetType())
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return ((SlowmodeIgnoredRole)obj).RoleId == RoleId;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // override object.GetHashCode
 | 
			
		||||
        public override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return RoleId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,24 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class SlowmodeIgnoredUser : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong UserId { get; set; }
 | 
			
		||||
 | 
			
		||||
        // override object.Equals
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            if (obj == null || GetType() != obj.GetType())
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return ((SlowmodeIgnoredUser)obj).UserId == UserId;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // override object.GetHashCode
 | 
			
		||||
        public override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return UserId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								src/NadekoBot/Services/Database/Models/Stake.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/NadekoBot/Services/Database/Models/Stake.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Used to set stakes for gambling games which don't reward right away -
 | 
			
		||||
    /// like blackjack. If the bot is restarted mid game, users will get their funds back
 | 
			
		||||
    /// when the bot is back up.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class Stake : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong UserId { get; set; }
 | 
			
		||||
        public long Amount { get; set; }
 | 
			
		||||
        public string Source { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										78
									
								
								src/NadekoBot/Services/Database/Models/StreamRoleSettings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/NadekoBot/Services/Database/Models/StreamRoleSettings.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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 HashSet<StreamRoleWhitelistedUser>();
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// A collection of blacklisted users' IDs. Blacklisted useres will never get the stream role.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public HashSet<StreamRoleBlacklistedUser> Blacklist { get; set; } = new HashSet<StreamRoleBlacklistedUser>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class StreamRoleBlacklistedUser : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong UserId { get; set; }
 | 
			
		||||
        public string Username { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            if (!(obj is StreamRoleBlacklistedUser x))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            return x.UserId == UserId;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return UserId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class StreamRoleWhitelistedUser : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong UserId { get; set; }
 | 
			
		||||
        public string Username { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is StreamRoleWhitelistedUser x
 | 
			
		||||
                ? x.UserId == UserId
 | 
			
		||||
                : false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return UserId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								src/NadekoBot/Services/Database/Models/UnbanTimer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/NadekoBot/Services/Database/Models/UnbanTimer.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is UnbanTimer ut
 | 
			
		||||
                ? ut.UserId == UserId
 | 
			
		||||
                : false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								src/NadekoBot/Services/Database/Models/UnmuteTimer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/NadekoBot/Services/Database/Models/UnmuteTimer.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is UnmuteTimer ut
 | 
			
		||||
                ? ut.UserId == UserId
 | 
			
		||||
                : false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								src/NadekoBot/Services/Database/Models/UnroleTimer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/NadekoBot/Services/Database/Models/UnroleTimer.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is UnroleTimer ut
 | 
			
		||||
                ? ut.UserId == UserId && ut.RoleId == RoleId
 | 
			
		||||
                : false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/NadekoBot/Services/Database/Models/UserXpStats.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/NadekoBot/Services/Database/Models/UserXpStats.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class UserXpStats : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong UserId { get; set; }
 | 
			
		||||
        public ulong GuildId { get; set; }
 | 
			
		||||
        public int Xp { get; set; }
 | 
			
		||||
        public int AwardedXp { get; set; }
 | 
			
		||||
        public XpNotificationLocation NotifyOnLevelUp { get; set; }
 | 
			
		||||
        public DateTime LastLevelUp { get; set; } = DateTime.UtcNow;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public enum XpNotificationLocation { None, Dm, Channel }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								src/NadekoBot/Services/Database/Models/VcRoleInfo.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/NadekoBot/Services/Database/Models/VcRoleInfo.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class VcRoleInfo : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong VoiceChannelId { get; set; }
 | 
			
		||||
        public ulong RoleId { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										89
									
								
								src/NadekoBot/Services/Database/Models/Waifu.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/NadekoBot/Services/Database/Models/Waifu.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using NadekoBot.Core.Modules.Gambling.Common;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.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 int Price { get; set; }
 | 
			
		||||
        public List<WaifuItem> Items { get; set; } = new List<WaifuItem>();
 | 
			
		||||
 | 
			
		||||
        public override string ToString()
 | 
			
		||||
        {
 | 
			
		||||
            var claimer = "no one";
 | 
			
		||||
            var status = "";
 | 
			
		||||
 | 
			
		||||
            var waifuUsername = Waifu.Username.TrimTo(20);
 | 
			
		||||
            var claimerUsername = Claimer?.Username.TrimTo(20);
 | 
			
		||||
 | 
			
		||||
            if (ClaimerId != null)
 | 
			
		||||
            {
 | 
			
		||||
                claimer = $"{ claimerUsername }#{Claimer.Discriminator}";
 | 
			
		||||
            }
 | 
			
		||||
            if (AffinityId == null)
 | 
			
		||||
            {
 | 
			
		||||
                status = $"... but {waifuUsername}'s heart is empty";
 | 
			
		||||
            }
 | 
			
		||||
            else if (AffinityId == ClaimerId)
 | 
			
		||||
            {
 | 
			
		||||
                status = $"... and {waifuUsername} likes {claimerUsername} too <3";
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                status = $"... but {waifuUsername}'s heart belongs to {Affinity.Username.TrimTo(20)}#{Affinity.Discriminator}";
 | 
			
		||||
            }
 | 
			
		||||
            return $"**{waifuUsername}#{Waifu.Discriminator}** - 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 int Price { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override string ToString()
 | 
			
		||||
        {
 | 
			
		||||
            var claimer = "no one";
 | 
			
		||||
            var status = "";
 | 
			
		||||
 | 
			
		||||
            var waifuUsername = Username.TrimTo(20);
 | 
			
		||||
            var claimerUsername = Claimer?.TrimTo(20);
 | 
			
		||||
 | 
			
		||||
            if (Claimer != null)
 | 
			
		||||
            {
 | 
			
		||||
                claimer = $"{ claimerUsername }#{ClaimerDiscrim}";
 | 
			
		||||
            }
 | 
			
		||||
            if (Affinity == 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}";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								src/NadekoBot/Services/Database/Models/WaifuItem.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/NadekoBot/Services/Database/Models/WaifuItem.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class WaifuItem : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public int? WaifuInfoId { get; set; }
 | 
			
		||||
        public string ItemEmoji { get; set; }
 | 
			
		||||
        public string Name { get; set; }
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
        [Obsolete]
 | 
			
		||||
        public int Price { get; set; }
 | 
			
		||||
        [Obsolete]
 | 
			
		||||
        public int Item { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								src/NadekoBot/Services/Database/Models/WaifuUpdate.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/NadekoBot/Services/Database/Models/WaifuUpdate.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class WaifuUpdate : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public int UserId { get; set; }
 | 
			
		||||
        public DiscordUser User { get; set; }
 | 
			
		||||
        public WaifuUpdateType UpdateType { get; set; }
 | 
			
		||||
 | 
			
		||||
        public int? OldId { get; set; }
 | 
			
		||||
        public DiscordUser Old { get; set; }
 | 
			
		||||
 | 
			
		||||
        public int? NewId { get; set; }
 | 
			
		||||
        public DiscordUser New { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public enum WaifuUpdateType
 | 
			
		||||
    {
 | 
			
		||||
        AffinityChanged,
 | 
			
		||||
        Claimed
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public enum WarnExpireAction
 | 
			
		||||
    {
 | 
			
		||||
        Clear,
 | 
			
		||||
        Delete
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								src/NadekoBot/Services/Database/Models/Warning.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/NadekoBot/Services/Database/Models/Warning.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								src/NadekoBot/Services/Database/Models/WarningPunishment.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/NadekoBot/Services/Database/Models/WarningPunishment.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.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; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										78
									
								
								src/NadekoBot/Services/Database/Models/XpSettings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/NadekoBot/Services/Database/Models/XpSettings.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class XpSettings : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public int GuildConfigId { get; set; }
 | 
			
		||||
        public GuildConfig GuildConfig { get; set; }
 | 
			
		||||
 | 
			
		||||
        public HashSet<XpRoleReward> RoleRewards { get; set; } = new HashSet<XpRoleReward>();
 | 
			
		||||
        public HashSet<XpCurrencyReward> CurrencyRewards { get; set; } = new HashSet<XpCurrencyReward>();
 | 
			
		||||
        public bool XpRoleRewardExclusive { get; set; }
 | 
			
		||||
        public string NotifyMessage { get; set; } = "Congratulations {0}! You have reached level {1}!";
 | 
			
		||||
        public HashSet<ExcludedItem> ExclusionList { get; set; } = new HashSet<ExcludedItem>();
 | 
			
		||||
        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()
 | 
			
		||||
        {
 | 
			
		||||
            return Level.GetHashCode() ^ XpSettingsId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return 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()
 | 
			
		||||
        {
 | 
			
		||||
            return Level.GetHashCode() ^ XpSettingsId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return 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()
 | 
			
		||||
        {
 | 
			
		||||
            return ItemId.GetHashCode() ^ ItemType.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is ExcludedItem ei && ei.ItemId == ItemId && ei.ItemType == ItemType;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
{
 | 
			
		||||
    public class YtFollowedChannel : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong ChannelId { get; set; }
 | 
			
		||||
        public string YtChannelId { get; set; }
 | 
			
		||||
        public string UploadMessage { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										329
									
								
								src/NadekoBot/Services/Database/NadekoContext.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										329
									
								
								src/NadekoBot/Services/Database/NadekoContext.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,329 @@
 | 
			
		||||
using Microsoft.Data.Sqlite;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using Microsoft.EntityFrameworkCore.Design;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using NadekoBot.Core.Services.Impl;
 | 
			
		||||
using System;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database
 | 
			
		||||
{
 | 
			
		||||
    public class NadekoContextFactory : IDesignTimeDbContextFactory<NadekoContext>
 | 
			
		||||
    {
 | 
			
		||||
        public NadekoContext CreateDbContext(string[] args)
 | 
			
		||||
        {
 | 
			
		||||
            LogSetup.SetupLogger(-2);
 | 
			
		||||
            var optionsBuilder = new DbContextOptionsBuilder<NadekoContext>();
 | 
			
		||||
            IBotCredentials creds = new BotCredentials();
 | 
			
		||||
            var builder = new SqliteConnectionStringBuilder(creds.Db.ConnectionString);
 | 
			
		||||
            builder.DataSource = Path.Combine(AppContext.BaseDirectory, builder.DataSource);
 | 
			
		||||
            optionsBuilder.UseSqlite(builder.ToString());
 | 
			
		||||
            var ctx = new NadekoContext(optionsBuilder.Options);
 | 
			
		||||
            ctx.Database.SetCommandTimeout(60);
 | 
			
		||||
            return ctx;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class NadekoContext : 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<CustomReaction> CustomReactions { get; set; }
 | 
			
		||||
        public DbSet<CurrencyTransaction> CurrencyTransactions { get; set; }
 | 
			
		||||
        public DbSet<WaifuUpdate> WaifuUpdates { get; set; }
 | 
			
		||||
        public DbSet<Warning> Warnings { get; set; }
 | 
			
		||||
        public DbSet<UserXpStats> UserXpStats { get; set; }
 | 
			
		||||
        public DbSet<ClubInfo> Clubs { get; set; }
 | 
			
		||||
 | 
			
		||||
        //logging
 | 
			
		||||
        public DbSet<LogSetting> LogSettings { get; set; }
 | 
			
		||||
        public DbSet<IgnoredLogChannel> IgnoredLogChannels { get; set; }
 | 
			
		||||
        public DbSet<IgnoredVoicePresenceChannel> IgnoredVoicePresenceCHannels { 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<Stake> Stakes { 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 NadekoContext(DbContextOptions<NadekoContext> options) : base(options)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
#if DEBUG
 | 
			
		||||
        public static readonly LoggerFactory _debugLoggerFactory = 
 | 
			
		||||
            new LoggerFactory(new[] { 
 | 
			
		||||
                new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() 
 | 
			
		||||
            });
 | 
			
		||||
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
 | 
			
		||||
        {      
 | 
			
		||||
            optionsBuilder.UseLoggerFactory(_debugLoggerFactory);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        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();
 | 
			
		||||
 | 
			
		||||
            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 Permission
 | 
			
		||||
            var permissionEntity = modelBuilder.Entity<Permission>();
 | 
			
		||||
            permissionEntity
 | 
			
		||||
                .HasOne(p => p.Next)
 | 
			
		||||
                .WithOne(p => p.Previous)
 | 
			
		||||
                .IsRequired(false);
 | 
			
		||||
            #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);
 | 
			
		||||
 | 
			
		||||
            var wu = modelBuilder.Entity<WaifuUpdate>();
 | 
			
		||||
            #endregion
 | 
			
		||||
 | 
			
		||||
            #region DiscordUser
 | 
			
		||||
 | 
			
		||||
            var du = modelBuilder.Entity<DiscordUser>();
 | 
			
		||||
            du.HasAlternateKey(w => w.UserId);
 | 
			
		||||
            du.HasOne(x => x.Club)
 | 
			
		||||
               .WithMany(x => x.Users)
 | 
			
		||||
               .IsRequired(false);
 | 
			
		||||
 | 
			
		||||
            du.Property(x => x.LastLevelUp)
 | 
			
		||||
                .HasDefaultValue(new DateTime(2017, 9, 21, 20, 53, 13, 305, DateTimeKind.Local));
 | 
			
		||||
 | 
			
		||||
            du.HasIndex(x => x.TotalXp);
 | 
			
		||||
            du.HasIndex(x => x.CurrencyAmount);
 | 
			
		||||
            du.HasIndex(x => x.UserId);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            #endregion
 | 
			
		||||
 | 
			
		||||
            #region Warnings
 | 
			
		||||
            var warn = modelBuilder.Entity<Warning>();
 | 
			
		||||
            warn.HasIndex(x => x.GuildId);
 | 
			
		||||
            warn.HasIndex(x => x.UserId);
 | 
			
		||||
            warn.HasIndex(x => x.DateAdded);
 | 
			
		||||
            #endregion
 | 
			
		||||
 | 
			
		||||
            #region PatreonRewards
 | 
			
		||||
            var pr = modelBuilder.Entity<RewardedUser>();
 | 
			
		||||
            pr.HasIndex(x => x.PatreonUserId)
 | 
			
		||||
                .IsUnique();
 | 
			
		||||
            #endregion
 | 
			
		||||
 | 
			
		||||
            #region XpStats
 | 
			
		||||
            var xps = modelBuilder.Entity<UserXpStats>();
 | 
			
		||||
            xps
 | 
			
		||||
                .HasIndex(x => new { x.UserId, x.GuildId })
 | 
			
		||||
                .IsUnique();
 | 
			
		||||
 | 
			
		||||
            xps
 | 
			
		||||
                .Property(x => x.LastLevelUp)
 | 
			
		||||
                .HasDefaultValue(new DateTime(2017, 9, 21, 20, 53, 13, 307, DateTimeKind.Local));
 | 
			
		||||
 | 
			
		||||
            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);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            ci.HasAlternateKey(x => new { x.Name, x.Discrim });
 | 
			
		||||
            #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 Polls
 | 
			
		||||
            modelBuilder.Entity<Poll>()
 | 
			
		||||
                .HasIndex(x => x.GuildId)
 | 
			
		||||
                .IsUnique();
 | 
			
		||||
            #endregion
 | 
			
		||||
 | 
			
		||||
            #region CurrencyTransactions
 | 
			
		||||
            modelBuilder.Entity<CurrencyTransaction>()
 | 
			
		||||
                .HasIndex(x => x.UserId)
 | 
			
		||||
                .IsUnique(false);
 | 
			
		||||
            #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();
 | 
			
		||||
 | 
			
		||||
            #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
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database
 | 
			
		||||
{
 | 
			
		||||
    public static class CurrencyTransactionExtensions
 | 
			
		||||
    {
 | 
			
		||||
        public static List<CurrencyTransaction> GetPageFor(this DbSet<CurrencyTransaction> set, ulong userId, int page)
 | 
			
		||||
        {
 | 
			
		||||
            return set.AsQueryable()
 | 
			
		||||
                .AsNoTracking()
 | 
			
		||||
                .Where(x => x.UserId == userId)
 | 
			
		||||
                .OrderByDescending(x => x.DateAdded)
 | 
			
		||||
                .Skip(15 * page)
 | 
			
		||||
                .Take(15)
 | 
			
		||||
                .ToList();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,17 @@
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface IClubRepository : IRepository<ClubInfo>
 | 
			
		||||
    {
 | 
			
		||||
        int GetNextDiscrim(string clubName);
 | 
			
		||||
        ClubInfo GetByName(string v, int discrim, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null);
 | 
			
		||||
        ClubInfo GetByOwner(ulong userId, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null);
 | 
			
		||||
        ClubInfo GetByOwnerOrAdmin(ulong userId);
 | 
			
		||||
        ClubInfo GetByMember(ulong userId, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null);
 | 
			
		||||
        ClubInfo[] GetClubLeaderboardPage(int page);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,12 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface ICustomReactionRepository : IRepository<CustomReaction>
 | 
			
		||||
    {
 | 
			
		||||
        IEnumerable<CustomReaction> ForId(ulong id);
 | 
			
		||||
        int ClearFromGuild(ulong id);
 | 
			
		||||
        CustomReaction GetByGuildIdAndInput(ulong? guildId, string input);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Discord;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface IDiscordUserRepository : IRepository<DiscordUser>
 | 
			
		||||
    {
 | 
			
		||||
        void EnsureCreated(ulong userId, string username, string discrim, string avatarId);
 | 
			
		||||
        DiscordUser GetOrCreate(ulong userId, string username, string discrim, string avatarId);
 | 
			
		||||
        DiscordUser GetOrCreate(IUser original);
 | 
			
		||||
        int GetUserGlobalRank(ulong id);
 | 
			
		||||
        DiscordUser[] GetUsersXpLeaderboardFor(int page);
 | 
			
		||||
 | 
			
		||||
        long GetUserCurrency(ulong userId);
 | 
			
		||||
        bool TryUpdateCurrencyState(ulong userId, string name, string discrim, string avatar, long change, bool allowNegative = false);
 | 
			
		||||
        List<DiscordUser> GetTopRichest(ulong botId, int count, int page);
 | 
			
		||||
        List<DiscordUser> GetTopRichest(ulong botId, int count);
 | 
			
		||||
        void RemoveFromMany(IEnumerable<ulong> ids);
 | 
			
		||||
        decimal GetTotalCurrency();
 | 
			
		||||
        decimal GetTopOnePercentCurrency(ulong botId);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface IGuildConfigRepository : IRepository<GuildConfig>
 | 
			
		||||
    {
 | 
			
		||||
        GuildConfig ForId(ulong guildId, Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes = null);
 | 
			
		||||
        GuildConfig LogSettingsFor(ulong guildId);
 | 
			
		||||
        IEnumerable<GuildConfig> GetAllGuildConfigs(List<ulong> availableGuilds);
 | 
			
		||||
        IEnumerable<FollowedStream> GetFollowedStreams(List<ulong> included);
 | 
			
		||||
        IEnumerable<FollowedStream> GetFollowedStreams();
 | 
			
		||||
        void SetCleverbotEnabled(ulong id, bool cleverbotEnabled);
 | 
			
		||||
        IEnumerable<GuildConfig> Permissionsv2ForAll(List<ulong> include);
 | 
			
		||||
        GuildConfig GcWithPermissionsv2For(ulong guildId);
 | 
			
		||||
        XpSettings XpSettingsFor(ulong guildId);
 | 
			
		||||
        IEnumerable<GeneratingChannel> GetGeneratingChannels();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class GeneratingChannel
 | 
			
		||||
    {
 | 
			
		||||
        public ulong GuildId { get; set; }
 | 
			
		||||
        public ulong ChannelId { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,11 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface IMusicPlaylistRepository : IRepository<MusicPlaylist>
 | 
			
		||||
    {
 | 
			
		||||
        List<MusicPlaylist> GetPlaylistsOnPage(int num);
 | 
			
		||||
        MusicPlaylist GetWithSongs(int id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface IPlantedCurrencyRepository : IRepository<PlantedCurrency>
 | 
			
		||||
    {
 | 
			
		||||
        (long Sum, ulong[] MessageIds) RemoveSumAndGetMessageIdsFor(ulong cid, string pass);
 | 
			
		||||
        decimal GetTotalPlanted();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,11 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface IPollsRepository : IRepository<Poll>
 | 
			
		||||
    {
 | 
			
		||||
        IEnumerable<Poll> GetAllPolls();
 | 
			
		||||
        void RemovePoll(int id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface IQuoteRepository : IRepository<Quote>
 | 
			
		||||
    {
 | 
			
		||||
        Task<Quote> GetRandomQuoteByKeywordAsync(ulong guildId, string keyword);
 | 
			
		||||
        Task<Quote> SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text);
 | 
			
		||||
        IEnumerable<Quote> GetGroup(ulong guildId, int page, OrderType order);
 | 
			
		||||
        void RemoveAllByKeyword(ulong guildId, string keyword);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,11 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface IReminderRepository : IRepository<Reminder>
 | 
			
		||||
    {
 | 
			
		||||
        IEnumerable<Reminder> GetIncludedReminders(IEnumerable<ulong> guildIds);
 | 
			
		||||
        IEnumerable<Reminder> RemindersFor(ulong userId, int page);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								src/NadekoBot/Services/Database/Repositories/IRepository.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/NadekoBot/Services/Database/Repositories/IRepository.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface IRepository<T> where T : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        T GetById(int id);
 | 
			
		||||
        IEnumerable<T> GetAll();
 | 
			
		||||
 | 
			
		||||
        void Add(T obj);
 | 
			
		||||
        void AddRange(params T[] objs);
 | 
			
		||||
 | 
			
		||||
        void Remove(int id);
 | 
			
		||||
        void Remove(T obj);
 | 
			
		||||
        void RemoveRange(params T[] objs);
 | 
			
		||||
 | 
			
		||||
        void Update(T obj);
 | 
			
		||||
        void UpdateRange(params T[] objs);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,11 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface ISelfAssignedRolesRepository : IRepository<SelfAssignedRole>
 | 
			
		||||
    {
 | 
			
		||||
        bool DeleteByGuildAndRoleId(ulong guildId, ulong roleId);
 | 
			
		||||
        IEnumerable<SelfAssignedRole> GetFromGuild(ulong guildId);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface IWaifuRepository : IRepository<WaifuInfo>
 | 
			
		||||
    {
 | 
			
		||||
        IEnumerable<WaifuLbResult> GetTop(int count, int skip = 0);
 | 
			
		||||
        WaifuInfo ByWaifuUserId(ulong userId, Func<DbSet<WaifuInfo>, IQueryable<WaifuInfo>> includes = null);
 | 
			
		||||
        IEnumerable<string> GetWaifuNames(ulong userId);
 | 
			
		||||
        decimal GetTotalValue();
 | 
			
		||||
        int AffinityCount(ulong userId);
 | 
			
		||||
        WaifuInfoStats GetWaifuInfo(ulong id);
 | 
			
		||||
        public ulong GetWaifuUserId(ulong ownerId, string name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class WaifuInfoStats
 | 
			
		||||
    {
 | 
			
		||||
        public string FullName { get; set; }
 | 
			
		||||
        public int Price { get; set; }
 | 
			
		||||
        public string ClaimerName { get; set; }
 | 
			
		||||
        public string AffinityName { get; set; }
 | 
			
		||||
        public int AffinityCount { get; set; }
 | 
			
		||||
        public int DivorceCount { get; set; }
 | 
			
		||||
        public int ClaimCount { get; set; }
 | 
			
		||||
        public List<WaifuItem> Items { get; set; }
 | 
			
		||||
        public List<string> Claims { get; set; }
 | 
			
		||||
        public List<string> Fans { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,13 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface IWarningsRepository : IRepository<Warning>
 | 
			
		||||
    {
 | 
			
		||||
        Warning[] ForId(ulong guildId, ulong userId);
 | 
			
		||||
        Task ForgiveAll(ulong guildId, ulong userId, string moderator);
 | 
			
		||||
        bool Forgive(ulong guildId, ulong userId, string moderator, int index);
 | 
			
		||||
        Warning[] GetForGuild(ulong id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories
 | 
			
		||||
{
 | 
			
		||||
    public interface IXpRepository : IRepository<UserXpStats>
 | 
			
		||||
    {
 | 
			
		||||
        UserXpStats GetOrCreateUser(ulong guildId, ulong userId);
 | 
			
		||||
        int GetUserGuildRanking(ulong userId, ulong guildId);
 | 
			
		||||
        List<UserXpStats> GetUsersFor(ulong guildId, int page);
 | 
			
		||||
        void ResetGuildUserXp(ulong userId, ulong guildId);
 | 
			
		||||
        void ResetGuildXp(ulong guildId);
 | 
			
		||||
        List<UserXpStats> GetTopUserXps(ulong guildId, int count);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,96 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public class ClubRepository : Repository<ClubInfo>, IClubRepository
 | 
			
		||||
    {
 | 
			
		||||
        public ClubRepository(DbContext context) : base(context)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ClubInfo GetByOwner(ulong userId, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null)
 | 
			
		||||
        {
 | 
			
		||||
            if (func == null)
 | 
			
		||||
                return _set
 | 
			
		||||
                    .Include(x => x.Bans)
 | 
			
		||||
                    .Include(x => x.Applicants)
 | 
			
		||||
                    .Include(x => x.Users)
 | 
			
		||||
                    .Include(x => x.Owner)
 | 
			
		||||
                    .FirstOrDefault(x => x.Owner.UserId == userId);
 | 
			
		||||
 | 
			
		||||
            return func(_set).FirstOrDefault(x => x.Owner.UserId == userId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ClubInfo GetByOwnerOrAdmin(ulong userId)
 | 
			
		||||
        {
 | 
			
		||||
            return _set
 | 
			
		||||
                .Include(x => x.Bans)
 | 
			
		||||
                    .ThenInclude(x => x.User)
 | 
			
		||||
                .Include(x => x.Applicants)
 | 
			
		||||
                    .ThenInclude(x => x.User)
 | 
			
		||||
                .Include(x => x.Owner)
 | 
			
		||||
                .Include(x => x.Users)
 | 
			
		||||
                .FirstOrDefault(x => x.Owner.UserId == userId) ??
 | 
			
		||||
            _context.Set<DiscordUser>()
 | 
			
		||||
                .Include(x => x.Club)
 | 
			
		||||
                    .ThenInclude(x => x.Users)
 | 
			
		||||
                .Include(x => x.Club)
 | 
			
		||||
                    .ThenInclude(x => x.Bans)
 | 
			
		||||
                        .ThenInclude(x => x.User)
 | 
			
		||||
                .Include(x => x.Club)
 | 
			
		||||
                    .ThenInclude(x => x.Applicants)
 | 
			
		||||
                        .ThenInclude(x => x.User)
 | 
			
		||||
                .Include(x => x.Club)
 | 
			
		||||
                .ThenInclude(x => x.Owner)
 | 
			
		||||
                .FirstOrDefault(x => x.UserId == userId && x.IsClubAdmin)
 | 
			
		||||
                ?.Club;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ClubInfo GetByName(string name, int discrim, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null)
 | 
			
		||||
        {
 | 
			
		||||
            if (func == null)
 | 
			
		||||
                return _set.AsQueryable()
 | 
			
		||||
                    .Where(x => x.Name == name && x.Discrim == discrim)
 | 
			
		||||
                    .Include(x => x.Users)
 | 
			
		||||
                    .Include(x => x.Bans)
 | 
			
		||||
                    .Include(x => x.Applicants)
 | 
			
		||||
                    .FirstOrDefault();
 | 
			
		||||
 | 
			
		||||
            return func(_set).FirstOrDefault(x => x.Name == name && x.Discrim == discrim);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int GetNextDiscrim(string clubName)
 | 
			
		||||
        {
 | 
			
		||||
            return _set.AsQueryable()
 | 
			
		||||
                .Where(x => x.Name.ToUpper() == clubName.ToUpper())
 | 
			
		||||
                .Select(x => x.Discrim)
 | 
			
		||||
                .ToList()
 | 
			
		||||
                .DefaultIfEmpty()
 | 
			
		||||
                .Max() + 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ClubInfo GetByMember(ulong userId, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null)
 | 
			
		||||
        {
 | 
			
		||||
            if (func == null)
 | 
			
		||||
                return _set
 | 
			
		||||
                    .Include(x => x.Users)
 | 
			
		||||
                    .Include(x => x.Bans)
 | 
			
		||||
                    .Include(x => x.Applicants)
 | 
			
		||||
                    .FirstOrDefault(x => x.Users.Any(y => y.UserId == userId));
 | 
			
		||||
 | 
			
		||||
            return func(_set).FirstOrDefault(x => x.Users.Any(y => y.UserId == userId));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ClubInfo[] GetClubLeaderboardPage(int page)
 | 
			
		||||
        {
 | 
			
		||||
            return _set.AsQueryable()
 | 
			
		||||
                .OrderByDescending(x => x.Xp)
 | 
			
		||||
                .Skip(page * 9)
 | 
			
		||||
                .Take(9)
 | 
			
		||||
                .ToArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public class CustomReactionsRepository : Repository<CustomReaction>, ICustomReactionRepository
 | 
			
		||||
    {
 | 
			
		||||
        public CustomReactionsRepository(DbContext context) : base(context)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int ClearFromGuild(ulong id)
 | 
			
		||||
        {
 | 
			
		||||
            return _context.Database.ExecuteSqlInterpolated($"DELETE FROM CustomReactions WHERE GuildId={id};");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<CustomReaction> ForId(ulong id)
 | 
			
		||||
        {
 | 
			
		||||
            return _set
 | 
			
		||||
                .AsNoTracking()
 | 
			
		||||
                .AsQueryable()
 | 
			
		||||
                .Where(x => x.GuildId == id)
 | 
			
		||||
                .ToArray();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public CustomReaction GetByGuildIdAndInput(ulong? guildId, string input)
 | 
			
		||||
        {
 | 
			
		||||
            return _set.FirstOrDefault(x => x.GuildId == guildId && x.Trigger.ToUpper() == input);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,180 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using Discord;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public class DiscordUserRepository : Repository<DiscordUser>, IDiscordUserRepository
 | 
			
		||||
    {
 | 
			
		||||
        public DiscordUserRepository(DbContext context) : base(context)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void EnsureCreated(ulong userId, string username, string discrim, string avatarId)
 | 
			
		||||
        {
 | 
			
		||||
            _context.Database.ExecuteSqlInterpolated($@"
 | 
			
		||||
UPDATE OR IGNORE DiscordUser
 | 
			
		||||
SET Username={username},
 | 
			
		||||
    Discriminator={discrim},
 | 
			
		||||
    AvatarId={avatarId}
 | 
			
		||||
WHERE UserId={userId};
 | 
			
		||||
 | 
			
		||||
INSERT OR IGNORE INTO DiscordUser (UserId, Username, Discriminator, AvatarId)
 | 
			
		||||
VALUES ({userId}, {username}, {discrim}, {avatarId});
 | 
			
		||||
");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //temp is only used in updatecurrencystate, so that i don't overwrite real usernames/discrims with Unknown
 | 
			
		||||
        public DiscordUser GetOrCreate(ulong userId, string username, string discrim, string avatarId)
 | 
			
		||||
        {
 | 
			
		||||
            EnsureCreated(userId, username, discrim, avatarId);
 | 
			
		||||
            return _set
 | 
			
		||||
                .Include(x => x.Club)
 | 
			
		||||
                .First(u => u.UserId == userId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public DiscordUser GetOrCreate(IUser original)
 | 
			
		||||
            => GetOrCreate(original.Id, original.Username, original.Discriminator, original.AvatarId);
 | 
			
		||||
 | 
			
		||||
        public int GetUserGlobalRank(ulong id)
 | 
			
		||||
        {
 | 
			
		||||
            //            @"SELECT COUNT(*) + 1
 | 
			
		||||
            //FROM DiscordUser
 | 
			
		||||
            //WHERE TotalXp > COALESCE((SELECT TotalXp
 | 
			
		||||
            //    FROM DiscordUser
 | 
			
		||||
            //    WHERE UserId = @p1
 | 
			
		||||
            //    LIMIT 1), 0);"
 | 
			
		||||
            return _set.AsQueryable()
 | 
			
		||||
                .Where(x => x.TotalXp > (_set
 | 
			
		||||
                    .AsQueryable()
 | 
			
		||||
                    .Where(y => y.UserId == id)
 | 
			
		||||
                    .Select(y => y.TotalXp)
 | 
			
		||||
                    .FirstOrDefault()))
 | 
			
		||||
                .Count() + 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public DiscordUser[] GetUsersXpLeaderboardFor(int page)
 | 
			
		||||
        {
 | 
			
		||||
            return _set.AsQueryable()
 | 
			
		||||
                .OrderByDescending(x => x.TotalXp)
 | 
			
		||||
                .Skip(page * 9)
 | 
			
		||||
                .Take(9)
 | 
			
		||||
                .AsEnumerable()
 | 
			
		||||
                .ToArray();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<DiscordUser> GetTopRichest(ulong botId, int count, int page = 0)
 | 
			
		||||
        {
 | 
			
		||||
            return _set.AsQueryable()
 | 
			
		||||
                .Where(c => c.CurrencyAmount > 0 && botId != c.UserId)
 | 
			
		||||
                .OrderByDescending(c => c.CurrencyAmount)
 | 
			
		||||
                .Skip(page * 9)
 | 
			
		||||
                .Take(count)
 | 
			
		||||
                .ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<DiscordUser> GetTopRichest(ulong botId, int count)
 | 
			
		||||
        {
 | 
			
		||||
            return _set.AsQueryable()
 | 
			
		||||
                .Where(c => c.CurrencyAmount > 0 && botId != c.UserId)
 | 
			
		||||
                .OrderByDescending(c => c.CurrencyAmount)
 | 
			
		||||
                .Take(count)
 | 
			
		||||
                .ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public long GetUserCurrency(ulong userId) =>
 | 
			
		||||
            _set.AsNoTracking()
 | 
			
		||||
                .FirstOrDefault(x => x.UserId == userId)
 | 
			
		||||
                ?.CurrencyAmount ?? 0;
 | 
			
		||||
 | 
			
		||||
        public void RemoveFromMany(IEnumerable<ulong> ids)
 | 
			
		||||
        {
 | 
			
		||||
            var items = _set.AsQueryable().Where(x => ids.Contains(x.UserId));
 | 
			
		||||
            foreach (var item in items)
 | 
			
		||||
            {
 | 
			
		||||
                item.CurrencyAmount = 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool TryUpdateCurrencyState(ulong userId, string name, string discrim, string avatarId, long amount, bool allowNegative = false)
 | 
			
		||||
        {
 | 
			
		||||
            if (amount == 0)
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
            // if remove - try to remove if he has more or equal than the amount
 | 
			
		||||
            // and return number of rows > 0 (was there a change)
 | 
			
		||||
            if (amount < 0 && !allowNegative)
 | 
			
		||||
            {
 | 
			
		||||
                var rows = _context.Database.ExecuteSqlInterpolated($@"
 | 
			
		||||
UPDATE DiscordUser
 | 
			
		||||
SET CurrencyAmount=CurrencyAmount+{amount}
 | 
			
		||||
WHERE UserId={userId} AND CurrencyAmount>={-amount};");
 | 
			
		||||
                return rows > 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // if remove and negative is allowed, just remove without any condition
 | 
			
		||||
            if (amount < 0 && allowNegative)
 | 
			
		||||
            {
 | 
			
		||||
                var rows = _context.Database.ExecuteSqlInterpolated($@"
 | 
			
		||||
UPDATE DiscordUser
 | 
			
		||||
SET CurrencyAmount=CurrencyAmount+{amount}
 | 
			
		||||
WHERE UserId={userId};");
 | 
			
		||||
                return rows > 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // if add - create a new user with default values if it doesn't exist
 | 
			
		||||
            // if it exists, sum current amount with the new one, if it doesn't
 | 
			
		||||
            // he just has the new amount
 | 
			
		||||
            var updatedUserData = !string.IsNullOrWhiteSpace(name);
 | 
			
		||||
            name = name ?? "Unknown";
 | 
			
		||||
            discrim = discrim ?? "????";
 | 
			
		||||
            avatarId = avatarId ?? "";
 | 
			
		||||
 | 
			
		||||
            // just update the amount, there is no new user data
 | 
			
		||||
            if (!updatedUserData)
 | 
			
		||||
            {
 | 
			
		||||
                _context.Database.ExecuteSqlInterpolated($@"
 | 
			
		||||
UPDATE OR IGNORE DiscordUser
 | 
			
		||||
SET CurrencyAmount=CurrencyAmount+{amount}
 | 
			
		||||
WHERE UserId={userId};
 | 
			
		||||
 | 
			
		||||
INSERT OR IGNORE INTO DiscordUser (UserId, Username, Discriminator, AvatarId, CurrencyAmount)
 | 
			
		||||
VALUES ({userId}, {name}, {discrim}, {avatarId}, {amount});
 | 
			
		||||
");
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _context.Database.ExecuteSqlInterpolated($@"
 | 
			
		||||
UPDATE OR IGNORE DiscordUser
 | 
			
		||||
SET CurrencyAmount=CurrencyAmount+{amount},
 | 
			
		||||
    Username={name},
 | 
			
		||||
    Discriminator={discrim},
 | 
			
		||||
    AvatarId={avatarId}
 | 
			
		||||
WHERE UserId={userId};
 | 
			
		||||
 | 
			
		||||
INSERT OR IGNORE INTO DiscordUser (UserId, Username, Discriminator, AvatarId, CurrencyAmount)
 | 
			
		||||
VALUES ({userId}, {name}, {discrim}, {avatarId}, {amount});
 | 
			
		||||
");
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public decimal GetTotalCurrency()
 | 
			
		||||
        {
 | 
			
		||||
            return _set
 | 
			
		||||
                .Sum(x => x.CurrencyAmount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public decimal GetTopOnePercentCurrency(ulong botId)
 | 
			
		||||
        {
 | 
			
		||||
            return _set.AsQueryable()
 | 
			
		||||
                .Where(x => x.UserId != botId)
 | 
			
		||||
                .OrderByDescending(x => x.CurrencyAmount)
 | 
			
		||||
                .Take(_set.Count() / 100 == 0 ? 1 : _set.Count() / 100)
 | 
			
		||||
                .Sum(x => x.CurrencyAmount);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,237 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public static class MusicPlayerSettingsExtensions
 | 
			
		||||
    {
 | 
			
		||||
        public static async Task<MusicPlayerSettings> ForGuildAsync(this DbSet<MusicPlayerSettings> settings, ulong guildId)
 | 
			
		||||
        {
 | 
			
		||||
            var toReturn = await settings
 | 
			
		||||
                .AsQueryable()
 | 
			
		||||
                .FirstOrDefaultAsync(x => x.GuildId == guildId);
 | 
			
		||||
 | 
			
		||||
            if (toReturn is null)
 | 
			
		||||
            {
 | 
			
		||||
                var newSettings = new MusicPlayerSettings()
 | 
			
		||||
                {
 | 
			
		||||
                    GuildId = guildId,
 | 
			
		||||
                    PlayerRepeat = PlayerRepeatType.Queue
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                await settings.AddAsync(newSettings);
 | 
			
		||||
                return newSettings;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return toReturn;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public class GuildConfigRepository : Repository<GuildConfig>, IGuildConfigRepository
 | 
			
		||||
    {
 | 
			
		||||
        public GuildConfigRepository(DbContext context) : base(context)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private List<WarningPunishment> DefaultWarnPunishments =>
 | 
			
		||||
            new List<WarningPunishment>() {
 | 
			
		||||
                new WarningPunishment() {
 | 
			
		||||
                    Count = 3,
 | 
			
		||||
                    Punishment = PunishmentAction.Kick
 | 
			
		||||
                },
 | 
			
		||||
                new WarningPunishment() {
 | 
			
		||||
                    Count = 5,
 | 
			
		||||
                    Punishment = PunishmentAction.Ban
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<GuildConfig> GetAllGuildConfigs(List<ulong> availableGuilds) =>
 | 
			
		||||
            IncludeEverything()
 | 
			
		||||
                .AsNoTracking()
 | 
			
		||||
                .Where(x => availableGuilds.Contains(x.GuildId))
 | 
			
		||||
                .ToList();
 | 
			
		||||
 | 
			
		||||
        private IQueryable<GuildConfig> IncludeEverything()
 | 
			
		||||
        {
 | 
			
		||||
            return _set
 | 
			
		||||
                .AsQueryable()
 | 
			
		||||
                .Include(gc => gc.CommandCooldowns)
 | 
			
		||||
                .Include(gc => gc.FollowedStreams)
 | 
			
		||||
                .Include(gc => gc.StreamRole)
 | 
			
		||||
                .Include(gc => gc.NsfwBlacklistedTags)
 | 
			
		||||
                .Include(gc => gc.XpSettings)
 | 
			
		||||
                    .ThenInclude(x => x.ExclusionList)
 | 
			
		||||
                .Include(gc => gc.DelMsgOnCmdChannels)
 | 
			
		||||
                .Include(gc => gc.ReactionRoleMessages)
 | 
			
		||||
                    .ThenInclude(x => x.ReactionRoles)
 | 
			
		||||
                ;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets and creates if it doesn't exist a config for a guild.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="guildId">For which guild</param>
 | 
			
		||||
        /// <param name="includes">Use to manipulate the set however you want</param>
 | 
			
		||||
        /// <returns>Config for the guild</returns>
 | 
			
		||||
        public GuildConfig ForId(ulong guildId, Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes)
 | 
			
		||||
        {
 | 
			
		||||
            GuildConfig config;
 | 
			
		||||
 | 
			
		||||
            if (includes == null)
 | 
			
		||||
            {
 | 
			
		||||
                config = IncludeEverything()
 | 
			
		||||
                    .FirstOrDefault(c => c.GuildId == guildId);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var set = includes(_set);
 | 
			
		||||
                config = set.FirstOrDefault(c => c.GuildId == guildId);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (config == null)
 | 
			
		||||
            {
 | 
			
		||||
                _set.Add((config = new GuildConfig
 | 
			
		||||
                {
 | 
			
		||||
                    GuildId = guildId,
 | 
			
		||||
                    Permissions = Permissionv2.GetDefaultPermlist,
 | 
			
		||||
                    WarningsInitialized = true,
 | 
			
		||||
                    WarnPunishments = DefaultWarnPunishments,
 | 
			
		||||
                }));
 | 
			
		||||
                _context.SaveChanges();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!config.WarningsInitialized)
 | 
			
		||||
            {
 | 
			
		||||
                config.WarningsInitialized = true;
 | 
			
		||||
                config.WarnPunishments = DefaultWarnPunishments;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return config;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public GuildConfig LogSettingsFor(ulong guildId)
 | 
			
		||||
        {
 | 
			
		||||
            var config = _set
 | 
			
		||||
                .AsQueryable()
 | 
			
		||||
                .Include(gc => gc.LogSetting)
 | 
			
		||||
                    .ThenInclude(gc => gc.IgnoredChannels)
 | 
			
		||||
                .FirstOrDefault(x => x.GuildId == guildId);
 | 
			
		||||
 | 
			
		||||
            if (config == null)
 | 
			
		||||
            {
 | 
			
		||||
                _set.Add((config = new GuildConfig
 | 
			
		||||
                {
 | 
			
		||||
                    GuildId = guildId,
 | 
			
		||||
                    Permissions = Permissionv2.GetDefaultPermlist,
 | 
			
		||||
                    WarningsInitialized = true,
 | 
			
		||||
                    WarnPunishments = DefaultWarnPunishments,
 | 
			
		||||
                }));
 | 
			
		||||
                _context.SaveChanges();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!config.WarningsInitialized)
 | 
			
		||||
            {
 | 
			
		||||
                config.WarningsInitialized = true;
 | 
			
		||||
                config.WarnPunishments = DefaultWarnPunishments;
 | 
			
		||||
            }
 | 
			
		||||
            return config;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<GuildConfig> Permissionsv2ForAll(List<ulong> include)
 | 
			
		||||
        {
 | 
			
		||||
            var query = _set.AsQueryable()
 | 
			
		||||
                .Where(x => include.Contains(x.GuildId))
 | 
			
		||||
                .Include(gc => gc.Permissions);
 | 
			
		||||
 | 
			
		||||
            return query.ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public GuildConfig GcWithPermissionsv2For(ulong guildId)
 | 
			
		||||
        {
 | 
			
		||||
            var config = _set.AsQueryable()
 | 
			
		||||
                .Where(gc => gc.GuildId == guildId)
 | 
			
		||||
                .Include(gc => gc.Permissions)
 | 
			
		||||
                .FirstOrDefault();
 | 
			
		||||
 | 
			
		||||
            if (config == null) // if there is no guildconfig, create new one
 | 
			
		||||
            {
 | 
			
		||||
                _set.Add((config = new GuildConfig
 | 
			
		||||
                {
 | 
			
		||||
                    GuildId = guildId,
 | 
			
		||||
                    Permissions = Permissionv2.GetDefaultPermlist
 | 
			
		||||
                }));
 | 
			
		||||
                _context.SaveChanges();
 | 
			
		||||
            }
 | 
			
		||||
            else if (config.Permissions == null || !config.Permissions.Any()) // if no perms, add default ones
 | 
			
		||||
            {
 | 
			
		||||
                config.Permissions = Permissionv2.GetDefaultPermlist;
 | 
			
		||||
                _context.SaveChanges();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return config;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<FollowedStream> GetFollowedStreams()
 | 
			
		||||
        {
 | 
			
		||||
            return _set
 | 
			
		||||
                .AsQueryable()
 | 
			
		||||
                .Include(x => x.FollowedStreams)
 | 
			
		||||
                .SelectMany(gc => gc.FollowedStreams)
 | 
			
		||||
                .ToArray();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<FollowedStream> GetFollowedStreams(List<ulong> included)
 | 
			
		||||
        {
 | 
			
		||||
            return _set.AsQueryable()
 | 
			
		||||
                .Where(gc => included.Contains(gc.GuildId))
 | 
			
		||||
                .Include(gc => gc.FollowedStreams)
 | 
			
		||||
                .SelectMany(gc => gc.FollowedStreams)
 | 
			
		||||
                .ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetCleverbotEnabled(ulong id, bool cleverbotEnabled)
 | 
			
		||||
        {
 | 
			
		||||
            var conf = _set.FirstOrDefault(gc => gc.GuildId == id);
 | 
			
		||||
 | 
			
		||||
            if (conf == null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            conf.CleverbotEnabled = cleverbotEnabled;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public XpSettings XpSettingsFor(ulong guildId)
 | 
			
		||||
        {
 | 
			
		||||
            var gc = ForId(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 == null)
 | 
			
		||||
                gc.XpSettings = new XpSettings();
 | 
			
		||||
 | 
			
		||||
            return gc.XpSettings;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<GeneratingChannel> GetGeneratingChannels()
 | 
			
		||||
        {
 | 
			
		||||
            return _set
 | 
			
		||||
                .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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public class MusicPlaylistRepository : Repository<MusicPlaylist>, IMusicPlaylistRepository
 | 
			
		||||
    {
 | 
			
		||||
        public MusicPlaylistRepository(DbContext context) : base(context)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<MusicPlaylist> GetPlaylistsOnPage(int num)
 | 
			
		||||
        {
 | 
			
		||||
            if (num < 1)
 | 
			
		||||
                throw new IndexOutOfRangeException();
 | 
			
		||||
 | 
			
		||||
            return _set.AsQueryable()
 | 
			
		||||
                .Skip((num - 1) * 20)
 | 
			
		||||
                .Take(20)
 | 
			
		||||
                .Include(pl => pl.Songs)
 | 
			
		||||
                .ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public MusicPlaylist GetWithSongs(int id) => 
 | 
			
		||||
            _set.Include(mpl => mpl.Songs)
 | 
			
		||||
                .FirstOrDefault(mpl => mpl.Id == id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public class PlantedCurrencyRepository : Repository<PlantedCurrency>, IPlantedCurrencyRepository
 | 
			
		||||
    {
 | 
			
		||||
        public PlantedCurrencyRepository(DbContext context) : base(context)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public decimal GetTotalPlanted()
 | 
			
		||||
        {
 | 
			
		||||
            return _set.Sum(x => x.Amount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public (long Sum, ulong[] MessageIds) RemoveSumAndGetMessageIdsFor(ulong cid, string pass = null)
 | 
			
		||||
        {
 | 
			
		||||
            pass = pass?.Trim().TrimTo(10, hideDots: true).ToUpperInvariant();
 | 
			
		||||
            // gets all plants in this channel with the same password
 | 
			
		||||
            var entries = _set.AsQueryable().Where(x => x.ChannelId == cid && pass == x.Password).ToArray();
 | 
			
		||||
            // sum how much currency that is, and get all of the message ids (so that i can delete them)
 | 
			
		||||
            var toReturn = (entries.Sum(x => x.Amount), entries.Select(x => x.MessageId).ToArray());
 | 
			
		||||
            // remove them from the database
 | 
			
		||||
            _set.RemoveRange(entries);
 | 
			
		||||
 | 
			
		||||
            return toReturn;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public class PollsRepository : Repository<Poll>, IPollsRepository
 | 
			
		||||
    {
 | 
			
		||||
        public PollsRepository(DbContext context) : base(context)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<Poll> GetAllPolls()
 | 
			
		||||
        {
 | 
			
		||||
            return _set.Include(x => x.Answers)
 | 
			
		||||
                .Include(x => x.Votes)
 | 
			
		||||
                .ToArray();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void RemovePoll(int id)
 | 
			
		||||
        {
 | 
			
		||||
            var p = _set
 | 
			
		||||
                .Include(x => x.Answers)
 | 
			
		||||
                .Include(x => x.Votes)
 | 
			
		||||
                .FirstOrDefault(x => x.Id == id);
 | 
			
		||||
 | 
			
		||||
            if (p is null)
 | 
			
		||||
                return;
 | 
			
		||||
            
 | 
			
		||||
            if (p.Votes != null)
 | 
			
		||||
            {
 | 
			
		||||
                _context.Set<PollVote>().RemoveRange(p.Votes);
 | 
			
		||||
                p.Votes.Clear();
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (p.Answers != null)
 | 
			
		||||
            {
 | 
			
		||||
                _context.Set<PollAnswer>().RemoveRange(p.Answers);
 | 
			
		||||
                p.Answers.Clear();
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            _set.Remove(p);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,57 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using NadekoBot.Common;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public class QuoteRepository : Repository<Quote>, IQuoteRepository
 | 
			
		||||
    {
 | 
			
		||||
        public QuoteRepository(DbContext context) : base(context)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<Quote> GetGroup(ulong guildId, int page, OrderType order)
 | 
			
		||||
        {
 | 
			
		||||
            var q = _set.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 async Task<Quote> GetRandomQuoteByKeywordAsync(ulong guildId, string keyword)
 | 
			
		||||
        {
 | 
			
		||||
            var rng = new NadekoRandom();
 | 
			
		||||
            return (await _set.AsQueryable()
 | 
			
		||||
                .Where(q => q.GuildId == guildId && q.Keyword == keyword)
 | 
			
		||||
                .ToListAsync())
 | 
			
		||||
                .OrderBy(q => rng.Next())
 | 
			
		||||
                .FirstOrDefault();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Quote> SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text)
 | 
			
		||||
        {
 | 
			
		||||
            var rngk = new NadekoRandom();
 | 
			
		||||
            return (await _set.AsQueryable()
 | 
			
		||||
                .Where(q => q.GuildId == guildId
 | 
			
		||||
                            && q.Keyword == keyword
 | 
			
		||||
                            && EF.Functions.Like(q.Text.ToUpper(), $"%{text.ToUpper()}%")
 | 
			
		||||
                            // && q.Text.Contains(text, StringComparison.OrdinalIgnoreCase)
 | 
			
		||||
                            )
 | 
			
		||||
                .ToListAsync())
 | 
			
		||||
                .OrderBy(q => rngk.Next())
 | 
			
		||||
                .FirstOrDefault();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void RemoveAllByKeyword(ulong guildId, string keyword)
 | 
			
		||||
        {
 | 
			
		||||
            _set.RemoveRange(_set.AsQueryable().Where(x => x.GuildId == guildId && x.Keyword.ToUpper() == keyword));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public class ReminderRepository : Repository<Reminder>, IReminderRepository
 | 
			
		||||
    {
 | 
			
		||||
        public ReminderRepository(DbContext context) : base(context)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<Reminder> GetIncludedReminders(IEnumerable<ulong> guildIds)
 | 
			
		||||
        {
 | 
			
		||||
            return _set.AsQueryable().Where(x => guildIds.Contains(x.ServerId) || x.ServerId == 0).ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<Reminder> RemindersFor(ulong userId, int page)
 | 
			
		||||
        {
 | 
			
		||||
            return _set.AsQueryable()
 | 
			
		||||
                .Where(x => x.UserId == userId)
 | 
			
		||||
                .OrderBy(x => x.DateAdded)
 | 
			
		||||
                .Skip(page * 10)
 | 
			
		||||
                .Take(10);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public abstract class Repository<T> : IRepository<T> where T : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        protected DbContext _context { get; set; }
 | 
			
		||||
        protected DbSet<T> _set { get; set; }
 | 
			
		||||
 | 
			
		||||
        public Repository(DbContext context)
 | 
			
		||||
        {
 | 
			
		||||
            _context = context;
 | 
			
		||||
            _set = context.Set<T>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Add(T obj) =>
 | 
			
		||||
            _set.Add(obj);
 | 
			
		||||
 | 
			
		||||
        public void AddRange(params T[] objs) =>
 | 
			
		||||
            _set.AddRange(objs);
 | 
			
		||||
 | 
			
		||||
        public T GetById(int id) =>
 | 
			
		||||
            _set.FirstOrDefault(e => e.Id == id);
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<T> GetAll() =>
 | 
			
		||||
            _set.ToList();
 | 
			
		||||
 | 
			
		||||
        public void Remove(int id) =>
 | 
			
		||||
            _set.Remove(this.GetById(id));
 | 
			
		||||
 | 
			
		||||
        public void Remove(T obj) =>
 | 
			
		||||
            _set.Remove(obj);
 | 
			
		||||
 | 
			
		||||
        public void RemoveRange(params T[] objs) =>
 | 
			
		||||
            _set.RemoveRange(objs);
 | 
			
		||||
 | 
			
		||||
        public void Update(T obj) =>
 | 
			
		||||
            _set.Update(obj);
 | 
			
		||||
 | 
			
		||||
        public void UpdateRange(params T[] objs) =>
 | 
			
		||||
            _set.UpdateRange(objs);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,30 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public class SelfAssignedRolesRepository : Repository<SelfAssignedRole>, ISelfAssignedRolesRepository
 | 
			
		||||
    {
 | 
			
		||||
        public SelfAssignedRolesRepository(DbContext context) : base(context)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool DeleteByGuildAndRoleId(ulong guildId, ulong roleId)
 | 
			
		||||
        {
 | 
			
		||||
            var role = _set.FirstOrDefault(s => s.GuildId == guildId && s.RoleId == roleId);
 | 
			
		||||
 | 
			
		||||
            if (role == null)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            _set.Remove(role);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<SelfAssignedRole> GetFromGuild(ulong guildId) 
 | 
			
		||||
            =>  _set.AsQueryable()
 | 
			
		||||
                    .Where(s => s.GuildId == guildId)
 | 
			
		||||
                    .ToArray();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,193 @@
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public class WaifuRepository : Repository<WaifuInfo>, IWaifuRepository
 | 
			
		||||
    {
 | 
			
		||||
        public WaifuRepository(DbContext context) : base(context)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public WaifuInfo ByWaifuUserId(ulong userId, Func<DbSet<WaifuInfo>, IQueryable<WaifuInfo>> includes = null)
 | 
			
		||||
        {
 | 
			
		||||
            if (includes == null)
 | 
			
		||||
            {
 | 
			
		||||
                return _set.Include(wi => wi.Waifu)
 | 
			
		||||
                            .Include(wi => wi.Affinity)
 | 
			
		||||
                            .Include(wi => wi.Claimer)
 | 
			
		||||
                            .Include(wi => wi.Items)
 | 
			
		||||
                            .FirstOrDefault(wi => wi.WaifuId == _context.Set<DiscordUser>()
 | 
			
		||||
                                .AsQueryable()
 | 
			
		||||
                                .Where(x => x.UserId == userId)
 | 
			
		||||
                                .Select(x => x.Id)
 | 
			
		||||
                                .FirstOrDefault());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return includes(_set)
 | 
			
		||||
                .AsQueryable()
 | 
			
		||||
                .FirstOrDefault(wi => wi.WaifuId == _context.Set<DiscordUser>()
 | 
			
		||||
                    .AsQueryable()
 | 
			
		||||
                    .Where(x => x.UserId == userId)
 | 
			
		||||
                    .Select(x => x.Id)
 | 
			
		||||
                    .FirstOrDefault());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<string> GetWaifuNames(ulong userId)
 | 
			
		||||
        {
 | 
			
		||||
            var waifus = _set.AsQueryable().Where(x => x.ClaimerId != null &&
 | 
			
		||||
                x.ClaimerId == _context.Set<DiscordUser>()
 | 
			
		||||
                    .AsQueryable()
 | 
			
		||||
                    .Where(y => y.UserId == userId)
 | 
			
		||||
                    .Select(y => y.Id)
 | 
			
		||||
                    .FirstOrDefault())
 | 
			
		||||
                .Select(x => x.WaifuId);
 | 
			
		||||
 | 
			
		||||
            return _context.Set<DiscordUser>()
 | 
			
		||||
                .AsQueryable()
 | 
			
		||||
                .Where(x => waifus.Contains(x.Id))
 | 
			
		||||
                .Select(x => x.Username + "#" + x.Discriminator)
 | 
			
		||||
                .ToList();
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<WaifuLbResult> GetTop(int count, int skip = 0)
 | 
			
		||||
        {
 | 
			
		||||
            if (count < 0)
 | 
			
		||||
                throw new ArgumentOutOfRangeException(nameof(count));
 | 
			
		||||
            if (count == 0)
 | 
			
		||||
                return new List<WaifuLbResult>();
 | 
			
		||||
 | 
			
		||||
            return _set.Include(wi => wi.Waifu)
 | 
			
		||||
                        .Include(wi => wi.Affinity)
 | 
			
		||||
                        .Include(wi => wi.Claimer)
 | 
			
		||||
                    .OrderByDescending(wi => wi.Price)
 | 
			
		||||
                    .Skip(skip)
 | 
			
		||||
                    .Take(count)
 | 
			
		||||
                    .Select(x => new WaifuLbResult
 | 
			
		||||
                    {
 | 
			
		||||
                        Affinity = x.Affinity == null ? null : x.Affinity.Username,
 | 
			
		||||
                        AffinityDiscrim = x.Affinity == null ? null : x.Affinity.Discriminator,
 | 
			
		||||
                        Claimer = x.Claimer == null ? null : x.Claimer.Username,
 | 
			
		||||
                        ClaimerDiscrim = x.Claimer == null ? null : x.Claimer.Discriminator,
 | 
			
		||||
                        Username = x.Waifu.Username,
 | 
			
		||||
                        Discrim = x.Waifu.Discriminator,
 | 
			
		||||
                        Price = x.Price,
 | 
			
		||||
                    })
 | 
			
		||||
                    .ToList();
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public decimal GetTotalValue()
 | 
			
		||||
        {
 | 
			
		||||
            return _set
 | 
			
		||||
                .AsQueryable()
 | 
			
		||||
                .Where(x => x.ClaimerId != null)
 | 
			
		||||
                .Sum(x => x.Price);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int AffinityCount(ulong userId)
 | 
			
		||||
        {
 | 
			
		||||
            //return _context.Set<WaifuUpdate>()
 | 
			
		||||
            //           .Count(w => w.User.UserId == userId &&
 | 
			
		||||
            //               w.UpdateType == WaifuUpdateType.AffinityChanged &&
 | 
			
		||||
            //               w.New != null));
 | 
			
		||||
 | 
			
		||||
            return _context.Set<WaifuUpdate>()
 | 
			
		||||
                .FromSqlInterpolated($@"SELECT 1 
 | 
			
		||||
FROM WaifuUpdates
 | 
			
		||||
WHERE UserId = (SELECT Id from DiscordUser WHERE UserId={userId}) AND 
 | 
			
		||||
    UpdateType = 0 AND 
 | 
			
		||||
    NewId IS NOT NULL")
 | 
			
		||||
                .Count();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ulong GetWaifuUserId(ulong ownerId, string name)
 | 
			
		||||
        {
 | 
			
		||||
            return _set
 | 
			
		||||
                .AsQueryable()
 | 
			
		||||
                .AsNoTracking()
 | 
			
		||||
                .Where(x => x.Claimer.UserId == ownerId
 | 
			
		||||
                            && x.Waifu.Username + "#" + x.Waifu.Discriminator == name)
 | 
			
		||||
                .Select(x => x.Waifu.UserId)
 | 
			
		||||
                .FirstOrDefault();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public WaifuInfoStats GetWaifuInfo(ulong userId)
 | 
			
		||||
        {
 | 
			
		||||
            _context.Database.ExecuteSqlInterpolated($@"
 | 
			
		||||
INSERT OR IGNORE INTO WaifuInfo (AffinityId, ClaimerId, Price, WaifuId)
 | 
			
		||||
VALUES ({null}, {null}, {1}, (SELECT Id FROM DiscordUser WHERE UserId={userId}));");
 | 
			
		||||
 | 
			
		||||
            var toReturn = _set.AsQueryable()
 | 
			
		||||
                .Where(w => w.WaifuId == _context.Set<DiscordUser>()
 | 
			
		||||
                    .AsQueryable()
 | 
			
		||||
                    .Where(u => u.UserId == userId)
 | 
			
		||||
                    .Select(u => u.Id).FirstOrDefault())
 | 
			
		||||
                .Select(w => new WaifuInfoStats
 | 
			
		||||
                {
 | 
			
		||||
                    FullName = _context.Set<DiscordUser>()
 | 
			
		||||
                        .AsQueryable()
 | 
			
		||||
                        .Where(u => u.UserId == userId)
 | 
			
		||||
                        .Select(u => u.Username + "#" + u.Discriminator)
 | 
			
		||||
                        .FirstOrDefault(),
 | 
			
		||||
 | 
			
		||||
                    AffinityCount = _context.Set<WaifuUpdate>()
 | 
			
		||||
                        .AsQueryable()
 | 
			
		||||
                        .Count(x => x.UserId == w.WaifuId &&
 | 
			
		||||
                            x.UpdateType == WaifuUpdateType.AffinityChanged &&
 | 
			
		||||
                            x.NewId != null),
 | 
			
		||||
 | 
			
		||||
                    AffinityName = _context.Set<DiscordUser>()
 | 
			
		||||
                        .AsQueryable()
 | 
			
		||||
                        .Where(u => u.Id == w.AffinityId)
 | 
			
		||||
                        .Select(u => u.Username + "#" + u.Discriminator)
 | 
			
		||||
                        .FirstOrDefault(),
 | 
			
		||||
 | 
			
		||||
                    ClaimCount = _set
 | 
			
		||||
                        .AsQueryable()
 | 
			
		||||
                        .Count(x => x.ClaimerId == w.WaifuId),
 | 
			
		||||
 | 
			
		||||
                    ClaimerName = _context.Set<DiscordUser>()
 | 
			
		||||
                        .AsQueryable()
 | 
			
		||||
                        .Where(u => u.Id == w.ClaimerId)
 | 
			
		||||
                        .Select(u => u.Username + "#" + u.Discriminator)
 | 
			
		||||
                        .FirstOrDefault(),
 | 
			
		||||
 | 
			
		||||
                    DivorceCount = _context
 | 
			
		||||
                        .Set<WaifuUpdate>()
 | 
			
		||||
                        .AsQueryable()
 | 
			
		||||
                        .Count(x => x.OldId == w.WaifuId &&
 | 
			
		||||
                                    x.NewId == null &&
 | 
			
		||||
                                    x.UpdateType == WaifuUpdateType.Claimed),
 | 
			
		||||
 | 
			
		||||
                    Price = w.Price,
 | 
			
		||||
 | 
			
		||||
                    Claims = _set
 | 
			
		||||
                        .AsQueryable()
 | 
			
		||||
                        .Include(x => x.Waifu)
 | 
			
		||||
                        .Where(x => x.ClaimerId == w.WaifuId)
 | 
			
		||||
                        .Select(x => x.Waifu.Username + "#" + x.Waifu.Discriminator)
 | 
			
		||||
                        .ToList(),
 | 
			
		||||
 | 
			
		||||
                    Fans = _set
 | 
			
		||||
                        .AsQueryable()
 | 
			
		||||
                        .Include(x => x.Waifu)
 | 
			
		||||
                        .Where(x => x.AffinityId == w.WaifuId)
 | 
			
		||||
                        .Select(x => x.Waifu.Username + "#" + x.Waifu.Discriminator)
 | 
			
		||||
                        .ToList(),
 | 
			
		||||
                    
 | 
			
		||||
                    Items = w.Items,
 | 
			
		||||
                })
 | 
			
		||||
            .FirstOrDefault();
 | 
			
		||||
 | 
			
		||||
            if (toReturn is null)
 | 
			
		||||
                return null;
 | 
			
		||||
            
 | 
			
		||||
            return toReturn;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,59 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public class WarningsRepository : Repository<Warning>, IWarningsRepository
 | 
			
		||||
    {
 | 
			
		||||
        public WarningsRepository(DbContext context) : base(context)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Warning[] ForId(ulong guildId, ulong userId)
 | 
			
		||||
        {
 | 
			
		||||
            var query = _set.AsQueryable().Where(x => x.GuildId == guildId && x.UserId == userId)
 | 
			
		||||
                .OrderByDescending(x => x.DateAdded);
 | 
			
		||||
 | 
			
		||||
            return query.ToArray();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool Forgive(ulong guildId, ulong userId, string mod, int index)
 | 
			
		||||
        {
 | 
			
		||||
            if (index < 0)
 | 
			
		||||
                throw new ArgumentOutOfRangeException(nameof(index));
 | 
			
		||||
 | 
			
		||||
            var warn = _set.AsQueryable().Where(x => x.GuildId == guildId && x.UserId == userId)
 | 
			
		||||
                .OrderByDescending(x => x.DateAdded)
 | 
			
		||||
                .Skip(index)
 | 
			
		||||
                .FirstOrDefault();
 | 
			
		||||
 | 
			
		||||
            if (warn == null || warn.Forgiven)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            warn.Forgiven = true;
 | 
			
		||||
            warn.ForgivenBy = mod;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task ForgiveAll(ulong guildId, ulong userId, string mod)
 | 
			
		||||
        {
 | 
			
		||||
            await _set.AsQueryable().Where(x => x.GuildId == guildId && x.UserId == userId)
 | 
			
		||||
                .ForEachAsync(x =>
 | 
			
		||||
                {
 | 
			
		||||
                    if (x.Forgiven != true)
 | 
			
		||||
                    {
 | 
			
		||||
                        x.Forgiven = true;
 | 
			
		||||
                        x.ForgivenBy = mod;
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Warning[] GetForGuild(ulong id)
 | 
			
		||||
        {
 | 
			
		||||
            return _set.AsQueryable().Where(x => x.GuildId == id).ToArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,86 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
{
 | 
			
		||||
    public class XpRepository : Repository<UserXpStats>, IXpRepository
 | 
			
		||||
    {
 | 
			
		||||
        public XpRepository(DbContext context) : base(context)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public UserXpStats GetOrCreateUser(ulong guildId, ulong userId)
 | 
			
		||||
        {
 | 
			
		||||
            var usr = _set.FirstOrDefault(x => x.UserId == userId && x.GuildId == guildId);
 | 
			
		||||
 | 
			
		||||
            if (usr == null)
 | 
			
		||||
            {
 | 
			
		||||
                _context.Add(usr = new UserXpStats()
 | 
			
		||||
                {
 | 
			
		||||
                    Xp = 0,
 | 
			
		||||
                    UserId = userId,
 | 
			
		||||
                    NotifyOnLevelUp = XpNotificationLocation.None,
 | 
			
		||||
                    GuildId = guildId,
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return usr;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<UserXpStats> GetUsersFor(ulong guildId, int page)
 | 
			
		||||
        {
 | 
			
		||||
            return _set
 | 
			
		||||
                .AsQueryable()
 | 
			
		||||
                .AsNoTracking()
 | 
			
		||||
                .Where(x => x.GuildId == guildId)
 | 
			
		||||
                .OrderByDescending(x => x.Xp + x.AwardedXp)
 | 
			
		||||
                .Skip(page * 9)
 | 
			
		||||
                .Take(9)
 | 
			
		||||
                .ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<UserXpStats> GetTopUserXps(ulong guildId, int count)
 | 
			
		||||
        {
 | 
			
		||||
            return _set
 | 
			
		||||
                .AsQueryable()
 | 
			
		||||
                .AsNoTracking()
 | 
			
		||||
                .Where(x => x.GuildId == guildId)
 | 
			
		||||
                .OrderByDescending(x => x.Xp + x.AwardedXp)
 | 
			
		||||
                .Take(count)
 | 
			
		||||
                .ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int GetUserGuildRanking(ulong userId, ulong guildId)
 | 
			
		||||
        {
 | 
			
		||||
            //            @"SELECT COUNT(*) + 1
 | 
			
		||||
            //FROM UserXpStats
 | 
			
		||||
            //WHERE GuildId = @p1 AND ((Xp + AwardedXp) > (SELECT Xp + AwardedXp
 | 
			
		||||
            //	FROM UserXpStats
 | 
			
		||||
            //	WHERE UserId = @p2 AND GuildId = @p1
 | 
			
		||||
            //	LIMIT 1));";
 | 
			
		||||
 | 
			
		||||
            return _set
 | 
			
		||||
                .AsQueryable()
 | 
			
		||||
                .AsNoTracking()
 | 
			
		||||
                .Where(x => x.GuildId == guildId && ((x.Xp + x.AwardedXp) >
 | 
			
		||||
                    (_set.AsQueryable()
 | 
			
		||||
                        .Where(y => y.UserId == userId && y.GuildId == guildId)
 | 
			
		||||
                        .Select(y => y.Xp + y.AwardedXp)
 | 
			
		||||
                        .FirstOrDefault())
 | 
			
		||||
                ))
 | 
			
		||||
                .Count() + 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ResetGuildUserXp(ulong userId, ulong guildId)
 | 
			
		||||
        {
 | 
			
		||||
            _context.Database.ExecuteSqlInterpolated($"DELETE FROM UserXpStats WHERE UserId={userId} AND GuildId={guildId};");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ResetGuildXp(ulong guildId)
 | 
			
		||||
        {
 | 
			
		||||
            _context.Database.ExecuteSqlInterpolated($"DELETE FROM UserXpStats WHERE GuildId={guildId};");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								src/NadekoBot/Services/Database/UnitOfWork.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/NadekoBot/Services/Database/UnitOfWork.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
using NadekoBot.Core.Services.Database.Repositories;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Repositories.Impl;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services.Database
 | 
			
		||||
{
 | 
			
		||||
    public sealed class UnitOfWork : IUnitOfWork
 | 
			
		||||
    {
 | 
			
		||||
        public NadekoContext _context { get; }
 | 
			
		||||
 | 
			
		||||
        private IQuoteRepository _quotes;
 | 
			
		||||
        public IQuoteRepository Quotes => _quotes ?? (_quotes = new QuoteRepository(_context));
 | 
			
		||||
 | 
			
		||||
        private IGuildConfigRepository _guildConfigs;
 | 
			
		||||
        public IGuildConfigRepository GuildConfigs => _guildConfigs ?? (_guildConfigs = new GuildConfigRepository(_context));
 | 
			
		||||
 | 
			
		||||
        private IReminderRepository _reminders;
 | 
			
		||||
        public IReminderRepository Reminders => _reminders ?? (_reminders = new ReminderRepository(_context));
 | 
			
		||||
 | 
			
		||||
        private ISelfAssignedRolesRepository _selfAssignedRoles;
 | 
			
		||||
        public ISelfAssignedRolesRepository SelfAssignedRoles => _selfAssignedRoles ?? (_selfAssignedRoles = new SelfAssignedRolesRepository(_context));
 | 
			
		||||
 | 
			
		||||
        private IMusicPlaylistRepository _musicPlaylists;
 | 
			
		||||
        public IMusicPlaylistRepository MusicPlaylists => _musicPlaylists ?? (_musicPlaylists = new MusicPlaylistRepository(_context));
 | 
			
		||||
 | 
			
		||||
        private ICustomReactionRepository _customReactions;
 | 
			
		||||
        public ICustomReactionRepository CustomReactions => _customReactions ?? (_customReactions = new CustomReactionsRepository(_context));
 | 
			
		||||
 | 
			
		||||
        private IWaifuRepository _waifus;
 | 
			
		||||
        public IWaifuRepository Waifus => _waifus ?? (_waifus = new WaifuRepository(_context));
 | 
			
		||||
 | 
			
		||||
        private IDiscordUserRepository _discordUsers;
 | 
			
		||||
        public IDiscordUserRepository DiscordUsers => _discordUsers ?? (_discordUsers = new DiscordUserRepository(_context));
 | 
			
		||||
 | 
			
		||||
        private IWarningsRepository _warnings;
 | 
			
		||||
        public IWarningsRepository Warnings => _warnings ?? (_warnings = new WarningsRepository(_context));
 | 
			
		||||
 | 
			
		||||
        private IXpRepository _xp;
 | 
			
		||||
        public IXpRepository Xp => _xp ?? (_xp = new XpRepository(_context));
 | 
			
		||||
 | 
			
		||||
        private IClubRepository _clubs;
 | 
			
		||||
        public IClubRepository Clubs => _clubs ?? (_clubs = new ClubRepository(_context));
 | 
			
		||||
 | 
			
		||||
        private IPollsRepository _polls;
 | 
			
		||||
        public IPollsRepository Polls => _polls ?? (_polls = new PollsRepository(_context));
 | 
			
		||||
 | 
			
		||||
        private IPlantedCurrencyRepository _planted;
 | 
			
		||||
        public IPlantedCurrencyRepository PlantedCurrency => _planted ?? (_planted = new PlantedCurrencyRepository(_context));
 | 
			
		||||
 | 
			
		||||
        public UnitOfWork(NadekoContext context)
 | 
			
		||||
        {
 | 
			
		||||
            _context = context;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int SaveChanges() =>
 | 
			
		||||
            _context.SaveChanges();
 | 
			
		||||
 | 
			
		||||
        public Task<int> SaveChangesAsync() =>
 | 
			
		||||
            _context.SaveChangesAsync();
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _context.Dispose();
 | 
			
		||||
            GC.SuppressFinalize(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										61
									
								
								src/NadekoBot/Services/DbService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/NadekoBot/Services/DbService.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
using Microsoft.Data.Sqlite;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using NadekoBot.Core.Services.Database;
 | 
			
		||||
using System;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services
 | 
			
		||||
{
 | 
			
		||||
    public class DbService
 | 
			
		||||
    {
 | 
			
		||||
        private readonly DbContextOptions<NadekoContext> options;
 | 
			
		||||
        private readonly DbContextOptions<NadekoContext> migrateOptions;
 | 
			
		||||
 | 
			
		||||
        public DbService(IBotCredentials creds)
 | 
			
		||||
        {
 | 
			
		||||
            var builder = new SqliteConnectionStringBuilder(creds.Db.ConnectionString);
 | 
			
		||||
            builder.DataSource = Path.Combine(AppContext.BaseDirectory, builder.DataSource);
 | 
			
		||||
 | 
			
		||||
            var optionsBuilder = new DbContextOptionsBuilder<NadekoContext>();
 | 
			
		||||
            optionsBuilder.UseSqlite(builder.ToString());
 | 
			
		||||
            options = optionsBuilder.Options;
 | 
			
		||||
 | 
			
		||||
            optionsBuilder = new DbContextOptionsBuilder<NadekoContext>();
 | 
			
		||||
            optionsBuilder.UseSqlite(builder.ToString());
 | 
			
		||||
            migrateOptions = optionsBuilder.Options;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Setup()
 | 
			
		||||
        {
 | 
			
		||||
            using (var context = new NadekoContext(options))
 | 
			
		||||
            {
 | 
			
		||||
                if (context.Database.GetPendingMigrations().Any())
 | 
			
		||||
                {
 | 
			
		||||
                    var mContext = new NadekoContext(migrateOptions);
 | 
			
		||||
                    mContext.Database.Migrate();
 | 
			
		||||
                    mContext.SaveChanges();
 | 
			
		||||
                    mContext.Dispose();
 | 
			
		||||
                }
 | 
			
		||||
                context.Database.ExecuteSqlRaw("PRAGMA journal_mode=WAL");
 | 
			
		||||
                context.SaveChanges();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private NadekoContext GetDbContextInternal()
 | 
			
		||||
        {
 | 
			
		||||
            var context = new NadekoContext(options);
 | 
			
		||||
            context.Database.SetCommandTimeout(60);
 | 
			
		||||
            var conn = context.Database.GetDbConnection();
 | 
			
		||||
            conn.Open();
 | 
			
		||||
            using (var com = conn.CreateCommand())
 | 
			
		||||
            {
 | 
			
		||||
                com.CommandText = "PRAGMA journal_mode=WAL; PRAGMA synchronous=OFF";
 | 
			
		||||
                com.ExecuteNonQuery();
 | 
			
		||||
            }
 | 
			
		||||
            return context;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IUnitOfWork GetDbContext() => new UnitOfWork(GetDbContextInternal());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										611
									
								
								src/NadekoBot/Services/GreetSettingsService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										611
									
								
								src/NadekoBot/Services/GreetSettingsService.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,611 @@
 | 
			
		||||
using Discord;
 | 
			
		||||
using Discord.WebSocket;
 | 
			
		||||
using NadekoBot.Common;
 | 
			
		||||
using NadekoBot.Common.Replacements;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Serilog;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services
 | 
			
		||||
{
 | 
			
		||||
    public class GreetSettingsService : INService
 | 
			
		||||
    {
 | 
			
		||||
        private readonly DbService _db;
 | 
			
		||||
 | 
			
		||||
        public ConcurrentDictionary<ulong, GreetSettings> GuildConfigsCache { get; }
 | 
			
		||||
        private readonly DiscordSocketClient _client;
 | 
			
		||||
        
 | 
			
		||||
        private GreetGrouper<IGuildUser> greets = new GreetGrouper<IGuildUser>();
 | 
			
		||||
        private GreetGrouper<IGuildUser> byes = new GreetGrouper<IGuildUser>();
 | 
			
		||||
        private readonly BotConfigService _bss;
 | 
			
		||||
        public bool GroupGreets => _bss.Data.GroupGreets;
 | 
			
		||||
 | 
			
		||||
        public GreetSettingsService(DiscordSocketClient client, NadekoBot bot, DbService db,
 | 
			
		||||
            BotConfigService bss)
 | 
			
		||||
        {
 | 
			
		||||
            _db = db;
 | 
			
		||||
            _client = client;
 | 
			
		||||
            _bss = bss;
 | 
			
		||||
 | 
			
		||||
            GuildConfigsCache = new ConcurrentDictionary<ulong, GreetSettings>(
 | 
			
		||||
                bot.AllGuildConfigs
 | 
			
		||||
                    .ToDictionary(g => g.GuildId, GreetSettings.Create));
 | 
			
		||||
 | 
			
		||||
            _client.UserJoined += UserJoined;
 | 
			
		||||
            _client.UserLeft += UserLeft;
 | 
			
		||||
 | 
			
		||||
            bot.JoinedGuild += Bot_JoinedGuild;
 | 
			
		||||
            _client.LeftGuild += _client_LeftGuild;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task _client_LeftGuild(SocketGuild arg)
 | 
			
		||||
        {
 | 
			
		||||
            GuildConfigsCache.TryRemove(arg.Id, out _);
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task Bot_JoinedGuild(GuildConfig gc)
 | 
			
		||||
        {
 | 
			
		||||
            GuildConfigsCache.AddOrUpdate(gc.GuildId,
 | 
			
		||||
                GreetSettings.Create(gc),
 | 
			
		||||
                delegate { return GreetSettings.Create(gc); });
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task UserLeft(IGuildUser user)
 | 
			
		||||
        {
 | 
			
		||||
            var _ = Task.Run(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var conf = GetOrAddSettingsForGuild(user.GuildId);
 | 
			
		||||
 | 
			
		||||
                    if (!conf.SendChannelByeMessage) return;
 | 
			
		||||
                    var channel = (await user.Guild.GetTextChannelsAsync().ConfigureAwait(false)).SingleOrDefault(c => c.Id == conf.ByeMessageChannelId);
 | 
			
		||||
 | 
			
		||||
                    if (channel == null) //maybe warn the server owner that the channel is missing
 | 
			
		||||
                        return;
 | 
			
		||||
                    
 | 
			
		||||
                    if (GroupGreets)
 | 
			
		||||
                    {
 | 
			
		||||
                        // if group is newly created, greet that user right away,
 | 
			
		||||
                        // but any user which joins in the next 5 seconds will
 | 
			
		||||
                        // be greeted in a group greet
 | 
			
		||||
                        if (byes.CreateOrAdd(user.GuildId, user))
 | 
			
		||||
                        {
 | 
			
		||||
                            // greet single user
 | 
			
		||||
                            await ByeUsers(conf, channel, new[] {user});
 | 
			
		||||
                            var groupClear = false;
 | 
			
		||||
                            while(!groupClear)
 | 
			
		||||
                            {
 | 
			
		||||
                                await Task.Delay(5000).ConfigureAwait(false);
 | 
			
		||||
                                groupClear = byes.ClearGroup(user.GuildId, 5, out var toBye);
 | 
			
		||||
                                await ByeUsers(conf, channel, toBye);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        await ByeUsers(conf, channel, new[] {user});
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
                    // ignored
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string GetDmGreetMsg(ulong id)
 | 
			
		||||
        {
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                return uow.GuildConfigs.ForId(id, set => set)?.DmGreetMessageText;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string GetGreetMsg(ulong gid)
 | 
			
		||||
        {
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                return uow.GuildConfigs.ForId(gid, set => set).ChannelGreetMessageText;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task ByeUsers(GreetSettings conf, ITextChannel channel, IUser user)
 | 
			
		||||
            => ByeUsers(conf, channel, new[] {user});
 | 
			
		||||
        private async Task ByeUsers(GreetSettings conf, ITextChannel channel, IEnumerable<IUser> users)
 | 
			
		||||
        {
 | 
			
		||||
            if (!users.Any())
 | 
			
		||||
                return;
 | 
			
		||||
            
 | 
			
		||||
            var rep = new ReplacementBuilder()
 | 
			
		||||
                .WithChannel(channel)
 | 
			
		||||
                .WithClient(_client)
 | 
			
		||||
                .WithServer(_client, (SocketGuild) channel.Guild)
 | 
			
		||||
                .WithManyUsers(users)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            if (CREmbed.TryParse(conf.ChannelByeMessageText, out var embedData))
 | 
			
		||||
            {
 | 
			
		||||
                rep.Replace(embedData);
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var toDelete = await channel.EmbedAsync(embedData).ConfigureAwait(false);
 | 
			
		||||
                    if (conf.AutoDeleteByeMessagesTimer > 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    Log.Warning(ex, "Error embeding bye message");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var msg = rep.Replace(conf.ChannelByeMessageText);
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(msg))
 | 
			
		||||
                    return;
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false);
 | 
			
		||||
                    if (conf.AutoDeleteByeMessagesTimer > 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    Log.Warning(ex, "Error sending bye message");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        private Task GreetUsers(GreetSettings conf, ITextChannel channel, IGuildUser user)
 | 
			
		||||
            => GreetUsers(conf, channel, new[] {user});
 | 
			
		||||
        
 | 
			
		||||
        private async Task GreetUsers(GreetSettings conf, ITextChannel channel, IEnumerable<IGuildUser> users)
 | 
			
		||||
        {
 | 
			
		||||
            if (!users.Any())
 | 
			
		||||
                return;
 | 
			
		||||
            
 | 
			
		||||
            var rep = new ReplacementBuilder()
 | 
			
		||||
                .WithChannel(channel)
 | 
			
		||||
                .WithClient(_client)
 | 
			
		||||
                .WithServer(_client, (SocketGuild) channel.Guild)
 | 
			
		||||
                .WithManyUsers(users)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            if (CREmbed.TryParse(conf.ChannelGreetMessageText, out var embedData))
 | 
			
		||||
            {
 | 
			
		||||
                rep.Replace(embedData);
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var toDelete = await channel.EmbedAsync(embedData).ConfigureAwait(false);
 | 
			
		||||
                    if (conf.AutoDeleteGreetMessagesTimer > 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    Log.Warning(ex, "Error embeding greet message");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var msg = rep.Replace(conf.ChannelGreetMessageText);
 | 
			
		||||
                if (!string.IsNullOrWhiteSpace(msg))
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false);
 | 
			
		||||
                        if (conf.AutoDeleteGreetMessagesTimer > 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex)
 | 
			
		||||
                    {
 | 
			
		||||
                        Log.Warning(ex, "Error sending greet message");
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<bool> GreetDmUser(GreetSettings conf, IDMChannel channel, IGuildUser user)
 | 
			
		||||
        {
 | 
			
		||||
            var rep = new ReplacementBuilder()
 | 
			
		||||
                .WithDefault(user, channel, (SocketGuild)user.Guild, _client)
 | 
			
		||||
                .Build();
 | 
			
		||||
            
 | 
			
		||||
            if (CREmbed.TryParse(conf.DmGreetMessageText, out var embedData))
 | 
			
		||||
            {
 | 
			
		||||
                rep.Replace(embedData);
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await channel.EmbedAsync(embedData).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var msg = rep.Replace(conf.DmGreetMessageText);
 | 
			
		||||
                if (!string.IsNullOrWhiteSpace(msg))
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        await channel.SendConfirmAsync(msg).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch
 | 
			
		||||
                    {
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task UserJoined(IGuildUser user)
 | 
			
		||||
        {
 | 
			
		||||
            var _ = Task.Run(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var conf = GetOrAddSettingsForGuild(user.GuildId);
 | 
			
		||||
 | 
			
		||||
                    if (conf.SendChannelGreetMessage)
 | 
			
		||||
                    {
 | 
			
		||||
                        var channel = await user.Guild.GetTextChannelAsync(conf.GreetMessageChannelId);
 | 
			
		||||
                        if (channel != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (GroupGreets)
 | 
			
		||||
                            {
 | 
			
		||||
                                // if group is newly created, greet that user right away,
 | 
			
		||||
                                // but any user which joins in the next 5 seconds will
 | 
			
		||||
                                // be greeted in a group greet
 | 
			
		||||
                                if (greets.CreateOrAdd(user.GuildId, user))
 | 
			
		||||
                                {
 | 
			
		||||
                                    // greet single user
 | 
			
		||||
                                    await GreetUsers(conf, channel, new[] {user});
 | 
			
		||||
                                    var groupClear = false;
 | 
			
		||||
                                    while(!groupClear)
 | 
			
		||||
                                    {
 | 
			
		||||
                                        await Task.Delay(5000).ConfigureAwait(false);
 | 
			
		||||
                                        groupClear = greets.ClearGroup(user.GuildId, 5, out var toGreet);
 | 
			
		||||
                                        await GreetUsers(conf, channel, toGreet);
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                await GreetUsers(conf, channel, new[] {user});
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (conf.SendDmGreetMessage)
 | 
			
		||||
                    {
 | 
			
		||||
                        var channel = await user.GetOrCreateDMChannelAsync().ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                        if (channel != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            await GreetDmUser(conf, channel, user);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
                    // ignored
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string GetByeMessage(ulong gid)
 | 
			
		||||
        {
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                return uow.GuildConfigs.ForId(gid, set => set).ChannelByeMessageText;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public GreetSettings GetOrAddSettingsForGuild(ulong guildId)
 | 
			
		||||
        {
 | 
			
		||||
            if (GuildConfigsCache.TryGetValue(guildId, out var settings) &&
 | 
			
		||||
                settings != null)
 | 
			
		||||
                return settings;
 | 
			
		||||
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var gc = uow.GuildConfigs.ForId(guildId, set => set);
 | 
			
		||||
                settings = GreetSettings.Create(gc);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            GuildConfigsCache.TryAdd(guildId, settings);
 | 
			
		||||
            return settings;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<bool> SetSettings(ulong guildId, GreetSettings settings)
 | 
			
		||||
        {
 | 
			
		||||
            if (settings.AutoDeleteByeMessagesTimer > 600 ||
 | 
			
		||||
                settings.AutoDeleteByeMessagesTimer < 0 ||
 | 
			
		||||
                settings.AutoDeleteGreetMessagesTimer > 600 ||
 | 
			
		||||
                settings.AutoDeleteGreetMessagesTimer < 0)
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var conf = uow.GuildConfigs.ForId(guildId, set => set);
 | 
			
		||||
                conf.DmGreetMessageText = settings.DmGreetMessageText?.SanitizeMentions();
 | 
			
		||||
                conf.ChannelGreetMessageText = settings.ChannelGreetMessageText?.SanitizeMentions();
 | 
			
		||||
                conf.ChannelByeMessageText = settings.ChannelByeMessageText?.SanitizeMentions();
 | 
			
		||||
 | 
			
		||||
                conf.AutoDeleteGreetMessagesTimer = settings.AutoDeleteGreetMessagesTimer;
 | 
			
		||||
                conf.AutoDeleteGreetMessages = settings.AutoDeleteGreetMessagesTimer > 0;
 | 
			
		||||
 | 
			
		||||
                conf.AutoDeleteByeMessagesTimer = settings.AutoDeleteByeMessagesTimer;
 | 
			
		||||
                conf.AutoDeleteByeMessages = settings.AutoDeleteByeMessagesTimer > 0;
 | 
			
		||||
 | 
			
		||||
                conf.GreetMessageChannelId = settings.GreetMessageChannelId;
 | 
			
		||||
                conf.ByeMessageChannelId = settings.ByeMessageChannelId;
 | 
			
		||||
 | 
			
		||||
                conf.SendChannelGreetMessage = settings.SendChannelGreetMessage;
 | 
			
		||||
                conf.SendChannelByeMessage = settings.SendChannelByeMessage;
 | 
			
		||||
 | 
			
		||||
                await uow.SaveChangesAsync();
 | 
			
		||||
 | 
			
		||||
                var toAdd = GreetSettings.Create(conf);
 | 
			
		||||
                GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<bool> SetGreet(ulong guildId, ulong channelId, bool? value = null)
 | 
			
		||||
        {
 | 
			
		||||
            bool enabled;
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var conf = uow.GuildConfigs.ForId(guildId, set => set);
 | 
			
		||||
                enabled = conf.SendChannelGreetMessage = value ?? !conf.SendChannelGreetMessage;
 | 
			
		||||
                conf.GreetMessageChannelId = channelId;
 | 
			
		||||
 | 
			
		||||
                var toAdd = GreetSettings.Create(conf);
 | 
			
		||||
                GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
 | 
			
		||||
 | 
			
		||||
                await uow.SaveChangesAsync();
 | 
			
		||||
            }
 | 
			
		||||
            return enabled;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool SetGreetMessage(ulong guildId, ref string message)
 | 
			
		||||
        {
 | 
			
		||||
            message = message?.SanitizeMentions();
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(message))
 | 
			
		||||
                throw new ArgumentNullException(nameof(message));
 | 
			
		||||
 | 
			
		||||
            bool greetMsgEnabled;
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var conf = uow.GuildConfigs.ForId(guildId, set => set);
 | 
			
		||||
                conf.ChannelGreetMessageText = message;
 | 
			
		||||
                greetMsgEnabled = conf.SendChannelGreetMessage;
 | 
			
		||||
 | 
			
		||||
                var toAdd = GreetSettings.Create(conf);
 | 
			
		||||
                GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
 | 
			
		||||
 | 
			
		||||
                uow.SaveChanges();
 | 
			
		||||
            }
 | 
			
		||||
            return greetMsgEnabled;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<bool> SetGreetDm(ulong guildId, bool? value = null)
 | 
			
		||||
        {
 | 
			
		||||
            bool enabled;
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var conf = uow.GuildConfigs.ForId(guildId, set => set);
 | 
			
		||||
                enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage;
 | 
			
		||||
 | 
			
		||||
                var toAdd = GreetSettings.Create(conf);
 | 
			
		||||
                GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
 | 
			
		||||
 | 
			
		||||
                await uow.SaveChangesAsync();
 | 
			
		||||
            }
 | 
			
		||||
            return enabled;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #region Get Enabled Status
 | 
			
		||||
        public bool GetGreetDmEnabled(ulong guildId)
 | 
			
		||||
        {
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var conf = uow.GuildConfigs.ForId(guildId, set => set);
 | 
			
		||||
                return conf.SendDmGreetMessage;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public bool GetGreetEnabled(ulong guildId)
 | 
			
		||||
        {
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var conf = uow.GuildConfigs.ForId(guildId, set => set);
 | 
			
		||||
                return conf.SendChannelGreetMessage;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public bool GetByeEnabled(ulong guildId)
 | 
			
		||||
        {
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var conf = uow.GuildConfigs.ForId(guildId, set => set);
 | 
			
		||||
                return conf.SendChannelByeMessage;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        #endregion
 | 
			
		||||
        
 | 
			
		||||
        #region Test Messages
 | 
			
		||||
 | 
			
		||||
        public Task ByeTest(ITextChannel channel, IGuildUser user)
 | 
			
		||||
        {
 | 
			
		||||
            var conf = GetOrAddSettingsForGuild(user.GuildId);
 | 
			
		||||
            return ByeUsers(conf, channel, user);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public Task GreetTest(ITextChannel channel, IGuildUser user)
 | 
			
		||||
        {
 | 
			
		||||
            var conf = GetOrAddSettingsForGuild(user.GuildId);
 | 
			
		||||
            return GreetUsers(conf, channel, user);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public Task<bool> GreetDmTest(IDMChannel channel, IGuildUser user)
 | 
			
		||||
        {
 | 
			
		||||
            var conf = GetOrAddSettingsForGuild(user.GuildId);
 | 
			
		||||
            return GreetDmUser(conf, channel, user);
 | 
			
		||||
        }
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
        public bool SetGreetDmMessage(ulong guildId, ref string message)
 | 
			
		||||
        {
 | 
			
		||||
            message = message?.SanitizeMentions();
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(message))
 | 
			
		||||
                throw new ArgumentNullException(nameof(message));
 | 
			
		||||
 | 
			
		||||
            bool greetMsgEnabled;
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var conf = uow.GuildConfigs.ForId(guildId, set => set);
 | 
			
		||||
                conf.DmGreetMessageText = message;
 | 
			
		||||
                greetMsgEnabled = conf.SendDmGreetMessage;
 | 
			
		||||
 | 
			
		||||
                var toAdd = GreetSettings.Create(conf);
 | 
			
		||||
                GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
 | 
			
		||||
 | 
			
		||||
                uow.SaveChanges();
 | 
			
		||||
            }
 | 
			
		||||
            return greetMsgEnabled;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<bool> SetBye(ulong guildId, ulong channelId, bool? value = null)
 | 
			
		||||
        {
 | 
			
		||||
            bool enabled;
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var conf = uow.GuildConfigs.ForId(guildId, set => set);
 | 
			
		||||
                enabled = conf.SendChannelByeMessage = value ?? !conf.SendChannelByeMessage;
 | 
			
		||||
                conf.ByeMessageChannelId = channelId;
 | 
			
		||||
 | 
			
		||||
                var toAdd = GreetSettings.Create(conf);
 | 
			
		||||
                GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
 | 
			
		||||
 | 
			
		||||
                await uow.SaveChangesAsync();
 | 
			
		||||
            }
 | 
			
		||||
            return enabled;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool SetByeMessage(ulong guildId, ref string message)
 | 
			
		||||
        {
 | 
			
		||||
            message = message?.SanitizeMentions();
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(message))
 | 
			
		||||
                throw new ArgumentNullException(nameof(message));
 | 
			
		||||
 | 
			
		||||
            bool byeMsgEnabled;
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var conf = uow.GuildConfigs.ForId(guildId, set => set);
 | 
			
		||||
                conf.ChannelByeMessageText = message;
 | 
			
		||||
                byeMsgEnabled = conf.SendChannelByeMessage;
 | 
			
		||||
 | 
			
		||||
                var toAdd = GreetSettings.Create(conf);
 | 
			
		||||
                GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
 | 
			
		||||
 | 
			
		||||
                uow.SaveChanges();
 | 
			
		||||
            }
 | 
			
		||||
            return byeMsgEnabled;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task SetByeDel(ulong guildId, int timer)
 | 
			
		||||
        {
 | 
			
		||||
            if (timer < 0 || timer > 600)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var conf = uow.GuildConfigs.ForId(guildId, set => set);
 | 
			
		||||
                conf.AutoDeleteByeMessagesTimer = timer;
 | 
			
		||||
 | 
			
		||||
                var toAdd = GreetSettings.Create(conf);
 | 
			
		||||
                GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
 | 
			
		||||
 | 
			
		||||
                await uow.SaveChangesAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task SetGreetDel(ulong id, int timer)
 | 
			
		||||
        {
 | 
			
		||||
            if (timer < 0 || timer > 600)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                var conf = uow.GuildConfigs.ForId(id, set => set);
 | 
			
		||||
                conf.AutoDeleteGreetMessagesTimer = timer;
 | 
			
		||||
 | 
			
		||||
                var toAdd = GreetSettings.Create(conf);
 | 
			
		||||
                GuildConfigsCache.AddOrUpdate(id, toAdd, (key, old) => toAdd);
 | 
			
		||||
 | 
			
		||||
                await uow.SaveChangesAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class GreetSettings
 | 
			
		||||
    {
 | 
			
		||||
        public int AutoDeleteGreetMessagesTimer { get; set; }
 | 
			
		||||
        public int AutoDeleteByeMessagesTimer { get; set; }
 | 
			
		||||
 | 
			
		||||
        public ulong GreetMessageChannelId { get; set; }
 | 
			
		||||
        public ulong ByeMessageChannelId { get; set; }
 | 
			
		||||
 | 
			
		||||
        public bool SendDmGreetMessage { get; set; }
 | 
			
		||||
        public string DmGreetMessageText { get; set; }
 | 
			
		||||
 | 
			
		||||
        public bool SendChannelGreetMessage { get; set; }
 | 
			
		||||
        public string ChannelGreetMessageText { get; set; }
 | 
			
		||||
 | 
			
		||||
        public bool SendChannelByeMessage { get; set; }
 | 
			
		||||
        public string ChannelByeMessageText { get; set; }
 | 
			
		||||
 | 
			
		||||
        public static GreetSettings Create(GuildConfig g) => new GreetSettings()
 | 
			
		||||
        {
 | 
			
		||||
            AutoDeleteByeMessagesTimer = g.AutoDeleteByeMessagesTimer,
 | 
			
		||||
            AutoDeleteGreetMessagesTimer = g.AutoDeleteGreetMessagesTimer,
 | 
			
		||||
            GreetMessageChannelId = g.GreetMessageChannelId,
 | 
			
		||||
            ByeMessageChannelId = g.ByeMessageChannelId,
 | 
			
		||||
            SendDmGreetMessage = g.SendDmGreetMessage,
 | 
			
		||||
            DmGreetMessageText = g.DmGreetMessageText,
 | 
			
		||||
            SendChannelGreetMessage = g.SendChannelGreetMessage,
 | 
			
		||||
            ChannelGreetMessageText = g.ChannelGreetMessageText,
 | 
			
		||||
            SendChannelByeMessage = g.SendChannelByeMessage,
 | 
			
		||||
            ChannelByeMessageText = g.ChannelByeMessageText,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								src/NadekoBot/Services/IBotCredentials.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/NadekoBot/Services/IBotCredentials.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
using Discord;
 | 
			
		||||
using System.Collections.Immutable;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services
 | 
			
		||||
{
 | 
			
		||||
    public interface IBotCredentials
 | 
			
		||||
    {
 | 
			
		||||
        string Token { get; }
 | 
			
		||||
        string GoogleApiKey { get; }
 | 
			
		||||
        ImmutableArray<ulong> OwnerIds { get; }
 | 
			
		||||
        string MashapeKey { get; }
 | 
			
		||||
        string PatreonAccessToken { get; }
 | 
			
		||||
        string CarbonKey { get; }
 | 
			
		||||
 | 
			
		||||
        DBConfig Db { get; }
 | 
			
		||||
        string OsuApiKey { get; }
 | 
			
		||||
 | 
			
		||||
        bool IsOwner(IUser u);
 | 
			
		||||
        int TotalShards { get; }
 | 
			
		||||
        string ShardRunCommand { get; }
 | 
			
		||||
        string ShardRunArguments { get; }
 | 
			
		||||
        string PatreonCampaignId { get; }
 | 
			
		||||
        string CleverbotApiKey { get; }
 | 
			
		||||
        RestartConfig RestartCommand { get; }
 | 
			
		||||
        string VotesUrl { get; }
 | 
			
		||||
        string VotesToken { get; }
 | 
			
		||||
        string BotListToken { get; }
 | 
			
		||||
        string TwitchClientId { get; }
 | 
			
		||||
        string RedisOptions { get; }
 | 
			
		||||
        string LocationIqApiKey { get; }
 | 
			
		||||
        string TimezoneDbApiKey { get; }
 | 
			
		||||
        string CoinmarketcapApiKey { get; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class RestartConfig
 | 
			
		||||
    {
 | 
			
		||||
        public RestartConfig(string cmd, string args)
 | 
			
		||||
        {
 | 
			
		||||
            this.Cmd = cmd;
 | 
			
		||||
            this.Args = args;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string Cmd { get; }
 | 
			
		||||
        public string Args { get; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class DBConfig
 | 
			
		||||
    {
 | 
			
		||||
        public DBConfig(string type, string connectionString)
 | 
			
		||||
        {
 | 
			
		||||
            this.Type = type;
 | 
			
		||||
            this.ConnectionString = connectionString;
 | 
			
		||||
        }
 | 
			
		||||
        public string Type { get; }
 | 
			
		||||
        public string ConnectionString { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/NadekoBot/Services/ICurrencyService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/NadekoBot/Services/ICurrencyService.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
using Discord;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Core.Services
 | 
			
		||||
{
 | 
			
		||||
    public interface ICurrencyService : INService
 | 
			
		||||
    {
 | 
			
		||||
        Task AddAsync(ulong userId, string reason, long amount, bool gamble = false);
 | 
			
		||||
        Task AddAsync(IUser user, string reason, long amount, bool sendMessage = false, bool gamble = false);
 | 
			
		||||
        Task AddBulkAsync(IEnumerable<ulong> userIds, IEnumerable<string> reasons, IEnumerable<long> amounts,  bool gamble = false);
 | 
			
		||||
        Task<bool> RemoveAsync(ulong userId, string reason, long amount, bool gamble = false);
 | 
			
		||||
        Task<bool> RemoveAsync(IUser userId, string reason, long amount, bool sendMessage = false, bool gamble = false);
 | 
			
		||||
        Task RemoveBulkAsync(IEnumerable<ulong> userIds, IEnumerable<string> reasons, IEnumerable<long> amounts, bool gamble = false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user