Initial split of the modules
This commit is contained in:
		
							
								
								
									
										426
									
								
								NadekoBot.Core/Services/CommandHandler.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										426
									
								
								NadekoBot.Core/Services/CommandHandler.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,426 @@ | ||||
| using Discord.WebSocket; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| using Discord; | ||||
| using NLog; | ||||
| using Discord.Commands; | ||||
| using NadekoBot.Extensions; | ||||
| using System.Collections.Concurrent; | ||||
| using System.Threading; | ||||
| using System.Collections.Immutable; | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.IO; | ||||
| using Discord.Net; | ||||
| using NadekoBot.Common; | ||||
| using NadekoBot.Common.Collections; | ||||
| using NadekoBot.Common.ModuleBehaviors; | ||||
|  | ||||
| namespace NadekoBot.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 Logger _log; | ||||
|         private readonly IBotCredentials _creds; | ||||
|         private readonly NadekoBot _bot; | ||||
|         private INServiceProvider _services; | ||||
|         public string DefaultPrefix { get; private set; } | ||||
|         private ConcurrentDictionary<ulong, string> _prefixes { get; } = new ConcurrentDictionary<ulong, string>(); | ||||
|  | ||||
|         private ImmutableArray<AsyncLazy<IDMChannel>> OwnerChannels { get; set; } = new ImmutableArray<AsyncLazy<IDMChannel>>(); | ||||
|          | ||||
|         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, IBotConfigProvider bc, IEnumerable<GuildConfig> gcs, CommandService commandService, IBotCredentials credentials, NadekoBot bot) | ||||
|         { | ||||
|             _client = client; | ||||
|             _commandService = commandService; | ||||
|             _creds = credentials; | ||||
|             _bot = bot; | ||||
|             _db = db; | ||||
|  | ||||
|             _log = LogManager.GetCurrentClassLogger(); | ||||
|  | ||||
|             _clearUsersOnShortCooldown = new Timer(_ => | ||||
|             { | ||||
|                 UsersOnShortCooldown.Clear(); | ||||
|             }, null, GlobalCommandsCooldown, GlobalCommandsCooldown); | ||||
|  | ||||
|             DefaultPrefix = bc.BotConfig.DefaultPrefix; | ||||
|             _prefixes = gcs | ||||
|                 .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) | ||||
|         { | ||||
|             if (id == null || !_prefixes.TryGetValue(id.Value, out var prefix)) | ||||
|                 return DefaultPrefix; | ||||
|  | ||||
|             return prefix; | ||||
|         } | ||||
|  | ||||
|         public string SetDefaultPrefix(string prefix) | ||||
|         { | ||||
|             if (string.IsNullOrWhiteSpace(prefix)) | ||||
|                 throw new ArgumentNullException(nameof(prefix)); | ||||
|  | ||||
|             prefix = prefix.ToLowerInvariant(); | ||||
|  | ||||
|             using (var uow = _db.UnitOfWork) | ||||
|             { | ||||
|                 uow.BotConfig.GetOrCreate(set => set).DefaultPrefix = prefix; | ||||
|                 uow.Complete(); | ||||
|             } | ||||
|  | ||||
|             return DefaultPrefix = 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)); | ||||
|  | ||||
|             prefix = prefix.ToLowerInvariant(); | ||||
|  | ||||
|             using (var uow = _db.UnitOfWork) | ||||
|             { | ||||
|                 var gc = uow.GuildConfigs.For(guild.Id, set => set); | ||||
|                 gc.Prefix = prefix; | ||||
|                 uow.Complete(); | ||||
|             } | ||||
|             _prefixes.AddOrUpdate(guild.Id, prefix, (key, old) => prefix); | ||||
|  | ||||
|             return prefix; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         public void AddServices(INServiceProvider services) | ||||
|         { | ||||
|             _services = services; | ||||
|         } | ||||
|  | ||||
|         public async Task ExecuteExternal(ulong? guildId, ulong channelId, string commandText) | ||||
|         { | ||||
|             if (guildId != null) | ||||
|             { | ||||
|                 var guild = _client.GetGuild(guildId.Value); | ||||
|                 var channel = guild?.GetChannel(channelId) as SocketTextChannel; | ||||
|                 if (channel == null) | ||||
|                 { | ||||
|                     _log.Warn("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) | ||||
|         { | ||||
|             _log.Info("Command Executed after " + string.Join("/", execPoints.Select(x => x * _oneThousandth)) + "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} | ||||
|                         ); | ||||
|             return Task.CompletedTask; | ||||
|         } | ||||
|  | ||||
|         private void LogErroredExecution(string errorMessage, IUserMessage usrMsg, ITextChannel channel, params int[] execPoints) | ||||
|         { | ||||
|             _log.Warn("Command Errored after " + string.Join("/", execPoints.Select(x => x * _oneThousandth)) + "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} | ||||
|                         ); | ||||
|         } | ||||
|  | ||||
|         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); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 _log.Warn("Error in CommandHandler"); | ||||
|                 _log.Warn(ex); | ||||
|                 if (ex.InnerException != null) | ||||
|                 { | ||||
|                     _log.Warn("Inner Exception of the error in CommandHandler"); | ||||
|                     _log.Warn(ex.InnerException); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         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 svc in _services) | ||||
|             { | ||||
|                 if (svc is IEarlyBlocker blocker && | ||||
|                     await blocker.TryBlockEarly(guild, usrMsg).ConfigureAwait(false)) | ||||
|                 { | ||||
|                     _log.Info("Blocked User: [{0}] Message: [{1}] Service: [{2}]", usrMsg.Author, usrMsg.Content, svc.GetType().Name); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             var exec2 = Environment.TickCount - execTime;             | ||||
|  | ||||
|             foreach (var svc in _services) | ||||
|             { | ||||
|                 if (svc is IEarlyBlockingExecutor exec &&  | ||||
|                     await exec.TryExecuteEarly(_client, guild, usrMsg).ConfigureAwait(false)) | ||||
|                 { | ||||
|                     _log.Info("User [{0}] executed [{1}] in [{2}]", usrMsg.Author, usrMsg.Content, svc.GetType().Name); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             var exec3 = Environment.TickCount - execTime; | ||||
|  | ||||
|             string messageContent = usrMsg.Content; | ||||
|             foreach (var svc in _services) | ||||
|             { | ||||
|                 string newContent; | ||||
|                 if (svc is IInputTransformer exec &&  | ||||
|                     (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"); | ||||
|             // execute the command and measure the time it took | ||||
|             if (messageContent.StartsWith(prefix) || isPrefixCommand) | ||||
|             { | ||||
|                 var result = await ExecuteCommandAsync(new CommandContext(_client, usrMsg), messageContent, isPrefixCommand ? 1 : prefix.Length, _services, MultiMatchHandling.Best); | ||||
|                 execTime = Environment.TickCount - execTime; | ||||
|  | ||||
|                 if (result.Success) | ||||
|                 { | ||||
|                     await LogSuccessfulExecution(usrMsg, channel as ITextChannel, exec2, exec3, execTime).ConfigureAwait(false); | ||||
|                     await CommandExecuted(usrMsg, result.Info).ConfigureAwait(false); | ||||
|                     return; | ||||
|                 } | ||||
|                 else if (result.Error != null) | ||||
|                 { | ||||
|                     LogErroredExecution(result.Error, usrMsg, channel as ITextChannel, exec2, exec3, execTime); | ||||
|                     if (guild != null) | ||||
|                         await CommandErrored(result.Info, channel as ITextChannel, result.Error); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 await OnMessageNoTrigger(usrMsg).ConfigureAwait(false); | ||||
|             } | ||||
|  | ||||
|             foreach (var svc in _services) | ||||
|             { | ||||
|                 if (svc is ILateExecutor exec) | ||||
|                 { | ||||
|                     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 svc in _services) | ||||
|             { | ||||
|                 if (svc is ILateBlocker exec && | ||||
|                     await exec.TryBlockLate(_client, context.Message, context.Guild, context.Channel, context.User, cmd.Module.GetTopLevelModule().Name, commandName).ConfigureAwait(false)) | ||||
|                 { | ||||
|                     _log.Info("Late blocking User [{0}] Command: [{1}] in [{2}]", context.User, commandName, svc.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)) | ||||
|             { | ||||
|                 lock (errorLogLock) | ||||
|                 { | ||||
|                     var now = DateTime.Now; | ||||
|                     File.AppendAllText($"./command_errors_{now:yyyy-MM-dd}.txt", | ||||
|                         $"[{now:HH:mm-yyyy-MM-dd}]" + Environment.NewLine | ||||
|                         + execResult.Exception.ToString() + Environment.NewLine | ||||
|                         + "------" + Environment.NewLine); | ||||
|                     _log.Warn(execResult.Exception); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return (true, null, cmd); | ||||
|         } | ||||
|  | ||||
|         private readonly object errorLogLock = new object(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										118
									
								
								NadekoBot.Core/Services/CurrencyService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								NadekoBot.Core/Services/CurrencyService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | ||||
| using System; | ||||
| using System.Threading.Tasks; | ||||
| using Discord; | ||||
| using NadekoBot.Extensions; | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using NadekoBot.Services.Database; | ||||
| using NadekoBot.Services; | ||||
|  | ||||
| namespace NadekoBot.Services | ||||
| { | ||||
|     public class CurrencyService : INService | ||||
|     { | ||||
|         private readonly IBotConfigProvider _config; | ||||
|         private readonly DbService _db; | ||||
|  | ||||
|         public CurrencyService(IBotConfigProvider config, DbService db) | ||||
|         { | ||||
|             _config = config; | ||||
|             _db = db; | ||||
|         } | ||||
|  | ||||
|         public async Task<bool> RemoveAsync(IUser author, string reason, long amount, bool sendMessage) | ||||
|         { | ||||
|             var success = await RemoveAsync(author.Id, reason, amount); | ||||
|  | ||||
|             if (success && sendMessage) | ||||
|                 try { await author.SendErrorAsync($"`You lost:` {amount} {_config.BotConfig.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { } | ||||
|  | ||||
|             return success; | ||||
|         } | ||||
|  | ||||
|         public async Task<bool> RemoveAsync(ulong authorId, string reason, long amount, IUnitOfWork uow = null) | ||||
|         { | ||||
|             if (amount < 0) | ||||
|                 throw new ArgumentNullException(nameof(amount)); | ||||
|              | ||||
|             if (uow == null) | ||||
|             { | ||||
|                 using (uow = _db.UnitOfWork) | ||||
|                 { | ||||
|                     var toReturn = InternalRemoveCurrency(authorId, reason, amount, uow); | ||||
|                     await uow.CompleteAsync().ConfigureAwait(false); | ||||
|                     return toReturn; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return InternalRemoveCurrency(authorId, reason, amount, uow); | ||||
|         } | ||||
|  | ||||
|         private bool InternalRemoveCurrency(ulong authorId, string reason, long amount, IUnitOfWork uow) | ||||
|         { | ||||
|             var success = uow.Currency.TryUpdateState(authorId, -amount); | ||||
|             if (!success) | ||||
|                 return false; | ||||
|             uow.CurrencyTransactions.Add(new CurrencyTransaction() | ||||
|             { | ||||
|                 UserId = authorId, | ||||
|                 Reason = reason, | ||||
|                 Amount = -amount, | ||||
|             }); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         public async Task AddToManyAsync(string reason, long amount, params ulong[] userIds) | ||||
|         { | ||||
|             using (var uow = _db.UnitOfWork) | ||||
|             { | ||||
|                 foreach (var userId in userIds) | ||||
|                 { | ||||
|                     var transaction = new CurrencyTransaction() | ||||
|                     { | ||||
|                         UserId = userId, | ||||
|                         Reason = reason, | ||||
|                         Amount = amount, | ||||
|                     }; | ||||
|                     uow.Currency.TryUpdateState(userId, amount); | ||||
|                     uow.CurrencyTransactions.Add(transaction); | ||||
|                 } | ||||
|  | ||||
|                 await uow.CompleteAsync(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public async Task AddAsync(IUser author, string reason, long amount, bool sendMessage) | ||||
|         { | ||||
|             await AddAsync(author.Id, reason, amount); | ||||
|  | ||||
|             if (sendMessage) | ||||
|                 try { await author.SendConfirmAsync($"`You received:` {amount} {_config.BotConfig.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { } | ||||
|         } | ||||
|  | ||||
|         public async Task AddAsync(ulong receiverId, string reason, long amount, IUnitOfWork uow = null) | ||||
|         { | ||||
|             if (amount < 0) | ||||
|                 throw new ArgumentNullException(nameof(amount)); | ||||
|  | ||||
|             var transaction = new CurrencyTransaction() | ||||
|             { | ||||
|                 UserId = receiverId, | ||||
|                 Reason = reason, | ||||
|                 Amount = amount, | ||||
|             }; | ||||
|  | ||||
|             if (uow == null) | ||||
|                 using (uow = _db.UnitOfWork) | ||||
|                 { | ||||
|                     uow.Currency.TryUpdateState(receiverId, amount); | ||||
|                     uow.CurrencyTransactions.Add(transaction); | ||||
|                     await uow.CompleteAsync(); | ||||
|                 } | ||||
|             else | ||||
|             { | ||||
|                 uow.Currency.TryUpdateState(receiverId, amount); | ||||
|                 uow.CurrencyTransactions.Add(transaction); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										33
									
								
								NadekoBot.Core/Services/Database/IUnitOfWork.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								NadekoBot.Core/Services/Database/IUnitOfWork.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| using NadekoBot.Services.Database.Repositories; | ||||
| using System; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace NadekoBot.Services.Database | ||||
| { | ||||
|     public interface IUnitOfWork : IDisposable | ||||
|     { | ||||
|         NadekoContext _context { get; } | ||||
|  | ||||
|         IQuoteRepository Quotes { get; } | ||||
|         IGuildConfigRepository GuildConfigs { get; } | ||||
|         IDonatorsRepository Donators { get; } | ||||
|         IClashOfClansRepository ClashOfClans { get; } | ||||
|         IReminderRepository Reminders { get; } | ||||
|         ISelfAssignedRolesRepository SelfAssignedRoles { get; } | ||||
|         IBotConfigRepository BotConfig { get; } | ||||
|         IUnitConverterRepository ConverterUnits { get; } | ||||
|         ICustomReactionRepository CustomReactions { get; } | ||||
|         ICurrencyRepository Currency { get; } | ||||
|         ICurrencyTransactionsRepository CurrencyTransactions { get; } | ||||
|         IMusicPlaylistRepository MusicPlaylists { get; } | ||||
|         IPokeGameRepository PokeGame { get; } | ||||
|         IWaifuRepository Waifus { get; } | ||||
|         IDiscordUserRepository DiscordUsers { get; } | ||||
|         IWarningsRepository Warnings { get; } | ||||
|         IXpRepository Xp { get; } | ||||
|         IClubRepository Clubs { get; } | ||||
|  | ||||
|         int Complete(); | ||||
|         Task<int> CompleteAsync(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										51
									
								
								NadekoBot.Core/Services/Database/Models/AntiProtection.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								NadekoBot.Core/Services/Database/Models/AntiProtection.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| using System.Collections.Generic; | ||||
| namespace NadekoBot.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; } | ||||
|     } | ||||
|  | ||||
|     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 HashSet<AntiSpamIgnore> IgnoredChannels { get; set; } = new HashSet<AntiSpamIgnore>(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public enum PunishmentAction | ||||
|     { | ||||
|         Mute, | ||||
|         Kick, | ||||
|         Ban, | ||||
|         Softban | ||||
|     } | ||||
|  | ||||
|     public class AntiSpamIgnore : DbEntity | ||||
|     { | ||||
|         public ulong ChannelId { get; set; } | ||||
|  | ||||
|         public override int GetHashCode() => ChannelId.GetHashCode(); | ||||
|  | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             var inst = obj as AntiSpamIgnore; | ||||
|  | ||||
|             if (inst == null) | ||||
|                 return false; | ||||
|  | ||||
|             return inst.ChannelId == ChannelId; | ||||
|              | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										177
									
								
								NadekoBot.Core/Services/Database/Models/BotConfig.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								NadekoBot.Core/Services/Database/Models/BotConfig.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class BotConfig : DbEntity | ||||
|     { | ||||
|         public HashSet<BlacklistItem> Blacklist { get; set; } | ||||
|         public ulong BufferSize { get; set; } = 4000000; | ||||
|         public bool ForwardMessages { get; set; } = true; | ||||
|         public bool ForwardToAllOwners { get; set; } = true; | ||||
|  | ||||
|         public float CurrencyGenerationChance { get; set; } = 0.02f; | ||||
|         public int CurrencyGenerationCooldown { get; set; } = 10; | ||||
|  | ||||
|         public HashSet<ModulePrefix> ModulePrefixes { get; set; } = new HashSet<ModulePrefix>(); | ||||
|  | ||||
|         public List<PlayingStatus> RotatingStatusMessages { get; set; } = new List<PlayingStatus>(); | ||||
|  | ||||
|         public bool RotatingStatuses { get; set; } = false; | ||||
|         public string RemindMessageFormat { get; set; } = "❗⏰**I've been told to remind you to '%message%' now by %user%.**⏰❗"; | ||||
|          | ||||
|         //currency | ||||
|         public string CurrencySign { get; set; } = "🌸"; | ||||
|         public string CurrencyName { get; set; } = "Nadeko Flower"; | ||||
|         public string CurrencyPluralName { get; set; } = "Nadeko Flowers"; | ||||
|  | ||||
|         public int TriviaCurrencyReward { get; set; } = 0; | ||||
|         public int MinimumBetAmount { get; set; } = 2; | ||||
|         public float BetflipMultiplier { get; set; } = 1.95f; | ||||
|         public int CurrencyDropAmount { get; set; } = 1; | ||||
|         public int? CurrencyDropAmountMax { get; set; } = null; | ||||
|         public float Betroll67Multiplier { get; set; } = 2; | ||||
|         public float Betroll91Multiplier { get; set; } = 4; | ||||
|         public float Betroll100Multiplier { get; set; } = 10; | ||||
|         //public HashSet<CommandCost> CommandCosts { get; set; } = new HashSet<CommandCost>(); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// I messed up, don't use | ||||
|         /// </summary> | ||||
|         public HashSet<CommandPrice> CommandPrices { get; set; } = new HashSet<CommandPrice>(); | ||||
|  | ||||
|  | ||||
|         public HashSet<EightBallResponse> EightBallResponses { get; set; } = new HashSet<EightBallResponse>(); | ||||
|         public HashSet<RaceAnimal> RaceAnimals { get; set; } = new HashSet<RaceAnimal>(); | ||||
|  | ||||
|         public string DMHelpString { get; set; } = "Type `.h` for help."; | ||||
|         public string HelpString { get; set; } = @"To add me to your server, use this link -> <https://discordapp.com/oauth2/authorize?client_id={0}&scope=bot&permissions=66186303> | ||||
| You can use `{1}modules` command to see a list of all modules. | ||||
| You can use `{1}commands ModuleName` | ||||
| (for example `{1}commands Administration`) to see a list of all of the commands in that module. | ||||
| For a specific command help, use `{1}h CommandName` (for example {1}h {1}q) | ||||
|  | ||||
|  | ||||
| **LIST OF COMMANDS CAN BE FOUND ON THIS LINK** | ||||
| <http://nadekobot.readthedocs.io/en/latest/Commands%20List/> | ||||
|  | ||||
|  | ||||
| Nadeko Support Server: https://discord.gg/nadekobot"; | ||||
|  | ||||
|         public int MigrationVersion { get; set; } | ||||
|  | ||||
|         public string OkColor { get; set; } = "71cd40"; | ||||
|         public string ErrorColor { get; set; } = "ee281f"; | ||||
|         public string Locale { get; set; } = null; | ||||
|         public List<StartupCommand> StartupCommands { get; set; } | ||||
|         public HashSet<BlockedCmdOrMdl> BlockedCommands { get; set; } | ||||
|         public HashSet<BlockedCmdOrMdl> BlockedModules { get; set; } | ||||
|         public int PermissionVersion { get; set; } | ||||
|         public string DefaultPrefix { get; set; } = "."; | ||||
|         public bool CustomReactionsStartWith { get; set; } = false; | ||||
|         public int XpPerMessage { get; set; } = 3; | ||||
|         public int XpMinutesTimeout { get; set; } = 5; | ||||
|     } | ||||
|  | ||||
|     public class BlockedCmdOrMdl : DbEntity | ||||
|     { | ||||
|         public string Name { get; set; } | ||||
|  | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             if (obj == null || GetType() != obj.GetType()) | ||||
|             { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             return ((BlockedCmdOrMdl)obj).Name.ToLowerInvariant() == Name.ToLowerInvariant(); | ||||
|         } | ||||
|  | ||||
|         public override int GetHashCode() => Name.GetHashCode(); | ||||
|     } | ||||
|  | ||||
|     public class StartupCommand : DbEntity, IIndexed | ||||
|     { | ||||
|         public int Index { get; set; } | ||||
|         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 class PlayingStatus :DbEntity | ||||
|     { | ||||
|         public string Status { get; set; } | ||||
|     } | ||||
|  | ||||
|     public class BlacklistItem : DbEntity | ||||
|     { | ||||
|         public ulong ItemId { get; set; } | ||||
|         public BlacklistType Type { get; set; } | ||||
|     } | ||||
|  | ||||
|     public enum BlacklistType | ||||
|     { | ||||
|         Server, | ||||
|         Channel, | ||||
|         User | ||||
|     } | ||||
|  | ||||
|     public class EightBallResponse : DbEntity | ||||
|     { | ||||
|         public string Text { get; set; } | ||||
|  | ||||
|         public override int GetHashCode() | ||||
|         { | ||||
|             return Text.GetHashCode(); | ||||
|         } | ||||
|  | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             if (!(obj is EightBallResponse)) | ||||
|                 return base.Equals(obj); | ||||
|  | ||||
|             return ((EightBallResponse)obj).Text == Text; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public class RaceAnimal : DbEntity | ||||
|     { | ||||
|         public string Icon { get; set; } | ||||
|         public string Name { get; set; } | ||||
|  | ||||
|         public override int GetHashCode() | ||||
|         { | ||||
|             return Icon.GetHashCode(); | ||||
|         } | ||||
|  | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             if (!(obj is RaceAnimal)) | ||||
|                 return base.Equals(obj); | ||||
|  | ||||
|             return ((RaceAnimal)obj).Icon == Icon; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public class ModulePrefix : DbEntity | ||||
|     { | ||||
|         public string ModuleName { get; set; } | ||||
|         public string Prefix { get; set; } | ||||
|  | ||||
|         public override int GetHashCode() | ||||
|         { | ||||
|             return ModuleName.GetHashCode(); | ||||
|         } | ||||
|  | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             if(!(obj is ModulePrefix)) | ||||
|                 return base.Equals(obj); | ||||
|  | ||||
|             return ((ModulePrefix)obj).ModuleName == ModuleName; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										22
									
								
								NadekoBot.Core/Services/Database/Models/ClashCaller.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								NadekoBot.Core/Services/Database/Models/ClashCaller.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| using System; | ||||
| using System.ComponentModel.DataAnnotations.Schema; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class ClashCaller : DbEntity | ||||
|     { | ||||
|         public int? SequenceNumber { get; set; } = null; | ||||
|         public string CallUser { get; set; } | ||||
|  | ||||
|         public DateTime TimeAdded { get; set; } | ||||
|  | ||||
|         public bool BaseDestroyed { get; set; } | ||||
|  | ||||
|         public int Stars { get; set; } = 3; | ||||
|  | ||||
|         public int ClashWarId { get; set; } | ||||
|  | ||||
|         [ForeignKey(nameof(ClashWarId))] | ||||
|         public ClashWar ClashWar { get; set; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										32
									
								
								NadekoBot.Core/Services/Database/Models/ClashWar.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								NadekoBot.Core/Services/Database/Models/ClashWar.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| using Discord; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.ComponentModel.DataAnnotations.Schema; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class ClashWar : DbEntity | ||||
|     { | ||||
|         public string EnemyClan { get; set; } | ||||
|         public int Size { get; set; } | ||||
|         public StateOfWar WarState { get; set; } = StateOfWar.Created; | ||||
|         public DateTime StartedAt { get; set; } | ||||
|  | ||||
|         public ulong GuildId { get; set; } | ||||
|         public ulong ChannelId { get; set; } | ||||
|  | ||||
|         [NotMapped] | ||||
|         public ITextChannel Channel { get; set; } | ||||
|  | ||||
|         public List<ClashCaller> Bases { get; set; } = new List<ClashCaller>(); | ||||
|     } | ||||
|  | ||||
|     public enum DestroyStars | ||||
|     { | ||||
|         One, Two, Three | ||||
|     } | ||||
|     public enum StateOfWar | ||||
|     { | ||||
|         Started, Ended, Created | ||||
|     } | ||||
| } | ||||
							
								
								
									
										47
									
								
								NadekoBot.Core/Services/Database/Models/ClubInfo.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								NadekoBot.Core/Services/Database/Models/ClubInfo.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.ComponentModel.DataAnnotations; | ||||
|  | ||||
| namespace NadekoBot.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 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; } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,8 @@ | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class CommandCooldown : DbEntity | ||||
|     { | ||||
|         public int Seconds { get; set; } | ||||
|         public string CommandName { get; set; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										21
									
								
								NadekoBot.Core/Services/Database/Models/CommandCost.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								NadekoBot.Core/Services/Database/Models/CommandCost.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class CommandCost : DbEntity | ||||
|     { | ||||
|         public int Cost { get; set; } | ||||
|         public string CommandName { get; set; } | ||||
|  | ||||
|         public override int GetHashCode() => | ||||
|             CommandName.GetHashCode(); | ||||
|  | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             var instance = obj as CommandCost; | ||||
|  | ||||
|             if (instance == null) | ||||
|                 return false; | ||||
|  | ||||
|             return instance.CommandName == CommandName; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										9
									
								
								NadekoBot.Core/Services/Database/Models/CommandPrice.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								NadekoBot.Core/Services/Database/Models/CommandPrice.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class CommandPrice : DbEntity | ||||
|     { | ||||
|         public int Price { get; set; } | ||||
|         //this is unique | ||||
|         public string CommandName { get; set; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										47
									
								
								NadekoBot.Core/Services/Database/Models/ConvertUnit.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								NadekoBot.Core/Services/Database/Models/ConvertUnit.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| using System.ComponentModel; | ||||
| using System.ComponentModel.DataAnnotations.Schema; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class ConvertUnit : DbEntity | ||||
|     { | ||||
|         public ConvertUnit() { } | ||||
|         [NotMapped] | ||||
|         private string[] _triggersValue; | ||||
|         [NotMapped] | ||||
|         public string[] Triggers | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return _triggersValue ?? (_triggersValue = InternalTrigger.Split('|')); | ||||
|             } | ||||
|             set | ||||
|             { | ||||
|                 _triggersValue = value; | ||||
|                 InternalTrigger = string.Join("|", _triggersValue); | ||||
|             } | ||||
|         } | ||||
|         //protected or private? | ||||
|         /// <summary> | ||||
|         /// DO NOT CALL THIS | ||||
|         /// </summary> | ||||
|         [EditorBrowsable(EditorBrowsableState.Never)] | ||||
|         public string InternalTrigger { get; set; } | ||||
|         public string UnitType { get; set; } | ||||
|         public decimal Modifier { get; set; } | ||||
|  | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             var cu = obj as ConvertUnit; | ||||
|             if (cu == null) | ||||
|                 return false; | ||||
|             return cu.UnitType == this.UnitType; | ||||
|         } | ||||
|  | ||||
|         public override int GetHashCode() | ||||
|         { | ||||
|             return this.UnitType.GetHashCode(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										8
									
								
								NadekoBot.Core/Services/Database/Models/Currency.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								NadekoBot.Core/Services/Database/Models/Currency.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class Currency : DbEntity | ||||
|     { | ||||
|         public ulong UserId { get; set; } | ||||
|         public long Amount { get; set; } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,9 @@ | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class CurrencyTransaction : DbEntity | ||||
|     { | ||||
|         public long Amount { get; set; } | ||||
|         public string Reason { get; set; } | ||||
|         public ulong UserId { get; set; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										33
									
								
								NadekoBot.Core/Services/Database/Models/CustomReaction.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								NadekoBot.Core/Services/Database/Models/CustomReaction.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| using Newtonsoft.Json; | ||||
| using System.ComponentModel.DataAnnotations.Schema; | ||||
| using System.Text.RegularExpressions; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class CustomReaction : DbEntity | ||||
|     { | ||||
|         public ulong? GuildId { get; set; } | ||||
|  | ||||
|         [NotMapped] | ||||
|         [JsonIgnore] | ||||
|         public Regex Regex { get; set; } | ||||
|         public string Response { get; set; } | ||||
|         public string Trigger { get; set; } | ||||
|  | ||||
|         public bool IsRegex { get; set; } | ||||
|         public bool OwnerOnly { get; set; } | ||||
|         public bool AutoDeleteTrigger { get; set; } | ||||
|         public bool DmResponse { get; set; } | ||||
|  | ||||
|         [JsonIgnore] | ||||
|         public bool IsGlobal => !GuildId.HasValue; | ||||
|  | ||||
|         public bool ContainsAnywhere { get; set; } | ||||
|     } | ||||
|  | ||||
|     public class ReactionResponse : DbEntity | ||||
|     { | ||||
|         public bool OwnerOnly { get; set; } | ||||
|         public string Text { get; set; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										12
									
								
								NadekoBot.Core/Services/Database/Models/DbEntity.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								NadekoBot.Core/Services/Database/Models/DbEntity.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| using System; | ||||
| using System.ComponentModel.DataAnnotations; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class DbEntity | ||||
|     { | ||||
|         [Key] | ||||
|         public int Id { get; set; } | ||||
|         public DateTime? DateAdded { get; set; } = DateTime.UtcNow; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										35
									
								
								NadekoBot.Core/Services/Database/Models/DiscordUser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								NadekoBot.Core/Services/Database/Models/DiscordUser.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| using System; | ||||
|  | ||||
| namespace NadekoBot.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 XpNotificationType NotifyOnLevelUp { 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; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										9
									
								
								NadekoBot.Core/Services/Database/Models/Donator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								NadekoBot.Core/Services/Database/Models/Donator.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class Donator : DbEntity | ||||
|     { | ||||
|         public ulong UserId { get; set; } | ||||
|         public string Name { get; set; } | ||||
|         public int Amount { get; set; } = 0; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										23
									
								
								NadekoBot.Core/Services/Database/Models/FeedSub.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								NadekoBot.Core/Services/Database/Models/FeedSub.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| namespace NadekoBot.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() ^ GuildConfigId.GetHashCode(); | ||||
|         } | ||||
|  | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             return obj is FeedSub s | ||||
|                 ? s.Url == Url && s.GuildConfigId == GuildConfigId | ||||
|                 : false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										31
									
								
								NadekoBot.Core/Services/Database/Models/FollowedStream.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								NadekoBot.Core/Services/Database/Models/FollowedStream.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class FollowedStream : DbEntity | ||||
|     { | ||||
|         public ulong ChannelId { get; set; } | ||||
|         public string Username { get; set; } | ||||
|         public FollowedStreamType Type { get; set; } | ||||
|         public ulong GuildId { get; set; } | ||||
|  | ||||
|         public enum FollowedStreamType | ||||
|         { | ||||
|             Twitch, Smashcast, Mixer | ||||
|         } | ||||
|  | ||||
|         public override int GetHashCode() =>  | ||||
|             ChannelId.GetHashCode() ^  | ||||
|             Username.GetHashCode() ^  | ||||
|             Type.GetHashCode(); | ||||
|  | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             var fs = obj as FollowedStream; | ||||
|             if (fs == null) | ||||
|                 return false; | ||||
|  | ||||
|             return fs.ChannelId == ChannelId &&  | ||||
|                    fs.Username.ToLowerInvariant().Trim() == Username.ToLowerInvariant().Trim() && | ||||
|                    fs.Type == Type; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										254
									
								
								NadekoBot.Core/Services/Database/Models/GuildConfig.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										254
									
								
								NadekoBot.Core/Services/Database/Models/GuildConfig.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,254 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class GuildConfig : DbEntity | ||||
|     { | ||||
|         public ulong GuildId { get; set; } | ||||
|  | ||||
|         public string Prefix { get; set; } = null; | ||||
|  | ||||
|         public bool DeleteMessageOnCommand { get; set; } | ||||
|         public ulong AutoAssignRoleId { 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; } = "Nadeko"; | ||||
|  | ||||
|         public HashSet<CommandCooldown> CommandCooldowns { get; set; } = new HashSet<CommandCooldown>(); | ||||
|  | ||||
|         //filtering | ||||
|         public bool FilterInvites { get; set; } | ||||
|         public HashSet<FilterChannelId> FilterInvitesChannelIds { get; set; } = new HashSet<FilterChannelId>(); | ||||
|  | ||||
|         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 HashSet<GuildRepeater> GuildRepeaters { get; set; } = new HashSet<GuildRepeater>(); | ||||
|  | ||||
|         public AntiRaidSetting AntiRaidSetting { get; set; } | ||||
|         public AntiSpamSetting AntiSpamSetting { 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<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 List<ProtectionIgnoredChannel> ProtectionIgnoredChannels { get; set; } = new List<ProtectionIgnoredChannel>(); | ||||
|     } | ||||
|  | ||||
|     public class NsfwBlacklitedTag : DbEntity | ||||
|     { | ||||
|         public string Tag { get; set; } | ||||
|  | ||||
|         public override int GetHashCode() | ||||
|         { | ||||
|             return Tag.GetHashCode(); | ||||
|         } | ||||
|  | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             return obj is NsfwBlacklitedTag x | ||||
|                 ? x.Tag == Tag | ||||
|                 : false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     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(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     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(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public class WarningPunishment : DbEntity | ||||
|     { | ||||
|         public int Count { get; set; } | ||||
|         public PunishmentAction Punishment { get; set; } | ||||
|         public int Time { get; set; } | ||||
|     } | ||||
|  | ||||
|     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(); | ||||
|         //} | ||||
|     } | ||||
|  | ||||
|     public class VcRoleInfo : DbEntity | ||||
|     { | ||||
|         public ulong VoiceChannelId { get; set; } | ||||
|         public ulong RoleId { get; set; } | ||||
|     } | ||||
|  | ||||
|     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) | ||||
|         { | ||||
|             var ut = obj as UnmuteTimer; | ||||
|             if (ut == null) | ||||
|                 return false; | ||||
|             return ut.UserId == UserId; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public class FilterChannelId : DbEntity | ||||
|     { | ||||
|         public ulong ChannelId { get; set; } | ||||
|     } | ||||
|  | ||||
|     public class FilteredWord : DbEntity | ||||
|     { | ||||
|         public string Word { get; set; } | ||||
|     } | ||||
|  | ||||
|     public class MutedUserId : DbEntity | ||||
|     { | ||||
|         public ulong UserId { get; set; } | ||||
|  | ||||
|         public override int GetHashCode() | ||||
|         { | ||||
|             return UserId.GetHashCode(); | ||||
|         } | ||||
|  | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             var mui = obj as MutedUserId; | ||||
|             if (mui == null) | ||||
|                 return false; | ||||
|  | ||||
|             return mui.UserId == this.UserId; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public class GCChannelId : DbEntity | ||||
|     { | ||||
|         public ulong ChannelId { get; set; } | ||||
|  | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             var gc = obj as GCChannelId; | ||||
|             if (gc == null) | ||||
|                 return false; | ||||
|  | ||||
|             return gc.ChannelId == this.ChannelId; | ||||
|         } | ||||
|  | ||||
|         public override int GetHashCode() => | ||||
|             this.ChannelId.GetHashCode(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,8 @@ | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class IgnoredLogChannel : DbEntity | ||||
|     { | ||||
|         public LogSetting LogSetting { get; set; } | ||||
|         public ulong ChannelId { get; set; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										105
									
								
								NadekoBot.Core/Services/Database/Models/LogSetting.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								NadekoBot.Core/Services/Database/Models/LogSetting.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.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
									
								
								NadekoBot.Core/Services/Database/Models/MusicPlaylist.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								NadekoBot.Core/Services/Database/Models/MusicPlaylist.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.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>(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										130
									
								
								NadekoBot.Core/Services/Database/Models/Permission.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								NadekoBot.Core/Services/Database/Models/Permission.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.ComponentModel.DataAnnotations.Schema; | ||||
| using System.Diagnostics; | ||||
|  | ||||
| namespace NadekoBot.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, | ||||
|             }; | ||||
|  | ||||
|         //[NotMapped] | ||||
|         //private static Permission AllowAllPerm => new Permission() | ||||
|         //{ | ||||
|         //    PrimaryTarget = PrimaryPermissionType.Server, | ||||
|         //    PrimaryTargetId = 0, | ||||
|         //    SecondaryTarget = SecondaryPermissionType.AllModules, | ||||
|         //    SecondaryTargetName = "*", | ||||
|         //    State = true, | ||||
|         //}; | ||||
|         //[NotMapped] | ||||
|         //private static Permission BlockNsfwPerm => new Permission() | ||||
|         //{ | ||||
|         //    PrimaryTarget = PrimaryPermissionType.Server, | ||||
|         //    PrimaryTargetId = 0, | ||||
|         //    SecondaryTarget = SecondaryPermissionType.Module, | ||||
|         //    SecondaryTargetName = "nsfw", | ||||
|         //    State = false, | ||||
|         //}; | ||||
|  | ||||
|         //public Permission Clone() => new Permission() | ||||
|         //{ | ||||
|         //    PrimaryTarget = PrimaryTarget, | ||||
|         //    SecondaryTarget = SecondaryTarget, | ||||
|         //    PrimaryTargetId = PrimaryTargetId, | ||||
|         //    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 State { get; set; } | ||||
|  | ||||
|         [NotMapped] | ||||
|         public static Permissionv2 AllowAllPerm => new Permissionv2() | ||||
|         { | ||||
|             PrimaryTarget = PrimaryPermissionType.Server, | ||||
|             PrimaryTargetId = 0, | ||||
|             SecondaryTarget = SecondaryPermissionType.AllModules, | ||||
|             SecondaryTargetName = "*", | ||||
|             State = true, | ||||
|             Index = 0, | ||||
|         }; | ||||
|         [NotMapped] | ||||
|         private static Permissionv2 BlockNsfwPerm => new Permissionv2() | ||||
|         { | ||||
|             PrimaryTarget = PrimaryPermissionType.Server, | ||||
|             PrimaryTargetId = 0, | ||||
|             SecondaryTarget = SecondaryPermissionType.Module, | ||||
|             SecondaryTargetName = "nsfw", | ||||
|             State = false, | ||||
|             Index = 1 | ||||
|         }; | ||||
|  | ||||
|         public static List<Permissionv2> GetDefaultPermlist => | ||||
|             new List<Permissionv2> | ||||
|             { | ||||
|                 BlockNsfwPerm, | ||||
|                 AllowAllPerm | ||||
|             }; | ||||
|  | ||||
|         //public Permission Clone() => new Permission() | ||||
|         //{ | ||||
|         //    PrimaryTarget = PrimaryTarget, | ||||
|         //    SecondaryTarget = SecondaryTarget, | ||||
|         //    PrimaryTargetId = PrimaryTargetId, | ||||
|         //    SecondaryTargetName = SecondaryTargetName, | ||||
|         //    State = State, | ||||
|         //}; | ||||
|     } | ||||
|     public enum PrimaryPermissionType | ||||
|     { | ||||
|         User, | ||||
|         Channel, | ||||
|         Role, | ||||
|         Server | ||||
|     } | ||||
|  | ||||
|     public enum SecondaryPermissionType | ||||
|     { | ||||
|         Module, | ||||
|         Command, | ||||
|         AllModules | ||||
|     } | ||||
| } | ||||
							
								
								
									
										19
									
								
								NadekoBot.Core/Services/Database/Models/PlaylistSong.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								NadekoBot.Core/Services/Database/Models/PlaylistSong.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| namespace NadekoBot.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 | ||||
|     } | ||||
| } | ||||
							
								
								
									
										8
									
								
								NadekoBot.Core/Services/Database/Models/PokeType.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								NadekoBot.Core/Services/Database/Models/PokeType.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class UserPokeTypes : DbEntity | ||||
|     { | ||||
|         public ulong UserId { get; set; } | ||||
|         public string type { get; set; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								NadekoBot.Core/Services/Database/Models/Quote.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								NadekoBot.Core/Services/Database/Models/Quote.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| using System.ComponentModel.DataAnnotations; | ||||
|  | ||||
| namespace NadekoBot.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; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										14
									
								
								NadekoBot.Core/Services/Database/Models/Reminder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								NadekoBot.Core/Services/Database/Models/Reminder.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| using System; | ||||
|  | ||||
| namespace NadekoBot.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; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										18
									
								
								NadekoBot.Core/Services/Database/Models/Repeater.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								NadekoBot.Core/Services/Database/Models/Repeater.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| using System; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class Repeater : DbEntity | ||||
|     { | ||||
|         public ulong GuildId { get; set; } | ||||
|         public ulong ChannelId { get; set; } | ||||
|         public string Message { get; set; } | ||||
|         public TimeSpan Interval { get; set; } | ||||
|         public TimeSpan? StartTimeOfDay { get; set; } | ||||
|     } | ||||
|  | ||||
|     public class GuildRepeater : Repeater | ||||
|     { | ||||
|  | ||||
|     } | ||||
| } | ||||
							
								
								
									
										12
									
								
								NadekoBot.Core/Services/Database/Models/RewardedUser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								NadekoBot.Core/Services/Database/Models/RewardedUser.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| using System; | ||||
|  | ||||
| namespace NadekoBot.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,8 @@ | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class SelfAssignedRole : DbEntity | ||||
|     { | ||||
|         public ulong GuildId { get; set; } | ||||
|         public ulong RoleId { get; set; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										45
									
								
								NadekoBot.Core/Services/Database/Models/ShopEntry.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								NadekoBot.Core/Services/Database/Models/ShopEntry.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.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(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,83 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.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) | ||||
|         { | ||||
|             var x = obj as StreamRoleBlacklistedUser; | ||||
|  | ||||
|             if (x == null) | ||||
|                 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) | ||||
|         { | ||||
|             var x = obj as StreamRoleWhitelistedUser; | ||||
|  | ||||
|             if (x == null) | ||||
|                 return false; | ||||
|  | ||||
|             return x.UserId == UserId; | ||||
|         } | ||||
|  | ||||
|         public override int GetHashCode() | ||||
|         { | ||||
|             return UserId.GetHashCode(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								NadekoBot.Core/Services/Database/Models/UserXpStats.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								NadekoBot.Core/Services/Database/Models/UserXpStats.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| using System; | ||||
|  | ||||
| namespace NadekoBot.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 XpNotificationType NotifyOnLevelUp { get; set; } | ||||
|         public DateTime LastLevelUp { get; set; } = DateTime.UtcNow; | ||||
|     } | ||||
|  | ||||
|     public enum XpNotificationType { None, Dm, Channel } | ||||
| } | ||||
| @@ -0,0 +1,8 @@ | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class IgnoredVoicePresenceChannel : DbEntity | ||||
|     { | ||||
|         public LogSetting LogSetting { get; set; } | ||||
|         public ulong ChannelId { get; set; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										46
									
								
								NadekoBot.Core/Services/Database/Models/Waifu.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								NadekoBot.Core/Services/Database/Models/Waifu.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| using NadekoBot.Extensions; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.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 (Claimer != 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}"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										87
									
								
								NadekoBot.Core/Services/Database/Models/WaifuItem.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								NadekoBot.Core/Services/Database/Models/WaifuItem.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| using System; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Models | ||||
| { | ||||
|     public class WaifuItem : DbEntity | ||||
|     { | ||||
|         public string ItemEmoji { get; set; } | ||||
|         public int Price { get; set; } | ||||
|         public ItemName Item { get; set; } | ||||
|  | ||||
|         public enum ItemName | ||||
|         { | ||||
|             Cookie, | ||||
|             Rose, | ||||
|             LoveLetter, | ||||
|             Chocolate, | ||||
|             Rice, | ||||
|             MovieTicket, | ||||
|             Book, | ||||
|             Lipstick, | ||||
|             Laptop, | ||||
|             Violin, | ||||
|             Ring, | ||||
|             Helicopter, | ||||
|         } | ||||
|  | ||||
|         public WaifuItem() | ||||
|         { | ||||
|  | ||||
|         } | ||||
|  | ||||
|         public WaifuItem(string itemEmoji, int price, ItemName item) | ||||
|         { | ||||
|             ItemEmoji = itemEmoji; | ||||
|             Price = price; | ||||
|             Item = item; | ||||
|         } | ||||
|  | ||||
|         public static WaifuItem GetItem(ItemName itemName) | ||||
|         { | ||||
|             switch (itemName) | ||||
|             { | ||||
|                 case ItemName.Cookie: | ||||
|                     return new WaifuItem("🍪", 10, itemName); | ||||
|                 case ItemName.Rose: | ||||
|                     return new WaifuItem("🌹", 50, itemName); | ||||
|                 case ItemName.LoveLetter: | ||||
|                     return new WaifuItem("💌", 100, itemName); | ||||
|                 case ItemName.Chocolate: | ||||
|                     return new WaifuItem("🍫", 200, itemName); | ||||
|                 case ItemName.Rice: | ||||
|                     return new WaifuItem("🍚", 400, itemName); | ||||
|                 case ItemName.MovieTicket: | ||||
|                     return new WaifuItem("🎟", 800, itemName); | ||||
|                 case ItemName.Book: | ||||
|                     return new WaifuItem("📔", 1500, itemName); | ||||
|                 case ItemName.Lipstick: | ||||
|                     return new WaifuItem("💄", 3000, itemName); | ||||
|                 case ItemName.Laptop: | ||||
|                     return new WaifuItem("💻", 5000, itemName); | ||||
|                 case ItemName.Violin: | ||||
|                     return new WaifuItem("🎻", 7500, itemName); | ||||
|                 case ItemName.Ring: | ||||
|                     return new WaifuItem("💍", 10000, itemName); | ||||
|                 case ItemName.Helicopter: | ||||
|                     return new WaifuItem("🚁", 20000, itemName); | ||||
|                 default: | ||||
|                     throw new ArgumentException(nameof(itemName)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
| 🍪 Cookie 10 | ||||
| 🌹  Rose 50 | ||||
| 💌 Love Letter 100 | ||||
| 🍫  Chocolate 200 | ||||
| 🍚 Rice 400 | ||||
| 🎟  Movie Ticket 800 | ||||
| 📔 Book 1.5k | ||||
| 💄  Lipstick 3k | ||||
| 💻 Laptop 5k | ||||
| 🎻 Violin 7.5k | ||||
| 💍 Ring 10k | ||||
| */ | ||||
							
								
								
									
										21
									
								
								NadekoBot.Core/Services/Database/Models/WaifuUpdate.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								NadekoBot.Core/Services/Database/Models/WaifuUpdate.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| namespace NadekoBot.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 | ||||
|     } | ||||
| } | ||||
							
								
								
									
										12
									
								
								NadekoBot.Core/Services/Database/Models/Warning.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								NadekoBot.Core/Services/Database/Models/Warning.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| namespace NadekoBot.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; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										53
									
								
								NadekoBot.Core/Services/Database/Models/XpSettings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								NadekoBot.Core/Services/Database/Models/XpSettings.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.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 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; } | ||||
|  | ||||
|         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 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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										355
									
								
								NadekoBot.Core/Services/Database/NadekoContext.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										355
									
								
								NadekoBot.Core/Services/Database/NadekoContext.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,355 @@ | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using NadekoBot.Extensions; | ||||
| using System; | ||||
| using Microsoft.EntityFrameworkCore.Design; | ||||
| using Microsoft.Data.Sqlite; | ||||
| using System.IO; | ||||
|  | ||||
| namespace NadekoBot.Services.Database | ||||
| { | ||||
|     public class NadekoContextFactory : IDesignTimeDbContextFactory<NadekoContext> | ||||
|     {         | ||||
|         public NadekoContext CreateDbContext(string[] args) | ||||
|         { | ||||
|             var optionsBuilder = new DbContextOptionsBuilder<NadekoContext>(); | ||||
|             var builder = new SqliteConnectionStringBuilder("Data Source=data/NadekoBot.db"); | ||||
|             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<Quote> Quotes { get; set; } | ||||
|         public DbSet<Donator> Donators { get; set; } | ||||
|         public DbSet<GuildConfig> GuildConfigs { get; set; } | ||||
|         public DbSet<ClashWar> ClashOfClans { get; set; } | ||||
|         public DbSet<ClashCaller> ClashCallers { get; set; } | ||||
|         public DbSet<Reminder> Reminders { get; set; } | ||||
|         public DbSet<SelfAssignedRole> SelfAssignableRoles { get; set; } | ||||
|         public DbSet<BotConfig> BotConfig { get; set; } | ||||
|         public DbSet<Currency> Currency { get; set; } | ||||
|         public DbSet<ConvertUnit> ConversionUnits { get; set; } | ||||
|         public DbSet<MusicPlaylist> MusicPlaylists { get; set; } | ||||
|         public DbSet<CustomReaction> CustomReactions { get; set; } | ||||
|         public DbSet<CurrencyTransaction> CurrencyTransactions { get; set; } | ||||
|         public DbSet<UserPokeTypes> PokeGame { 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; } | ||||
|  | ||||
|         //orphans xD | ||||
|         public DbSet<EightBallResponse> EightBallResponses { get; set; } | ||||
|         public DbSet<RaceAnimal> RaceAnimals { get; set; } | ||||
|         public DbSet<ModulePrefix> ModulePrefixes { get; set; } | ||||
|         public DbSet<RewardedUser> RewardedUsers { get; set; } | ||||
|  | ||||
|         public NadekoContext(DbContextOptions<NadekoContext> options) : base(options) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         public void EnsureSeedData() | ||||
|         { | ||||
|             if (!BotConfig.Any()) | ||||
|             { | ||||
|                 var bc = new BotConfig(); | ||||
|  | ||||
|                 bc.RaceAnimals.AddRange(new HashSet<RaceAnimal> | ||||
|                 { | ||||
|                     new RaceAnimal { Icon = "🐼", Name = "Panda" }, | ||||
|                     new RaceAnimal { Icon = "🐻", Name = "Bear" }, | ||||
|                     new RaceAnimal { Icon = "🐧", Name = "Pengu" }, | ||||
|                     new RaceAnimal { Icon = "🐨", Name = "Koala" }, | ||||
|                     new RaceAnimal { Icon = "🐬", Name = "Dolphin" }, | ||||
|                     new RaceAnimal { Icon = "🐞", Name = "Ladybird" }, | ||||
|                     new RaceAnimal { Icon = "🦀", Name = "Crab" }, | ||||
|                     new RaceAnimal { Icon = "🦄", Name = "Unicorn" } | ||||
|                 }); | ||||
|                 bc.EightBallResponses.AddRange(new HashSet<EightBallResponse> | ||||
|                 { | ||||
|                     new EightBallResponse() { Text = "Most definitely yes" }, | ||||
|                     new EightBallResponse() { Text = "For sure" }, | ||||
|                     new EightBallResponse() { Text = "Totally!" }, | ||||
|                     new EightBallResponse() { Text = "Of course!" }, | ||||
|                     new EightBallResponse() { Text = "As I see it, yes" }, | ||||
|                     new EightBallResponse() { Text = "My sources say yes" }, | ||||
|                     new EightBallResponse() { Text = "Yes" }, | ||||
|                     new EightBallResponse() { Text = "Most likely" }, | ||||
|                     new EightBallResponse() { Text = "Perhaps" }, | ||||
|                     new EightBallResponse() { Text = "Maybe" }, | ||||
|                     new EightBallResponse() { Text = "Not sure" }, | ||||
|                     new EightBallResponse() { Text = "It is uncertain" }, | ||||
|                     new EightBallResponse() { Text = "Ask me again later" }, | ||||
|                     new EightBallResponse() { Text = "Don't count on it" }, | ||||
|                     new EightBallResponse() { Text = "Probably not" }, | ||||
|                     new EightBallResponse() { Text = "Very doubtful" }, | ||||
|                     new EightBallResponse() { Text = "Most likely no" }, | ||||
|                     new EightBallResponse() { Text = "Nope" }, | ||||
|                     new EightBallResponse() { Text = "No" }, | ||||
|                     new EightBallResponse() { Text = "My sources say no" }, | ||||
|                     new EightBallResponse() { Text = "Dont even think about it" }, | ||||
|                     new EightBallResponse() { Text = "Definitely no" }, | ||||
|                     new EightBallResponse() { Text = "NO - It may cause disease contraction" } | ||||
|                 }); | ||||
|  | ||||
|                 BotConfig.Add(bc); | ||||
|  | ||||
|                 this.SaveChanges(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         protected override void OnModelCreating(ModelBuilder modelBuilder) | ||||
|         { | ||||
|             #region QUOTES | ||||
|              | ||||
|             //var quoteEntity = modelBuilder.Entity<Quote>(); | ||||
|  | ||||
|             #endregion | ||||
|              | ||||
|             #region Donators | ||||
|  | ||||
|             var donatorEntity = modelBuilder.Entity<Donator>(); | ||||
|             donatorEntity | ||||
|                 .HasIndex(d => d.UserId) | ||||
|                 .IsUnique(); | ||||
|  | ||||
|             #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<FeedSub>() | ||||
|                 .HasAlternateKey(x => new { x.GuildConfigId, x.Url }); | ||||
|  | ||||
|             //modelBuilder.Entity<ProtectionIgnoredChannel>() | ||||
|             //    .HasAlternateKey(c => new { c.ChannelId, c.ProtectionType }); | ||||
|  | ||||
|             #endregion | ||||
|  | ||||
|             #region streamrole | ||||
|             modelBuilder.Entity<StreamRoleSettings>() | ||||
|                 .HasOne(x => x.GuildConfig) | ||||
|                 .WithOne(x => x.StreamRole); | ||||
|             #endregion | ||||
|  | ||||
|             #region BotConfig | ||||
|             var botConfigEntity = modelBuilder.Entity<BotConfig>(); | ||||
|  | ||||
|             botConfigEntity.Property(x => x.XpMinutesTimeout) | ||||
|                 .HasDefaultValue(5); | ||||
|  | ||||
|             botConfigEntity.Property(x => x.XpPerMessage) | ||||
|                 .HasDefaultValue(3); | ||||
|  | ||||
|             //botConfigEntity | ||||
|             //    .HasMany(c => c.ModulePrefixes) | ||||
|             //    .WithOne(mp => mp.BotConfig) | ||||
|             //    .HasForeignKey(mp => mp.BotConfigId); | ||||
|  | ||||
|             #endregion | ||||
|  | ||||
|             #region ClashOfClans | ||||
|  | ||||
|             var callersEntity = modelBuilder.Entity<ClashCaller>(); | ||||
|             callersEntity | ||||
|                 .HasOne(c => c.ClashWar) | ||||
|                 .WithMany(c => c.Bases); | ||||
|  | ||||
|             #endregion | ||||
|  | ||||
|             #region Self Assignable Roles | ||||
|  | ||||
|             var selfassignableRolesEntity = modelBuilder.Entity<SelfAssignedRole>(); | ||||
|  | ||||
|             selfassignableRolesEntity | ||||
|                 .HasIndex(s => new { s.GuildId, s.RoleId }) | ||||
|                 .IsUnique(); | ||||
|  | ||||
|             #endregion | ||||
|  | ||||
|             #region Currency | ||||
|             var currencyEntity = modelBuilder.Entity<Currency>(); | ||||
|  | ||||
|             currencyEntity | ||||
|                 .HasIndex(c => c.UserId) | ||||
|                 .IsUnique(); | ||||
|             #endregion | ||||
|  | ||||
|             #region Permission | ||||
|             var permissionEntity = modelBuilder.Entity<Permission>(); | ||||
|             permissionEntity | ||||
|                 .HasOne(p => p.Next) | ||||
|                 .WithOne(p => p.Previous) | ||||
|                 .IsRequired(false); | ||||
|             #endregion | ||||
|  | ||||
|             #region LogSettings | ||||
|  | ||||
|             //var logSettingEntity = modelBuilder.Entity<LogSetting>(); | ||||
|  | ||||
|             //logSettingEntity | ||||
|             //    .HasMany(ls => ls.IgnoredChannels) | ||||
|             //    .WithOne(ls => ls.LogSetting) | ||||
|             //    .HasPrincipalKey(ls => ls.id; | ||||
|  | ||||
|             //logSettingEntity | ||||
|             //    .HasMany(ls => ls.IgnoredVoicePresenceChannelIds) | ||||
|             //    .WithOne(ls => ls.LogSetting); | ||||
|             #endregion | ||||
|  | ||||
|             #region MusicPlaylists | ||||
|             var musicPlaylistEntity = modelBuilder.Entity<MusicPlaylist>(); | ||||
|  | ||||
|             musicPlaylistEntity | ||||
|                 .HasMany(p => p.Songs) | ||||
|                 .WithOne() | ||||
|                 .OnDelete(DeleteBehavior.Cascade); | ||||
|  | ||||
|  | ||||
|             #endregion | ||||
|  | ||||
|             #region PokeGame | ||||
|             var pokeGameEntity = modelBuilder.Entity<UserPokeTypes>(); | ||||
|  | ||||
|             pokeGameEntity | ||||
|                 .HasIndex(pt => pt.UserId) | ||||
|                 .IsUnique(); | ||||
|  | ||||
|  | ||||
|             #endregion | ||||
|  | ||||
|             #region CommandPrice | ||||
|             //well, i failed | ||||
|             modelBuilder.Entity<CommandPrice>() | ||||
|                 .HasIndex(cp => cp.Price) | ||||
|                 .IsUnique(); | ||||
|  | ||||
|             //modelBuilder.Entity<CommandCost>() | ||||
|             //    .HasIndex(cp => cp.CommandName) | ||||
|             //    .IsUnique(); | ||||
|             #endregion | ||||
|  | ||||
|             #region Waifus | ||||
|  | ||||
|             var wi = modelBuilder.Entity<WaifuInfo>(); | ||||
|             wi.HasOne(x => x.Waifu) | ||||
|                 .WithOne(); | ||||
|             //    //.HasForeignKey<WaifuInfo>(w => w.WaifuId) | ||||
|             //    //.IsRequired(true); | ||||
|  | ||||
|             //wi.HasOne(x => x.Claimer) | ||||
|             //    .WithOne(); | ||||
|             //    //.HasForeignKey<WaifuInfo>(w => w.ClaimerId) | ||||
|             //    //.IsRequired(false); | ||||
|             #endregion | ||||
|  | ||||
|             #region DiscordUser | ||||
|              | ||||
|             var du = modelBuilder.Entity<DiscordUser>(); | ||||
|             du.HasAlternateKey(w => w.UserId); | ||||
|             du.HasOne(x => x.Club) | ||||
|                .WithMany(x => x.Users) | ||||
|                .IsRequired(false); | ||||
|  | ||||
|             modelBuilder.Entity<DiscordUser>() | ||||
|                 .Property(x => x.LastLevelUp) | ||||
|                 .HasDefaultValue(new DateTime(2017, 9, 21, 20, 53, 13, 305, DateTimeKind.Local)); | ||||
|  | ||||
|             #endregion | ||||
|  | ||||
|             #region Warnings | ||||
|             var warn = modelBuilder.Entity<Warning>(); | ||||
|             #endregion | ||||
|  | ||||
|             #region PatreonRewards | ||||
|             var pr = modelBuilder.Entity<RewardedUser>(); | ||||
|             pr.HasIndex(x => x.UserId) | ||||
|                 .IsUnique(); | ||||
|             #endregion | ||||
|  | ||||
|             #region XpStats | ||||
|             modelBuilder.Entity<UserXpStats>() | ||||
|                 .HasIndex(x => new { x.UserId, x.GuildId }) | ||||
|                 .IsUnique(); | ||||
|  | ||||
|             modelBuilder.Entity<UserXpStats>() | ||||
|                 .Property(x => x.LastLevelUp) | ||||
|                 .HasDefaultValue(new DateTime(2017, 9, 21, 20, 53, 13, 307, DateTimeKind.Local)); | ||||
|              | ||||
|             #endregion | ||||
|  | ||||
|             #region XpSettings | ||||
|             modelBuilder.Entity<XpSettings>() | ||||
|                 .HasOne(x => x.GuildConfig) | ||||
|                 .WithOne(x => x.XpSettings); | ||||
|             #endregion | ||||
|  | ||||
|             //todo major bug | ||||
|             #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 | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,12 @@ | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IBotConfigRepository : IRepository<BotConfig> | ||||
|     { | ||||
|         BotConfig GetOrCreate(Func<DbSet<BotConfig>, IQueryable<BotConfig>> includes = null); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,10 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IClashOfClansRepository : IRepository<ClashWar> | ||||
|     { | ||||
|         IEnumerable<ClashWar> GetAllWars(List<long> guilds); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,17 @@ | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace NadekoBot.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,13 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface ICurrencyRepository : IRepository<Currency> | ||||
|     { | ||||
|         Currency GetOrCreate(ulong userId); | ||||
|         long GetUserCurrency(ulong userId); | ||||
|         bool TryUpdateState(ulong userId, long change); | ||||
|         IEnumerable<Currency> GetTopRichest(int count, int skip); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,8 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface ICurrencyTransactionsRepository : IRepository<CurrencyTransaction> | ||||
|     { | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,9 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface ICustomReactionRepository : IRepository<CustomReaction> | ||||
|     { | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,12 @@ | ||||
| using Discord; | ||||
| using NadekoBot.Services.Database.Models; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IDiscordUserRepository : IRepository<DiscordUser> | ||||
|     { | ||||
|         DiscordUser GetOrCreate(IUser original); | ||||
|         int GetUserGlobalRanking(ulong id); | ||||
|         DiscordUser[] GetUsersXpLeaderboardFor(int page); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,11 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IDonatorsRepository : IRepository<Donator> | ||||
|     { | ||||
|         IEnumerable<Donator> GetDonatorsOrdered(); | ||||
|         Donator AddOrUpdateDonator(ulong userId, string name, int amount); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IGuildConfigRepository : IRepository<GuildConfig> | ||||
|     { | ||||
|         GuildConfig For(ulong guildId, Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes = null); | ||||
|         GuildConfig LogSettingsFor(ulong guildId); | ||||
|         IEnumerable<GuildConfig> OldPermissionsForAll(); | ||||
|         IEnumerable<GuildConfig> GetAllGuildConfigs(List<long> availableGuilds); | ||||
|         IEnumerable<FollowedStream> GetAllFollowedStreams(List<long> included); | ||||
|         void SetCleverbotEnabled(ulong id, bool cleverbotEnabled); | ||||
|         IEnumerable<GuildConfig> Permissionsv2ForAll(List<long> include); | ||||
|         GuildConfig GcWithPermissionsv2For(ulong guildId); | ||||
|         XpSettings XpSettingsFor(ulong guildId); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,11 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IMusicPlaylistRepository : IRepository<MusicPlaylist> | ||||
|     { | ||||
|         List<MusicPlaylist> GetPlaylistsOnPage(int num); | ||||
|         MusicPlaylist GetWithSongs(int id); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,9 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IPokeGameRepository : IRepository<UserPokeTypes> | ||||
|     { | ||||
|         //List<UserPokeTypes> GetAllPokeTypes(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,15 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Collections.Generic; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IQuoteRepository : IRepository<Quote> | ||||
|     { | ||||
|         IEnumerable<Quote> GetAllQuotesByKeyword(ulong guildId, string keyword); | ||||
|         Task<Quote> GetRandomQuoteByKeywordAsync(ulong guildId, string keyword); | ||||
|         Task<Quote> SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text); | ||||
|         IEnumerable<Quote> GetGroup(ulong guildId, int skip, int take); | ||||
|         void RemoveAllByKeyword(ulong guildId, string keyword); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,10 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IReminderRepository : IRepository<Reminder> | ||||
|     { | ||||
|         IEnumerable<Reminder> GetIncludedReminders(IEnumerable<long> guildIds); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										21
									
								
								NadekoBot.Core/Services/Database/Repositories/IRepository.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								NadekoBot.Core/Services/Database/Repositories/IRepository.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| using System.Collections.Generic; | ||||
| using NadekoBot.Services.Database.Models; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IRepository<T> where T : DbEntity | ||||
|     { | ||||
|         T Get(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.Services.Database.Models; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface ISelfAssignedRolesRepository : IRepository<SelfAssignedRole> | ||||
|     { | ||||
|         bool DeleteByGuildAndRoleId(ulong guildId, ulong roleId); | ||||
|         IEnumerable<SelfAssignedRole> GetFromGuild(ulong guildId); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,11 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IUnitConverterRepository : IRepository<ConvertUnit> | ||||
|     { | ||||
|         void AddOrUpdate(Func<ConvertUnit, bool> check, ConvertUnit toAdd, Func<ConvertUnit, ConvertUnit> toUpdate); | ||||
|         bool Empty(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,12 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IWaifuRepository : IRepository<WaifuInfo> | ||||
|     { | ||||
|         IList<WaifuInfo> GetTop(int count, int skip = 0); | ||||
|         WaifuInfo ByWaifuUserId(ulong userId); | ||||
|         IList<WaifuInfo> ByClaimerUserId(ulong userId); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,12 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IWarningsRepository : IRepository<Warning> | ||||
|     { | ||||
|         Warning[] For(ulong guildId, ulong userId); | ||||
|         Task ForgiveAll(ulong guildId, ulong userId, string mod); | ||||
|         Warning[] GetForGuild(ulong id); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,11 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories | ||||
| { | ||||
|     public interface IXpRepository : IRepository<UserXpStats> | ||||
|     { | ||||
|         UserXpStats GetOrCreateUser(ulong guildId, ulong userId); | ||||
|         int GetUserGuildRanking(ulong userId, ulong guildId); | ||||
|         UserXpStats[] GetUsersFor(ulong guildId, int page); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,40 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Linq; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using System; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class BotConfigRepository : Repository<BotConfig>, IBotConfigRepository | ||||
|     { | ||||
|         public BotConfigRepository(DbContext context) : base(context) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         public BotConfig GetOrCreate(Func<DbSet<BotConfig>, IQueryable<BotConfig>> includes = null) | ||||
|         { | ||||
|             BotConfig config; | ||||
|  | ||||
|             if (includes == null) | ||||
|                 config = _set.Include(bc => bc.RotatingStatusMessages) | ||||
|                              .Include(bc => bc.RaceAnimals) | ||||
|                              .Include(bc => bc.Blacklist) | ||||
|                              .Include(bc => bc.EightBallResponses) | ||||
|                              .Include(bc => bc.StartupCommands) | ||||
|                              .Include(bc => bc.BlockedCommands) | ||||
|                              .Include(bc => bc.BlockedModules) | ||||
|                              .Include(bc => bc.Blacklist) | ||||
|                              //.Include(bc => bc.CommandCosts) | ||||
|                              .FirstOrDefault(); | ||||
|             else | ||||
|                 config = includes(_set).FirstOrDefault(); | ||||
|  | ||||
|             if (config == null) | ||||
|             { | ||||
|                 _set.Add(config = new BotConfig()); | ||||
|                 _context.SaveChanges(); | ||||
|             } | ||||
|             return config; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,24 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class ClashOfClansRepository : Repository<ClashWar>, IClashOfClansRepository | ||||
|     { | ||||
|         public ClashOfClansRepository(DbContext context) : base(context) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         public IEnumerable<ClashWar> GetAllWars(List<long> guilds) | ||||
|         { | ||||
|             var toReturn =  _set | ||||
|                 .Where(cw => guilds.Contains((long)cw.GuildId)) | ||||
|                 .Include(cw => cw.Bases) | ||||
|                         .ToList(); | ||||
|             toReturn.ForEach(cw => cw.Bases = cw.Bases.Where(w => w.SequenceNumber != null).OrderBy(w => w.SequenceNumber).ToList()); | ||||
|             return toReturn; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,95 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Linq; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using System; | ||||
|  | ||||
| namespace NadekoBot.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 | ||||
|                     .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 | ||||
|                 .Where(x => x.Name.ToLowerInvariant() == clubName.ToLowerInvariant()) | ||||
|                 .Select(x => x.Discrim) | ||||
|                 .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 | ||||
|                 .OrderByDescending(x => x.Xp) | ||||
|                 .Skip(page * 9) | ||||
|                 .Take(9) | ||||
|                 .ToArray(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,57 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class CurrencyRepository : Repository<Currency>, ICurrencyRepository | ||||
|     { | ||||
|         public CurrencyRepository(DbContext context) : base(context) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         public Currency GetOrCreate(ulong userId) | ||||
|         { | ||||
|             var cur = _set.FirstOrDefault(c => c.UserId == userId); | ||||
|  | ||||
|             if (cur == null) | ||||
|             { | ||||
|                 _set.Add(cur = new Currency() | ||||
|                 { | ||||
|                     UserId = userId, | ||||
|                     Amount = 0 | ||||
|                 }); | ||||
|                 _context.SaveChanges(); | ||||
|             } | ||||
|             return cur; | ||||
|         } | ||||
|  | ||||
|         public IEnumerable<Currency> GetTopRichest(int count, int skip = 0) => | ||||
|             _set.OrderByDescending(c => c.Amount).Skip(skip).Take(count).ToList(); | ||||
|  | ||||
|         public long GetUserCurrency(ulong userId) =>  | ||||
|             GetOrCreate(userId).Amount; | ||||
|  | ||||
|         public bool TryUpdateState(ulong userId, long change) | ||||
|         { | ||||
|             var cur = GetOrCreate(userId); | ||||
|  | ||||
|             if (change == 0) | ||||
|                 return true; | ||||
|  | ||||
|             if (change > 0) | ||||
|             { | ||||
|                 cur.Amount += change; | ||||
|                 return true; | ||||
|             } | ||||
|             //change is negative | ||||
|             if (cur.Amount + change >= 0) | ||||
|             { | ||||
|                 cur.Amount += change; | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,12 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class CurrencyTransactionsRepository : Repository<CurrencyTransaction>, ICurrencyTransactionsRepository | ||||
|     { | ||||
|         public CurrencyTransactionsRepository(DbContext context) : base(context) | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,12 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class CustomReactionsRepository : Repository<CustomReaction>, ICustomReactionRepository | ||||
|     { | ||||
|         public CustomReactionsRepository(DbContext context) : base(context) | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,63 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Linq; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Discord; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class DiscordUserRepository : Repository<DiscordUser>, IDiscordUserRepository | ||||
|     { | ||||
|         public DiscordUserRepository(DbContext context) : base(context) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         public DiscordUser GetOrCreate(IUser original) | ||||
|         { | ||||
|             DiscordUser toReturn; | ||||
|  | ||||
|             toReturn = _set.Include(x => x.Club) | ||||
|                 .FirstOrDefault(u => u.UserId == original.Id); | ||||
|  | ||||
|             if (toReturn != null) | ||||
|             { | ||||
|                 toReturn.AvatarId = original.AvatarId; | ||||
|                 toReturn.Username = original.Username; | ||||
|                 toReturn.Discriminator = original.Discriminator; | ||||
|             } | ||||
|  | ||||
|             if (toReturn == null) | ||||
|                 _set.Add(toReturn = new DiscordUser() | ||||
|                 { | ||||
|                     AvatarId = original.AvatarId, | ||||
|                     Discriminator = original.Discriminator, | ||||
|                     UserId = original.Id, | ||||
|                     Username = original.Username, | ||||
|                     Club = null, | ||||
|                 }); | ||||
|  | ||||
|             return toReturn; | ||||
|         } | ||||
|  | ||||
|         public int GetUserGlobalRanking(ulong id) | ||||
|         { | ||||
|             if (!_set.Where(y => y.UserId == id).Any()) | ||||
|             { | ||||
|                 return _set.Count() + 1; | ||||
|             } | ||||
|             return _set.Count(x => x.TotalXp >=  | ||||
|                 _set.Where(y => y.UserId == id) | ||||
|                     .DefaultIfEmpty() | ||||
|                     .Sum(y => y.TotalXp)); | ||||
|         } | ||||
|  | ||||
|         public DiscordUser[] GetUsersXpLeaderboardFor(int page) | ||||
|         { | ||||
|             return _set | ||||
|                 .OrderByDescending(x => x.TotalXp) | ||||
|                 .Skip(page * 9) | ||||
|                 .Take(9) | ||||
|                 .AsEnumerable() | ||||
|                 .ToArray(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,40 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using NadekoBot.Services.Database.Models; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class DonatorsRepository : Repository<Donator>, IDonatorsRepository | ||||
|     { | ||||
|         public DonatorsRepository(DbContext context) : base(context) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         public Donator AddOrUpdateDonator(ulong userId, string name, int amount) | ||||
|         { | ||||
|             var donator = _set.Where(d => d.UserId == userId).FirstOrDefault(); | ||||
|  | ||||
|             if (donator == null) | ||||
|             { | ||||
|                 _set.Add(donator = new Donator | ||||
|                 { | ||||
|                     Amount = amount, | ||||
|                     UserId = userId, | ||||
|                     Name = name | ||||
|                 }); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 donator.Amount += amount; | ||||
|                 donator.Name = name; | ||||
|                 _set.Update(donator); | ||||
|             } | ||||
|  | ||||
|             return donator; | ||||
|         } | ||||
|  | ||||
|         public IEnumerable<Donator> GetDonatorsOrdered() =>  | ||||
|             _set.OrderByDescending(d => d.Amount).ToList(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,211 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using System; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     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<long> availableGuilds) => | ||||
|             _set | ||||
|                 .Where(gc => availableGuilds.Contains((long)gc.GuildId)) | ||||
|                 .Include(gc => gc.LogSetting) | ||||
|                     .ThenInclude(ls => ls.IgnoredChannels) | ||||
|                 .Include(gc => gc.MutedUsers) | ||||
|                 .Include(gc => gc.CommandAliases) | ||||
|                 .Include(gc => gc.UnmuteTimers) | ||||
|                 .Include(gc => gc.VcRoleInfos) | ||||
|                 .Include(gc => gc.GenerateCurrencyChannelIds) | ||||
|                 .Include(gc => gc.FilterInvitesChannelIds) | ||||
|                 .Include(gc => gc.FilterWordsChannelIds) | ||||
|                 .Include(gc => gc.FilteredWords) | ||||
|                 .Include(gc => gc.CommandCooldowns) | ||||
|                 .Include(gc => gc.GuildRepeaters) | ||||
|                 .Include(gc => gc.AntiRaidSetting) | ||||
|                 .Include(gc => gc.SlowmodeIgnoredRoles) | ||||
|                 .Include(gc => gc.SlowmodeIgnoredUsers) | ||||
|                 .Include(gc => gc.AntiSpamSetting) | ||||
|                     .ThenInclude(x => x.IgnoredChannels) | ||||
|                 .Include(gc => gc.FeedSubs) | ||||
|                     .ThenInclude(x => x.GuildConfig) | ||||
|                 .Include(gc => gc.FollowedStreams) | ||||
|                 .Include(gc => gc.StreamRole) | ||||
|                 .Include(gc => gc.NsfwBlacklistedTags) | ||||
|                 .Include(gc => gc.XpSettings) | ||||
|                     .ThenInclude(x => x.ExclusionList) | ||||
|                 .ToList(); | ||||
|  | ||||
|         /// <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 For(ulong guildId, Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes = null) | ||||
|         { | ||||
|             GuildConfig config; | ||||
|  | ||||
|             if (includes == null) | ||||
|             { | ||||
|                 config = _set | ||||
|                     .Include(gc => gc.FollowedStreams) | ||||
|                     .Include(gc => gc.LogSetting) | ||||
|                         .ThenInclude(ls => ls.IgnoredChannels) | ||||
|                     .Include(gc => gc.FilterInvitesChannelIds) | ||||
|                     .Include(gc => gc.FilterWordsChannelIds) | ||||
|                     .Include(gc => gc.FilteredWords) | ||||
|                     .Include(gc => gc.GenerateCurrencyChannelIds) | ||||
|                     .Include(gc => gc.CommandCooldowns) | ||||
|                     .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.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> OldPermissionsForAll() | ||||
|         { | ||||
|             var query = _set | ||||
|                 .Where(gc => gc.RootPermission != null) | ||||
|                 .Include(gc => gc.RootPermission); | ||||
|  | ||||
|             for (int i = 0; i < 60; i++) | ||||
|             { | ||||
|                 query = query.ThenInclude(gc => gc.Next); | ||||
|             } | ||||
|  | ||||
|             return query.ToList(); | ||||
|         } | ||||
|  | ||||
|         public IEnumerable<GuildConfig> Permissionsv2ForAll(List<long> include) | ||||
|         { | ||||
|             var query = _set | ||||
|                 .Where(x => include.Contains((long)x.GuildId)) | ||||
|                 .Include(gc => gc.Permissions); | ||||
|  | ||||
|             return query.ToList(); | ||||
|         } | ||||
|  | ||||
|         public GuildConfig GcWithPermissionsv2For(ulong guildId) | ||||
|         { | ||||
|             var config = _set | ||||
|                 .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> GetAllFollowedStreams(List<long> included) => | ||||
|             _set | ||||
|                 .Where(gc => included.Contains((long)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 = For(guildId, | ||||
|                 set => set.Include(x => x.XpSettings) | ||||
|                           .ThenInclude(x => x.RoleRewards) | ||||
|                           .Include(x => x.XpSettings) | ||||
|                           .ThenInclude(x => x.ExclusionList)); | ||||
|  | ||||
|             if (gc.XpSettings == null) | ||||
|                 gc.XpSettings = new XpSettings(); | ||||
|  | ||||
|             return gc.XpSettings; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,30 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|  | ||||
| namespace NadekoBot.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.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,20 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class PokeGameRepository : Repository<UserPokeTypes>, IPokeGameRepository | ||||
|     { | ||||
|         public PokeGameRepository(DbContext context) : base(context) | ||||
|         { | ||||
|  | ||||
|         } | ||||
|  | ||||
|         //List<UserPokeTypes> GetAllPokeTypes() | ||||
|         //{ | ||||
|         //    var toReturn = _set.Include(pt => pt.UserId).ToList(); | ||||
|         //    toReturn.ForEach(pt => pt.).ToList(); | ||||
|         //    return toReturn; | ||||
|         //} | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,39 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using NadekoBot.Extensions; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using NadekoBot.Common; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class QuoteRepository : Repository<Quote>, IQuoteRepository | ||||
|     { | ||||
|         public QuoteRepository(DbContext context) : base(context) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         public IEnumerable<Quote> GetAllQuotesByKeyword(ulong guildId, string keyword) =>  | ||||
|             _set.Where(q => q.GuildId == guildId && q.Keyword == keyword); | ||||
|  | ||||
|         public IEnumerable<Quote> GetGroup(ulong guildId, int skip, int take) =>  | ||||
|             _set.Where(q=>q.GuildId == guildId).OrderBy(q => q.Keyword).Skip(skip).Take(take).ToList(); | ||||
|  | ||||
|         public Task<Quote> GetRandomQuoteByKeywordAsync(ulong guildId, string keyword) | ||||
|         { | ||||
|             var rng = new NadekoRandom(); | ||||
|             return _set.Where(q => q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rng.Next()).FirstOrDefaultAsync(); | ||||
|         } | ||||
|         public Task<Quote> SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text) | ||||
|         {      			 | ||||
|             var rngk = new NadekoRandom(); | ||||
|             return _set.Where(q => q.Text.ContainsNoCase(text, StringComparison.OrdinalIgnoreCase) && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); | ||||
|     } | ||||
|  | ||||
|         public void RemoveAllByKeyword(ulong guildId, string keyword) => | ||||
|             _set.RemoveRange(_set.Where(x => x.GuildId == guildId && x.Keyword.ToUpper() == keyword)); | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,19 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class ReminderRepository : Repository<Reminder>, IReminderRepository | ||||
|     { | ||||
|         public ReminderRepository(DbContext context) : base(context) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         public IEnumerable<Reminder> GetIncludedReminders(IEnumerable<long> guildIds) | ||||
|         { | ||||
|             return _set.Where(x => guildIds.Contains((long)x.ServerId)).ToList(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,46 @@ | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class Repository<T> : IRepository<T> where T : DbEntity | ||||
|     { | ||||
|         protected DbContext _context; | ||||
|         protected DbSet<T> _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 Get(int id) => | ||||
|             _set.FirstOrDefault(e => e.Id == id); | ||||
|  | ||||
|         public IEnumerable<T> GetAll() => | ||||
|             _set.ToList(); | ||||
|  | ||||
|         public void Remove(int id) => | ||||
|             _set.Remove(this.Get(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,28 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|  | ||||
| namespace NadekoBot.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.Where(s => s.GuildId == guildId).ToList(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,26 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System; | ||||
| using System.Linq; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class UnitConverterRepository : Repository<ConvertUnit>, IUnitConverterRepository | ||||
|     { | ||||
|         public UnitConverterRepository(DbContext context) : base(context) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         public void AddOrUpdate(Func<ConvertUnit, bool> check, ConvertUnit toAdd, Func<ConvertUnit, ConvertUnit> toUpdate) | ||||
|         { | ||||
|            var existing = _set.FirstOrDefault(check); | ||||
|             if (existing != null) | ||||
|             { | ||||
|                 existing = toUpdate.Invoke(existing); | ||||
|             } | ||||
|             else _set.Add(toAdd); | ||||
|         } | ||||
|  | ||||
|         public bool Empty() => !_set.Any(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,50 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class WaifuRepository : Repository<WaifuInfo>, IWaifuRepository | ||||
|     { | ||||
|         public WaifuRepository(DbContext context) : base(context) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         public WaifuInfo ByWaifuUserId(ulong userId) | ||||
|         { | ||||
|             return _set.Include(wi => wi.Waifu) | ||||
|                         .Include(wi => wi.Affinity) | ||||
|                         .Include(wi => wi.Claimer) | ||||
|                         .Include(wi => wi.Items) | ||||
|                         .FirstOrDefault(wi => wi.Waifu.UserId == userId); | ||||
|         } | ||||
|  | ||||
|         public IList<WaifuInfo> ByClaimerUserId(ulong userId) | ||||
|         { | ||||
|             return _set.Include(wi => wi.Waifu) | ||||
|                         .Include(wi => wi.Affinity) | ||||
|                         .Include(wi => wi.Claimer) | ||||
|                         .Include(wi => wi.Items) | ||||
|                         .Where(wi => wi.Claimer != null && wi.Claimer.UserId == userId) | ||||
|                         .ToList(); | ||||
|         } | ||||
|  | ||||
|         public IList<WaifuInfo> GetTop(int count, int skip = 0) | ||||
|         { | ||||
|             if (count < 0) | ||||
|                 throw new ArgumentOutOfRangeException(nameof(count)); | ||||
|             if (count == 0) | ||||
|                 return new List<WaifuInfo>(); | ||||
|  | ||||
|             return _set.Include(wi => wi.Waifu) | ||||
|                         .Include(wi => wi.Affinity) | ||||
|                         .Include(wi => wi.Claimer) | ||||
|                     .OrderByDescending(wi => wi.Price) | ||||
|                     .Skip(skip) | ||||
|                     .Take(count) | ||||
|                     .ToList(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,41 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace NadekoBot.Services.Database.Repositories.Impl | ||||
| { | ||||
|     public class WarningsRepository : Repository<Warning>, IWarningsRepository | ||||
|     { | ||||
|         public WarningsRepository(DbContext context) : base(context) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         public Warning[] For(ulong guildId, ulong userId) | ||||
|         { | ||||
|             var query = _set.Where(x => x.GuildId == guildId && x.UserId == userId) | ||||
|                 .OrderByDescending(x => x.DateAdded); | ||||
|  | ||||
|             return query.ToArray(); | ||||
|         } | ||||
|  | ||||
|         public async Task ForgiveAll(ulong guildId, ulong userId, string mod) | ||||
|         { | ||||
|             await _set.Where(x => x.GuildId == guildId && x.UserId == userId) | ||||
|                 .ForEachAsync(x => | ||||
|                 { | ||||
|                     if (x.Forgiven != true) | ||||
|                     { | ||||
|                         x.Forgiven = true; | ||||
|                         x.ForgivenBy = mod; | ||||
|                     } | ||||
|                 }) | ||||
|                 .ConfigureAwait(false); | ||||
|         } | ||||
|  | ||||
|         public Warning[] GetForGuild(ulong id) | ||||
|         { | ||||
|             return _set.Where(x => x.GuildId == id).ToArray(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,60 @@ | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using System.Linq; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
|  | ||||
| namespace NadekoBot.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 = XpNotificationType.None, | ||||
|                     GuildId = guildId, | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             return usr; | ||||
|         } | ||||
|  | ||||
|         public UserXpStats[] GetUsersFor(ulong guildId, int page) | ||||
|         { | ||||
|             return _set.Where(x => x.GuildId == guildId) | ||||
|                 .OrderByDescending(x => x.Xp + x.AwardedXp) | ||||
|                 .Skip(page * 9) | ||||
|                 .Take(9) | ||||
|                 .ToArray(); | ||||
|         } | ||||
|  | ||||
|         public int GetUserGuildRanking(ulong userId, ulong guildId) | ||||
|         { | ||||
|             if (!_set.Where(x => x.GuildId == guildId && x.UserId == userId).Any()) | ||||
|             { | ||||
|                 var cnt = _set.Count(x => x.GuildId == guildId); | ||||
|                 if (cnt == 0) | ||||
|                     return 1; | ||||
|                 else | ||||
|                     return cnt; | ||||
|             } | ||||
|  | ||||
|             return _set | ||||
|                 .Where(x => x.GuildId == guildId) | ||||
|                 .Count(x => x.Xp > (_set | ||||
|                     .Where(y => y.UserId == userId && y.GuildId == guildId) | ||||
|                     .Select(y => y.Xp) | ||||
|                     .DefaultIfEmpty() | ||||
|                     .Sum())) + 1; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										93
									
								
								NadekoBot.Core/Services/Database/UnitOfWork.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								NadekoBot.Core/Services/Database/UnitOfWork.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| using NadekoBot.Services.Database.Repositories; | ||||
| using NadekoBot.Services.Database.Repositories.Impl; | ||||
| using System; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace NadekoBot.Services.Database | ||||
| { | ||||
|     public 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 IDonatorsRepository _donators; | ||||
|         public IDonatorsRepository Donators => _donators ?? (_donators = new DonatorsRepository(_context)); | ||||
|  | ||||
|         private IClashOfClansRepository _clashOfClans; | ||||
|         public IClashOfClansRepository ClashOfClans => _clashOfClans ?? (_clashOfClans = new ClashOfClansRepository(_context)); | ||||
|  | ||||
|         private IReminderRepository _reminders; | ||||
|         public IReminderRepository Reminders => _reminders ?? (_reminders = new ReminderRepository(_context)); | ||||
|  | ||||
|         private ISelfAssignedRolesRepository _selfAssignedRoles; | ||||
|         public ISelfAssignedRolesRepository SelfAssignedRoles => _selfAssignedRoles ?? (_selfAssignedRoles = new SelfAssignedRolesRepository(_context)); | ||||
|  | ||||
|         private IBotConfigRepository _botConfig; | ||||
|         public IBotConfigRepository BotConfig => _botConfig ?? (_botConfig = new BotConfigRepository(_context)); | ||||
|  | ||||
|         private ICurrencyRepository _currency; | ||||
|         public ICurrencyRepository Currency => _currency ?? (_currency = new CurrencyRepository(_context)); | ||||
|  | ||||
|         private ICurrencyTransactionsRepository _currencyTransactions; | ||||
|         public ICurrencyTransactionsRepository CurrencyTransactions => _currencyTransactions ?? (_currencyTransactions = new CurrencyTransactionsRepository(_context)); | ||||
|  | ||||
|         private IUnitConverterRepository _conUnits; | ||||
|         public IUnitConverterRepository ConverterUnits => _conUnits ?? (_conUnits = new UnitConverterRepository(_context)); | ||||
|  | ||||
|         private IMusicPlaylistRepository _musicPlaylists; | ||||
|         public IMusicPlaylistRepository MusicPlaylists => _musicPlaylists ?? (_musicPlaylists = new MusicPlaylistRepository(_context)); | ||||
|  | ||||
|         private ICustomReactionRepository _customReactions; | ||||
|         public ICustomReactionRepository CustomReactions => _customReactions ?? (_customReactions = new CustomReactionsRepository(_context)); | ||||
|  | ||||
|         private IPokeGameRepository _pokegame; | ||||
|         public IPokeGameRepository PokeGame => _pokegame ?? (_pokegame = new PokeGameRepository(_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)); | ||||
|  | ||||
|         public UnitOfWork(NadekoContext context) | ||||
|         { | ||||
|             _context = context; | ||||
|         } | ||||
|  | ||||
|         public int Complete() => | ||||
|             _context.SaveChanges(); | ||||
|  | ||||
|         public Task<int> CompleteAsync() =>  | ||||
|             _context.SaveChangesAsync(); | ||||
|  | ||||
|         private bool disposed = false; | ||||
|  | ||||
|         protected void Dispose(bool disposing) | ||||
|         { | ||||
|             if (!this.disposed) | ||||
|                 if (disposing) | ||||
|                     _context.Dispose(); | ||||
|             this.disposed = true; | ||||
|         } | ||||
|  | ||||
|         public void Dispose() | ||||
|         { | ||||
|             Dispose(true); | ||||
|             GC.SuppressFinalize(this); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										59
									
								
								NadekoBot.Core/Services/DbService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								NadekoBot.Core/Services/DbService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| using Microsoft.Data.Sqlite; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using NadekoBot.Services.Database; | ||||
| using System; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace NadekoBot.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(), x => x.SuppressForeignKeyEnforcement()); | ||||
|             migrateOptions = optionsBuilder.Options; | ||||
|         } | ||||
|  | ||||
|         public NadekoContext GetDbContext() | ||||
|         { | ||||
|             var context = new NadekoContext(options); | ||||
|             if (context.Database.GetPendingMigrations().Any()) | ||||
|             { | ||||
|                 var mContext = new NadekoContext(migrateOptions); | ||||
|                 mContext.Database.Migrate(); | ||||
|                 mContext.SaveChanges(); | ||||
|                 mContext.Dispose(); | ||||
|             } | ||||
|             context.Database.SetCommandTimeout(60); | ||||
|             context.EnsureSeedData(); | ||||
|  | ||||
|             //set important sqlite stuffs | ||||
|             var conn = context.Database.GetDbConnection(); | ||||
|             conn.Open(); | ||||
|  | ||||
|             context.Database.ExecuteSqlCommand("PRAGMA journal_mode=WAL"); | ||||
|             using (var com = conn.CreateCommand()) | ||||
|             { | ||||
|                 com.CommandText = "PRAGMA journal_mode=WAL; PRAGMA synchronous=OFF"; | ||||
|                 com.ExecuteNonQuery(); | ||||
|             } | ||||
|  | ||||
|             return context; | ||||
|         } | ||||
|  | ||||
|         public IUnitOfWork UnitOfWork => | ||||
|             new UnitOfWork(GetDbContext()); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										419
									
								
								NadekoBot.Core/Services/GreetSettingsService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										419
									
								
								NadekoBot.Core/Services/GreetSettingsService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,419 @@ | ||||
| using Discord; | ||||
| using Discord.WebSocket; | ||||
| using NadekoBot.Extensions; | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using NLog; | ||||
| using System; | ||||
| using System.Collections.Concurrent; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| using NadekoBot.Common; | ||||
| using NadekoBot.Common.Replacements; | ||||
|  | ||||
| namespace NadekoBot.Services | ||||
| { | ||||
|     public class GreetSettingsService : INService | ||||
|     { | ||||
|         private readonly DbService _db; | ||||
|  | ||||
|         public readonly ConcurrentDictionary<ulong, GreetSettings> GuildConfigsCache; | ||||
|         private readonly DiscordSocketClient _client; | ||||
|         private readonly Logger _log; | ||||
|  | ||||
|         public GreetSettingsService(DiscordSocketClient client, IEnumerable<GuildConfig> guildConfigs, DbService db) | ||||
|         { | ||||
|             _db = db; | ||||
|             _client = client; | ||||
|             _log = LogManager.GetCurrentClassLogger(); | ||||
|  | ||||
|             GuildConfigsCache = new ConcurrentDictionary<ulong, GreetSettings>(guildConfigs.ToDictionary(g => g.GuildId, GreetSettings.Create)); | ||||
|  | ||||
|             _client.UserJoined += UserJoined; | ||||
|             _client.UserLeft += UserLeft; | ||||
|         } | ||||
|  | ||||
|         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()).SingleOrDefault(c => c.Id == conf.ByeMessageChannelId); | ||||
|  | ||||
|                     if (channel == null) //maybe warn the server owner that the channel is missing | ||||
|                         return; | ||||
|  | ||||
|                     var rep = new ReplacementBuilder() | ||||
|                         .WithDefault(user, channel, user.Guild, _client) | ||||
|                         .Build(); | ||||
|  | ||||
|                     if (CREmbed.TryParse(conf.ChannelByeMessageText, out var embedData)) | ||||
|                     { | ||||
|                         rep.Replace(embedData); | ||||
|                         try | ||||
|                         { | ||||
|                             var toDelete = await channel.EmbedAsync(embedData.ToEmbed(), embedData.PlainText?.SanitizeMentions() ?? "").ConfigureAwait(false); | ||||
|                             if (conf.AutoDeleteByeMessagesTimer > 0) | ||||
|                             { | ||||
|                                 toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer); | ||||
|                             } | ||||
|                         } | ||||
|                         catch (Exception ex) { _log.Warn(ex); } | ||||
|                     } | ||||
|                     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.Warn(ex); } | ||||
|                     } | ||||
|                 } | ||||
|                 catch | ||||
|                 { | ||||
|                     // ignored | ||||
|                 } | ||||
|             }); | ||||
|             return Task.CompletedTask; | ||||
|         } | ||||
|  | ||||
|         private Task UserJoined(IGuildUser user) | ||||
|         { | ||||
|             var _ = Task.Run(async () => | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     var conf = GetOrAddSettingsForGuild(user.GuildId); | ||||
|  | ||||
|                     if (conf.SendChannelGreetMessage) | ||||
|                     { | ||||
|                         var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.GreetMessageChannelId); | ||||
|                         if (channel != null) //maybe warn the server owner that the channel is missing | ||||
|                         { | ||||
|                             var rep = new ReplacementBuilder() | ||||
|                                 .WithDefault(user, channel, user.Guild, _client) | ||||
|                                 .Build(); | ||||
|  | ||||
|                             if (CREmbed.TryParse(conf.ChannelGreetMessageText, out var embedData)) | ||||
|                             { | ||||
|                                 rep.Replace(embedData); | ||||
|                                 try | ||||
|                                 { | ||||
|                                     var toDelete = await channel.EmbedAsync(embedData.ToEmbed(), embedData.PlainText?.SanitizeMentions() ?? "").ConfigureAwait(false); | ||||
|                                     if (conf.AutoDeleteGreetMessagesTimer > 0) | ||||
|                                     { | ||||
|                                         toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer); | ||||
|                                     } | ||||
|                                 } | ||||
|                                 catch (Exception ex) { _log.Warn(ex); } | ||||
|                             } | ||||
|                             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.Warn(ex); } | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     if (conf.SendDmGreetMessage) | ||||
|                     { | ||||
|                         var channel = await user.GetOrCreateDMChannelAsync(); | ||||
|  | ||||
|                         if (channel != null) | ||||
|                         { | ||||
|                             var rep = new ReplacementBuilder() | ||||
|                                 .WithDefault(user, channel, user.Guild, _client) | ||||
|                                 .Build(); | ||||
|                             if (CREmbed.TryParse(conf.DmGreetMessageText, out var embedData)) | ||||
|                             { | ||||
|  | ||||
|                                 rep.Replace(embedData); | ||||
|                                 try | ||||
|                                 { | ||||
|                                     await channel.EmbedAsync(embedData.ToEmbed(), embedData.PlainText?.SanitizeMentions() ?? "").ConfigureAwait(false); | ||||
|                                 } | ||||
|                                 catch (Exception ex) | ||||
|                                 { | ||||
|                                     _log.Warn(ex); | ||||
|                                 } | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 var msg = rep.Replace(conf.DmGreetMessageText); | ||||
|                                 if (!string.IsNullOrWhiteSpace(msg)) | ||||
|                                 { | ||||
|                                     await channel.SendConfirmAsync(msg).ConfigureAwait(false); | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 catch | ||||
|                 { | ||||
|                     // ignored | ||||
|                 } | ||||
|             }); | ||||
|             return Task.CompletedTask; | ||||
|         } | ||||
|  | ||||
|         public GreetSettings GetOrAddSettingsForGuild(ulong guildId) | ||||
|         { | ||||
|             GreetSettings settings; | ||||
|             GuildConfigsCache.TryGetValue(guildId, out settings); | ||||
|  | ||||
|             if (settings != null) | ||||
|                 return settings; | ||||
|  | ||||
|             using (var uow = _db.UnitOfWork) | ||||
|             { | ||||
|                 var gc = uow.GuildConfigs.For(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.UnitOfWork) | ||||
|             { | ||||
|                 var conf = uow.GuildConfigs.For(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.CompleteAsync().ConfigureAwait(false); | ||||
|  | ||||
|                 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.UnitOfWork) | ||||
|             { | ||||
|                 var conf = uow.GuildConfigs.For(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.CompleteAsync().ConfigureAwait(false); | ||||
|             } | ||||
|             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.UnitOfWork) | ||||
|             { | ||||
|                 var conf = uow.GuildConfigs.For(guildId, set => set); | ||||
|                 conf.ChannelGreetMessageText = message; | ||||
|                 greetMsgEnabled = conf.SendChannelGreetMessage; | ||||
|  | ||||
|                 var toAdd = GreetSettings.Create(conf); | ||||
|                 GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); | ||||
|  | ||||
|                 uow.Complete(); | ||||
|             } | ||||
|             return greetMsgEnabled; | ||||
|         } | ||||
|  | ||||
|         public async Task<bool> SetGreetDm(ulong guildId, bool? value = null) | ||||
|         { | ||||
|             bool enabled; | ||||
|             using (var uow = _db.UnitOfWork) | ||||
|             { | ||||
|                 var conf = uow.GuildConfigs.For(guildId, set => set); | ||||
|                 enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage; | ||||
|  | ||||
|                 var toAdd = GreetSettings.Create(conf); | ||||
|                 GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); | ||||
|  | ||||
|                 await uow.CompleteAsync().ConfigureAwait(false); | ||||
|             } | ||||
|             return enabled; | ||||
|         } | ||||
|  | ||||
|         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.UnitOfWork) | ||||
|             { | ||||
|                 var conf = uow.GuildConfigs.For(guildId); | ||||
|                 conf.DmGreetMessageText = message; | ||||
|                 greetMsgEnabled = conf.SendDmGreetMessage; | ||||
|  | ||||
|                 var toAdd = GreetSettings.Create(conf); | ||||
|                 GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); | ||||
|  | ||||
|                 uow.Complete(); | ||||
|             } | ||||
|             return greetMsgEnabled; | ||||
|         } | ||||
|  | ||||
|         public async Task<bool> SetBye(ulong guildId, ulong channelId, bool? value = null) | ||||
|         { | ||||
|             bool enabled; | ||||
|             using (var uow = _db.UnitOfWork) | ||||
|             { | ||||
|                 var conf = uow.GuildConfigs.For(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.CompleteAsync(); | ||||
|             } | ||||
|             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.UnitOfWork) | ||||
|             { | ||||
|                 var conf = uow.GuildConfigs.For(guildId, set => set); | ||||
|                 conf.ChannelByeMessageText = message; | ||||
|                 byeMsgEnabled = conf.SendChannelByeMessage; | ||||
|  | ||||
|                 var toAdd = GreetSettings.Create(conf); | ||||
|                 GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); | ||||
|  | ||||
|                 uow.Complete(); | ||||
|             } | ||||
|             return byeMsgEnabled; | ||||
|         } | ||||
|  | ||||
|         public async Task SetByeDel(ulong guildId, int timer) | ||||
|         { | ||||
|             if (timer < 0 || timer > 600) | ||||
|                 return; | ||||
|  | ||||
|             using (var uow = _db.UnitOfWork) | ||||
|             { | ||||
|                 var conf = uow.GuildConfigs.For(guildId, set => set); | ||||
|                 conf.AutoDeleteByeMessagesTimer = timer; | ||||
|  | ||||
|                 var toAdd = GreetSettings.Create(conf); | ||||
|                 GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); | ||||
|  | ||||
|                 await uow.CompleteAsync().ConfigureAwait(false); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public async Task SetGreetDel(ulong id, int timer) | ||||
|         { | ||||
|             if (timer < 0 || timer > 600) | ||||
|                 return; | ||||
|  | ||||
|             using (var uow = _db.UnitOfWork) | ||||
|             { | ||||
|                 var conf = uow.GuildConfigs.For(id, set => set); | ||||
|                 conf.AutoDeleteGreetMessagesTimer = timer; | ||||
|  | ||||
|                 var toAdd = GreetSettings.Create(conf); | ||||
|                 GuildConfigsCache.AddOrUpdate(id, toAdd, (key, old) => toAdd); | ||||
|  | ||||
|                 await uow.CompleteAsync().ConfigureAwait(false); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     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, | ||||
|         }; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										12
									
								
								NadekoBot.Core/Services/IBotConfigProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								NadekoBot.Core/Services/IBotConfigProvider.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| using NadekoBot.Common; | ||||
| using NadekoBot.Services.Database.Models; | ||||
|  | ||||
| namespace NadekoBot.Services | ||||
| { | ||||
|     public interface IBotConfigProvider | ||||
|     { | ||||
|         BotConfig BotConfig { get; } | ||||
|         void Reload(); | ||||
|         bool Edit(BotConfigEditType type, string newValue); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										52
									
								
								NadekoBot.Core/Services/IBotCredentials.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								NadekoBot.Core/Services/IBotCredentials.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| using Discord; | ||||
| using System.Collections.Immutable; | ||||
|  | ||||
| namespace NadekoBot.Services | ||||
| { | ||||
|     public interface IBotCredentials | ||||
|     { | ||||
|         ulong ClientId { get; } | ||||
|  | ||||
|         string Token { get; } | ||||
|         string GoogleApiKey { get; } | ||||
|         ImmutableArray<ulong> OwnerIds { get; } | ||||
|         string MashapeKey { get; } | ||||
|         string LoLApiKey { 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; } | ||||
|     } | ||||
|  | ||||
|     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; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										18
									
								
								NadekoBot.Core/Services/IDataCache.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								NadekoBot.Core/Services/IDataCache.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| using StackExchange.Redis; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace NadekoBot.Services | ||||
| { | ||||
|     public interface IDataCache | ||||
|     { | ||||
|         ConnectionMultiplexer Redis { get; } | ||||
|         Task<(bool Success, byte[] Data)> TryGetImageDataAsync(string key); | ||||
|         Task<(bool Success, string Data)> TryGetAnimeDataAsync(string key); | ||||
|         Task SetImageDataAsync(string key, byte[] data); | ||||
|         Task SetAnimeDataAsync(string link, string data); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										35
									
								
								NadekoBot.Core/Services/IGoogleApiService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								NadekoBot.Core/Services/IGoogleApiService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| using Google.Apis.Customsearch.v1.Data; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace NadekoBot.Services | ||||
| { | ||||
|     public interface IGoogleApiService : INService | ||||
|     { | ||||
|         IEnumerable<string> Languages { get; } | ||||
|  | ||||
|         Task<IEnumerable<string>> GetVideoLinksByKeywordAsync(string keywords, int count = 1); | ||||
|         Task<IEnumerable<(string Name, string Id, string Url)>> GetVideoInfosByKeywordAsync(string keywords, int count = 1); | ||||
|         Task<IEnumerable<string>> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1); | ||||
|         Task<IEnumerable<string>> GetRelatedVideosAsync(string url, int count = 1); | ||||
|         Task<IEnumerable<string>> GetPlaylistTracksAsync(string playlistId, int count = 50); | ||||
|         Task<IReadOnlyDictionary<string, TimeSpan>> GetVideoDurationsAsync(IEnumerable<string> videoIds); | ||||
|         Task<ImageResult> GetImageAsync(string query, int start = 1); | ||||
|         Task<string> Translate(string sourceText, string sourceLanguage, string targetLanguage); | ||||
|  | ||||
|         Task<string> ShortenUrl(string url); | ||||
|     } | ||||
|  | ||||
|     public struct ImageResult | ||||
|     { | ||||
|         public Result.ImageData Image { get; } | ||||
|         public string Link { get; } | ||||
|  | ||||
|         public ImageResult(Result.ImageData image, string link) | ||||
|         { | ||||
|             this.Image = image; | ||||
|             this.Link = link; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										24
									
								
								NadekoBot.Core/Services/IImagesService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								NadekoBot.Core/Services/IImagesService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| using System.Collections.Immutable; | ||||
|  | ||||
| namespace NadekoBot.Services | ||||
| { | ||||
|     public interface IImagesService : INService | ||||
|     { | ||||
|         ImmutableArray<byte> Heads { get; } | ||||
|         ImmutableArray<byte> Tails { get; } | ||||
|  | ||||
|         ImmutableArray<(string, ImmutableArray<byte>)> Currency { get; } | ||||
|         ImmutableArray<ImmutableArray<byte>> Dice { get; } | ||||
|  | ||||
|         ImmutableArray<byte> SlotBackground { get; } | ||||
|         ImmutableArray<ImmutableArray<byte>> SlotEmojis { get; } | ||||
|         ImmutableArray<ImmutableArray<byte>> SlotNumbers { get; } | ||||
|  | ||||
|         ImmutableArray<byte> WifeMatrix { get; } | ||||
|         ImmutableArray<byte> RategirlDot { get; } | ||||
|  | ||||
|         ImmutableArray<byte> XpCard { get; } | ||||
|  | ||||
|         void Reload(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										21
									
								
								NadekoBot.Core/Services/ILocalization.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								NadekoBot.Core/Services/ILocalization.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| using System.Collections.Concurrent; | ||||
| using System.Globalization; | ||||
| using Discord; | ||||
|  | ||||
| namespace NadekoBot.Services | ||||
| { | ||||
|     public interface ILocalization : INService | ||||
|     { | ||||
|         CultureInfo DefaultCultureInfo { get; } | ||||
|         ConcurrentDictionary<ulong, CultureInfo> GuildCultureInfos { get; } | ||||
|  | ||||
|         CultureInfo GetCultureInfo(IGuild guild); | ||||
|         CultureInfo GetCultureInfo(ulong? guildId); | ||||
|         void RemoveGuildCulture(IGuild guild); | ||||
|         void RemoveGuildCulture(ulong guildId); | ||||
|         void ResetDefaultCulture(); | ||||
|         void SetDefaultCulture(CultureInfo ci); | ||||
|         void SetGuildCulture(IGuild guild, CultureInfo ci); | ||||
|         void SetGuildCulture(ulong guildId, CultureInfo ci); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										10
									
								
								NadekoBot.Core/Services/INService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								NadekoBot.Core/Services/INService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| namespace NadekoBot.Services | ||||
| { | ||||
|     /// <summary> | ||||
|     /// All services must implement this interface in order to be auto-discovered by the DI system | ||||
|     /// </summary> | ||||
|     public interface INService | ||||
|     { | ||||
|          | ||||
|     } | ||||
| } | ||||
							
								
								
									
										23
									
								
								NadekoBot.Core/Services/IStatsService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								NadekoBot.Core/Services/IStatsService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| using System; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace NadekoBot.Services | ||||
| { | ||||
|     public interface IStatsService : INService | ||||
|     { | ||||
|         string Author { get; } | ||||
|         long CommandsRan { get; } | ||||
|         string Heap { get; } | ||||
|         string Library { get; } | ||||
|         long MessageCounter { get; } | ||||
|         double MessagesPerSecond { get; } | ||||
|         long TextChannels { get; } | ||||
|         long VoiceChannels { get; } | ||||
|         int GuildCount { get; } | ||||
|  | ||||
|         TimeSpan GetUptime(); | ||||
|         string GetUptimeString(string separator = ", "); | ||||
|         void Initialize(); | ||||
|         Task<string> Print(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										147
									
								
								NadekoBot.Core/Services/Impl/BotConfigProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								NadekoBot.Core/Services/Impl/BotConfigProvider.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| using System; | ||||
| using NadekoBot.Common; | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using NadekoBot.Services; | ||||
|  | ||||
| namespace NadekoBot.Services.Impl | ||||
| { | ||||
|     public class BotConfigProvider : IBotConfigProvider | ||||
|     { | ||||
|         private readonly DbService _db; | ||||
|         public BotConfig BotConfig { get; private set; } | ||||
|  | ||||
|         public BotConfigProvider(DbService db, BotConfig bc) | ||||
|         { | ||||
|             _db = db; | ||||
|             BotConfig = bc; | ||||
|         } | ||||
|  | ||||
|         public void Reload() | ||||
|         { | ||||
|             using (var uow = _db.UnitOfWork) | ||||
|             { | ||||
|                 BotConfig = uow.BotConfig.GetOrCreate(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public bool Edit(BotConfigEditType type, string newValue) | ||||
|         { | ||||
|             using (var uow = _db.UnitOfWork) | ||||
|             { | ||||
|                 var bc = uow.BotConfig.GetOrCreate(); | ||||
|                 switch (type) | ||||
|                 { | ||||
|                     case BotConfigEditType.CurrencyGenerationChance: | ||||
|                         if (float.TryParse(newValue, out var chance) | ||||
|                             && chance >= 0 | ||||
|                             && chance <= 1) | ||||
|                         { | ||||
|                             bc.CurrencyGenerationChance = chance; | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             return false; | ||||
|                         } | ||||
|                         break; | ||||
|                     case BotConfigEditType.CurrencyGenerationCooldown: | ||||
|                         if (int.TryParse(newValue, out var cd) && cd >= 1) | ||||
|                         { | ||||
|                             bc.CurrencyGenerationCooldown = cd; | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             return false; | ||||
|                         } | ||||
|                         break; | ||||
|                     case BotConfigEditType.CurrencyName: | ||||
|                         bc.CurrencyName = newValue ?? "-"; | ||||
|                         break; | ||||
|                     case BotConfigEditType.CurrencyPluralName: | ||||
|                         bc.CurrencyPluralName = newValue ?? bc.CurrencyName + "s"; | ||||
|                         break; | ||||
|                     case BotConfigEditType.CurrencySign: | ||||
|                         bc.CurrencySign = newValue ?? "-"; | ||||
|                         break; | ||||
|                     case BotConfigEditType.DmHelpString: | ||||
|                         bc.DMHelpString = string.IsNullOrWhiteSpace(newValue) | ||||
|                             ? "-" | ||||
|                             : newValue; | ||||
|                         break; | ||||
|                     case BotConfigEditType.HelpString: | ||||
|                         bc.HelpString = string.IsNullOrWhiteSpace(newValue) | ||||
|                             ? "-" | ||||
|                             : newValue; | ||||
|                         break; | ||||
|                     case BotConfigEditType.CurrencyDropAmount: | ||||
|                         if (int.TryParse(newValue, out var amount) && amount > 0) | ||||
|                             bc.CurrencyDropAmount = amount; | ||||
|                         else | ||||
|                             return false; | ||||
|                         break; | ||||
|                     case BotConfigEditType.CurrencyDropAmountMax: | ||||
|                         if (newValue == null) | ||||
|                             bc.CurrencyDropAmountMax = null; | ||||
|                         else if (int.TryParse(newValue, out var maxAmount) && maxAmount > 0) | ||||
|                             bc.CurrencyDropAmountMax = maxAmount; | ||||
|                         else | ||||
|                             return false; | ||||
|                         break; | ||||
|                     case BotConfigEditType.MinimumBetAmount: | ||||
|                         if (int.TryParse(newValue, out var minBetAmount) && minBetAmount > 0) | ||||
|                             bc.MinimumBetAmount = minBetAmount; | ||||
|                         else | ||||
|                             return false; | ||||
|                         break; | ||||
|                     case BotConfigEditType.TriviaCurrencyReward: | ||||
|                         if (int.TryParse(newValue, out var triviaReward) && triviaReward > 0) | ||||
|                             bc.TriviaCurrencyReward = triviaReward; | ||||
|                         else | ||||
|                             return false; | ||||
|                         break; | ||||
|                     case BotConfigEditType.Betroll100Multiplier: | ||||
|                         if (float.TryParse(newValue, out var br100) && br100 > 0) | ||||
|                             bc.Betroll100Multiplier = br100; | ||||
|                         else | ||||
|                             return false; | ||||
|                         break; | ||||
|                     case BotConfigEditType.Betroll91Multiplier: | ||||
|                         if (int.TryParse(newValue, out var br91) && br91 > 0) | ||||
|                             bc.Betroll91Multiplier = br91; | ||||
|                         else | ||||
|                             return false; | ||||
|                         break; | ||||
|                     case BotConfigEditType.Betroll67Multiplier: | ||||
|                         if (int.TryParse(newValue, out var br67) && br67 > 0) | ||||
|                             bc.Betroll67Multiplier = br67; | ||||
|                         else | ||||
|                             return false; | ||||
|                         break; | ||||
|                     case BotConfigEditType.BetflipMultiplier: | ||||
|                         if (int.TryParse(newValue, out var bf) && bf > 0) | ||||
|                             bc.BetflipMultiplier = bf; | ||||
|                         else | ||||
|                             return false; | ||||
|                         break; | ||||
|                     case BotConfigEditType.XpPerMessage: | ||||
|                         if (int.TryParse(newValue, out var xp) && xp > 0) | ||||
|                             bc.XpPerMessage = xp; | ||||
|                         else | ||||
|                             return false; | ||||
|                         break; | ||||
|                     case BotConfigEditType.XpMinutesTimeout: | ||||
|                         if (int.TryParse(newValue, out var min) && min > 0) | ||||
|                             bc.XpMinutesTimeout = min; | ||||
|                         else | ||||
|                             return false; | ||||
|                         break; | ||||
|                     default: | ||||
|                         return false; | ||||
|                 } | ||||
|  | ||||
|                 BotConfig = bc; | ||||
|                 uow.Complete(); | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										149
									
								
								NadekoBot.Core/Services/Impl/BotCredentials.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								NadekoBot.Core/Services/Impl/BotCredentials.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,149 @@ | ||||
| using Newtonsoft.Json; | ||||
| using System; | ||||
| using System.IO; | ||||
| using Discord; | ||||
| using System.Linq; | ||||
| using NLog; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| using System.Collections.Immutable; | ||||
| using NadekoBot.Common; | ||||
|  | ||||
| namespace NadekoBot.Services.Impl | ||||
| { | ||||
|     public class BotCredentials : IBotCredentials | ||||
|     { | ||||
|         private Logger _log; | ||||
|  | ||||
|         public ulong ClientId { get; } | ||||
|  | ||||
|         public string GoogleApiKey { get; } | ||||
|  | ||||
|         public string MashapeKey { get; } | ||||
|  | ||||
|         public string Token { get; } | ||||
|  | ||||
|         public ImmutableArray<ulong> OwnerIds { get; } | ||||
|  | ||||
|         public string LoLApiKey { get; } | ||||
|         public string OsuApiKey { get; } | ||||
|         public string CleverbotApiKey { get; } | ||||
|         public RestartConfig RestartCommand { get; } | ||||
|         public DBConfig Db { get; } | ||||
|         public int TotalShards { get; } | ||||
|         public string CarbonKey { get; } | ||||
|  | ||||
|         private readonly string _credsFileName = Path.Combine(Directory.GetCurrentDirectory(), "credentials.json"); | ||||
|         public string PatreonAccessToken { get; } | ||||
|         public string ShardRunCommand { get; } | ||||
|         public string ShardRunArguments { get; } | ||||
|         public int ShardRunPort { get; } | ||||
|  | ||||
|         public string PatreonCampaignId { get; } | ||||
|  | ||||
|         public BotCredentials() | ||||
|         { | ||||
|             _log = LogManager.GetCurrentClassLogger(); | ||||
|  | ||||
|             try { File.WriteAllText("./credentials_example.json", JsonConvert.SerializeObject(new CredentialsModel(), Formatting.Indented)); } catch { } | ||||
|             if(!File.Exists(_credsFileName)) | ||||
|                 _log.Warn($"credentials.json is missing. Attempting to load creds from environment variables prefixed with 'NadekoBot_'. Example is in {Path.GetFullPath("./credentials_example.json")}"); | ||||
|             try | ||||
|             { | ||||
|                 var configBuilder = new ConfigurationBuilder(); | ||||
|                 configBuilder.AddJsonFile(_credsFileName, true) | ||||
|                     .AddEnvironmentVariables("NadekoBot_"); | ||||
|  | ||||
|                 var data = configBuilder.Build(); | ||||
|  | ||||
|                 Token = data[nameof(Token)]; | ||||
|                 if (string.IsNullOrWhiteSpace(Token)) | ||||
|                 { | ||||
|                     _log.Error("Token is missing from credentials.json or Environment varibles. Add it and restart the program."); | ||||
|                     Console.ReadKey(); | ||||
|                     Environment.Exit(3); | ||||
|                 } | ||||
|                 OwnerIds = data.GetSection("OwnerIds").GetChildren().Select(c => ulong.Parse(c.Value)).ToImmutableArray(); | ||||
|                 LoLApiKey = data[nameof(LoLApiKey)]; | ||||
|                 GoogleApiKey = data[nameof(GoogleApiKey)]; | ||||
|                 MashapeKey = data[nameof(MashapeKey)]; | ||||
|                 OsuApiKey = data[nameof(OsuApiKey)]; | ||||
|                 PatreonAccessToken = data[nameof(PatreonAccessToken)]; | ||||
|                 PatreonCampaignId = data[nameof(PatreonCampaignId)] ?? "334038"; | ||||
|                 ShardRunCommand = data[nameof(ShardRunCommand)]; | ||||
|                 ShardRunArguments = data[nameof(ShardRunArguments)]; | ||||
|                 CleverbotApiKey = data[nameof(CleverbotApiKey)]; | ||||
|  | ||||
|                 var restartSection = data.GetSection(nameof(RestartCommand)); | ||||
|                 var cmd = restartSection["cmd"]; | ||||
|                 var args = restartSection["args"]; | ||||
|                 if (!string.IsNullOrWhiteSpace(cmd)) | ||||
|                     RestartCommand = new RestartConfig(cmd, args); | ||||
|  | ||||
|                 if (string.IsNullOrWhiteSpace(ShardRunCommand)) | ||||
|                     ShardRunCommand = "dotnet"; | ||||
|                 if (string.IsNullOrWhiteSpace(ShardRunArguments)) | ||||
|                     ShardRunArguments = "run -c Release -- {0} {1} {2}"; | ||||
|                  | ||||
|                 var portStr = data[nameof(ShardRunPort)]; | ||||
|                 if (string.IsNullOrWhiteSpace(portStr)) | ||||
|                     ShardRunPort = new NadekoRandom().Next(5000, 6000); | ||||
|                 else | ||||
|                     ShardRunPort = int.Parse(portStr); | ||||
|  | ||||
|                 int ts = 1; | ||||
|                 int.TryParse(data[nameof(TotalShards)], out ts); | ||||
|                 TotalShards = ts < 1 ? 1 : ts; | ||||
|  | ||||
|                 ulong.TryParse(data[nameof(ClientId)], out ulong clId); | ||||
|                 ClientId = clId; | ||||
|  | ||||
|                 CarbonKey = data[nameof(CarbonKey)]; | ||||
|                 var dbSection = data.GetSection("db"); | ||||
|                 Db = new DBConfig(string.IsNullOrWhiteSpace(dbSection["Type"])  | ||||
|                                 ? "sqlite"  | ||||
|                                 : dbSection["Type"],  | ||||
|                             string.IsNullOrWhiteSpace(dbSection["ConnectionString"])  | ||||
|                                 ? "Data Source=data/NadekoBot.db" | ||||
|                                 : dbSection["ConnectionString"]); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 _log.Fatal(ex.Message); | ||||
|                 _log.Fatal(ex); | ||||
|                 throw; | ||||
|             } | ||||
|              | ||||
|         } | ||||
|  | ||||
|         private class CredentialsModel | ||||
|         { | ||||
|             public ulong ClientId { get; set; } = 123123123; | ||||
|             public string Token { get; set; } = ""; | ||||
|             public ulong[] OwnerIds { get; set; } = new ulong[1]; | ||||
|             public string LoLApiKey { get; set; } = ""; | ||||
|             public string GoogleApiKey { get; set; } = ""; | ||||
|             public string MashapeKey { get; set; } = ""; | ||||
|             public string OsuApiKey { get; set; } = ""; | ||||
|             public string SoundCloudClientId { get; set; } = ""; | ||||
|             public string CleverbotApiKey { get; } = ""; | ||||
|             public string CarbonKey { get; set; } = ""; | ||||
|             public DBConfig Db { get; set; } = new DBConfig("sqlite", "Data Source=data/NadekoBot.db"); | ||||
|             public int TotalShards { get; set; } = 1; | ||||
|             public string PatreonAccessToken { get; set; } = ""; | ||||
|             public string PatreonCampaignId { get; set; } = "334038"; | ||||
|             public string RestartCommand { get; set; } = null; | ||||
|  | ||||
|             public string ShardRunCommand { get; set; } = ""; | ||||
|             public string ShardRunArguments { get; set; } = ""; | ||||
|             public int? ShardRunPort { get; set; } = null; | ||||
|         } | ||||
|  | ||||
|         private class DbModel | ||||
|         { | ||||
|             public string Type { get; set; } | ||||
|             public string ConnectionString { get; set; } | ||||
|         } | ||||
|  | ||||
|         public bool IsOwner(IUser u) => OwnerIds.Contains(u.Id); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										384
									
								
								NadekoBot.Core/Services/Impl/GoogleApiService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								NadekoBot.Core/Services/Impl/GoogleApiService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,384 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| using Google.Apis.YouTube.v3; | ||||
| using Google.Apis.Services; | ||||
| using System.Text.RegularExpressions; | ||||
| using Google.Apis.Urlshortener.v1; | ||||
| using Google.Apis.Urlshortener.v1.Data; | ||||
| using NLog; | ||||
| using Google.Apis.Customsearch.v1; | ||||
| using System.Net.Http; | ||||
| using System.Net; | ||||
| using Newtonsoft.Json.Linq; | ||||
| using NadekoBot.Extensions; | ||||
|  | ||||
| namespace NadekoBot.Services.Impl | ||||
| { | ||||
|     public class GoogleApiService : IGoogleApiService | ||||
|     { | ||||
|         const string search_engine_id = "018084019232060951019:hs5piey28-e"; | ||||
|  | ||||
|         private YouTubeService yt; | ||||
|         private UrlshortenerService sh; | ||||
|         private CustomsearchService cs; | ||||
|  | ||||
|         private Logger _log { get; } | ||||
|  | ||||
|         public GoogleApiService(IBotCredentials creds) | ||||
|         { | ||||
|             _creds = creds; | ||||
|  | ||||
|             var bcs = new BaseClientService.Initializer | ||||
|             { | ||||
|                 ApplicationName = "Nadeko Bot", | ||||
|                 ApiKey = _creds.GoogleApiKey, | ||||
|             }; | ||||
|  | ||||
|             _log = LogManager.GetCurrentClassLogger(); | ||||
|  | ||||
|             yt = new YouTubeService(bcs); | ||||
|             sh = new UrlshortenerService(bcs); | ||||
|             cs = new CustomsearchService(bcs); | ||||
|         } | ||||
|         private static readonly Regex plRegex = new Regex("(?:youtu\\.be\\/|list=)(?<id>[\\da-zA-Z\\-_]*)", RegexOptions.Compiled); | ||||
|         public async Task<IEnumerable<string>> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1) | ||||
|         { | ||||
|             await Task.Yield(); | ||||
|             if (string.IsNullOrWhiteSpace(keywords)) | ||||
|                 throw new ArgumentNullException(nameof(keywords)); | ||||
|  | ||||
|             if (count <= 0) | ||||
|                 throw new ArgumentOutOfRangeException(nameof(count)); | ||||
|  | ||||
|             var match = plRegex.Match(keywords); | ||||
|             if (match.Length > 1) | ||||
|             { | ||||
|                 return new[] { match.Groups["id"].Value.ToString() }; | ||||
|             } | ||||
|             var query = yt.Search.List("snippet"); | ||||
|             query.MaxResults = count; | ||||
|             query.Type = "playlist"; | ||||
|             query.Q = keywords; | ||||
|  | ||||
|             return (await query.ExecuteAsync()).Items.Select(i => i.Id.PlaylistId); | ||||
|         } | ||||
|  | ||||
|         //private readonly Regex YtVideoIdRegex = new Regex(@"(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)(?<id>[a-zA-Z0-9_-]{6,11})", RegexOptions.Compiled); | ||||
|         private readonly IBotCredentials _creds; | ||||
|  | ||||
|         public async Task<IEnumerable<string>> GetRelatedVideosAsync(string id, int count = 1) | ||||
|         { | ||||
|             await Task.Yield(); | ||||
|             if (string.IsNullOrWhiteSpace(id)) | ||||
|                 throw new ArgumentNullException(nameof(id)); | ||||
|  | ||||
|             if (count <= 0) | ||||
|                 throw new ArgumentOutOfRangeException(nameof(count)); | ||||
|             var query = yt.Search.List("snippet"); | ||||
|             query.MaxResults = count; | ||||
|             query.RelatedToVideoId = id; | ||||
|             query.Type = "video"; | ||||
|             return (await query.ExecuteAsync()).Items.Select(i => "http://www.youtube.com/watch?v=" + i.Id.VideoId); | ||||
|         } | ||||
|  | ||||
|         public async Task<IEnumerable<string>> GetVideoLinksByKeywordAsync(string keywords, int count = 1) | ||||
|         { | ||||
|             await Task.Yield(); | ||||
|             if (string.IsNullOrWhiteSpace(keywords)) | ||||
|                 throw new ArgumentNullException(nameof(keywords)); | ||||
|  | ||||
|             if (count <= 0) | ||||
|                 throw new ArgumentOutOfRangeException(nameof(count)); | ||||
|              | ||||
|             var query = yt.Search.List("snippet"); | ||||
|             query.MaxResults = count; | ||||
|             query.Q = keywords; | ||||
|             query.Type = "video"; | ||||
|             return (await query.ExecuteAsync()).Items.Select(i => "http://www.youtube.com/watch?v=" + i.Id.VideoId); | ||||
|         } | ||||
|  | ||||
|         public async Task<IEnumerable<(string Name, string Id, string Url)>> GetVideoInfosByKeywordAsync(string keywords, int count = 1) | ||||
|         { | ||||
|             await Task.Yield(); | ||||
|             if (string.IsNullOrWhiteSpace(keywords)) | ||||
|                 throw new ArgumentNullException(nameof(keywords)); | ||||
|  | ||||
|             if (count <= 0) | ||||
|                 throw new ArgumentOutOfRangeException(nameof(count)); | ||||
|  | ||||
|             var query = yt.Search.List("snippet"); | ||||
|             query.MaxResults = count; | ||||
|             query.Q = keywords; | ||||
|             query.Type = "video"; | ||||
|             return (await query.ExecuteAsync()).Items.Select(i => (i.Snippet.Title.TrimTo(50), i.Id.VideoId, "http://www.youtube.com/watch?v=" + i.Id.VideoId)); | ||||
|         } | ||||
|  | ||||
|         public async Task<string> ShortenUrl(string url) | ||||
|         { | ||||
|             await Task.Yield(); | ||||
|             if (string.IsNullOrWhiteSpace(url)) | ||||
|                 throw new ArgumentNullException(nameof(url)); | ||||
|  | ||||
|             if (string.IsNullOrWhiteSpace(_creds.GoogleApiKey)) | ||||
|                 return url; | ||||
|  | ||||
|             try | ||||
|             { | ||||
|                 var response = await sh.Url.Insert(new Url { LongUrl = url }).ExecuteAsync(); | ||||
|                 return response.Id; | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 _log.Warn(ex); | ||||
|                 return url; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public async Task<IEnumerable<string>> GetPlaylistTracksAsync(string playlistId, int count = 50) | ||||
|         { | ||||
|             await Task.Yield(); | ||||
|             if (string.IsNullOrWhiteSpace(playlistId)) | ||||
|                 throw new ArgumentNullException(nameof(playlistId)); | ||||
|  | ||||
|             if (count <= 0) | ||||
|                 throw new ArgumentOutOfRangeException(nameof(count)); | ||||
|  | ||||
|             string nextPageToken = null; | ||||
|  | ||||
|             List<string> toReturn = new List<string>(count); | ||||
|  | ||||
|             do | ||||
|             { | ||||
|                 var toGet = count > 50 ? 50 : count; | ||||
|                 count -= toGet; | ||||
|  | ||||
|                 var query = yt.PlaylistItems.List("contentDetails"); | ||||
|                 query.MaxResults = toGet; | ||||
|                 query.PlaylistId = playlistId; | ||||
|                 query.PageToken = nextPageToken; | ||||
|  | ||||
|                 var data = await query.ExecuteAsync(); | ||||
|  | ||||
|                 toReturn.AddRange(data.Items.Select(i => i.ContentDetails.VideoId)); | ||||
|                 nextPageToken = data.NextPageToken; | ||||
|             } | ||||
|             while (count > 0 && !string.IsNullOrWhiteSpace(nextPageToken)); | ||||
|  | ||||
|             return toReturn; | ||||
|         } | ||||
|  | ||||
|         public async Task<IReadOnlyDictionary<string, TimeSpan>> GetVideoDurationsAsync(IEnumerable<string> videoIds) | ||||
|         { | ||||
|             await Task.Yield(); | ||||
|             var videoIdsList = videoIds as List<string> ?? videoIds.ToList(); | ||||
|  | ||||
|             Dictionary<string, TimeSpan> toReturn = new Dictionary<string, TimeSpan>(); | ||||
|  | ||||
|             if (!videoIdsList.Any()) | ||||
|                 return toReturn; | ||||
|             var toGet = 0; | ||||
|             var remaining = videoIdsList.Count; | ||||
|  | ||||
|             do | ||||
|             { | ||||
|                 toGet = remaining > 50 ? 50 : remaining; | ||||
|                 remaining -= toGet; | ||||
|  | ||||
|                 var q = yt.Videos.List("contentDetails"); | ||||
|                 q.Id = string.Join(",", videoIdsList.Take(toGet)); | ||||
|                 videoIdsList = videoIdsList.Skip(toGet).ToList(); | ||||
|                 var items = (await q.ExecuteAsync().ConfigureAwait(false)).Items; | ||||
|                 foreach (var i in items) | ||||
|                 { | ||||
|                     toReturn.Add(i.Id, System.Xml.XmlConvert.ToTimeSpan(i.ContentDetails.Duration)); | ||||
|                 } | ||||
|             } | ||||
|             while (remaining > 0); | ||||
|  | ||||
|             return toReturn; | ||||
|         } | ||||
|  | ||||
|         public async Task<ImageResult> GetImageAsync(string query, int start = 1) | ||||
|         { | ||||
|             await Task.Yield(); | ||||
|             if (string.IsNullOrWhiteSpace(query)) | ||||
|                 throw new ArgumentNullException(nameof(query)); | ||||
|  | ||||
|             var req = cs.Cse.List(query); | ||||
|             req.Cx = search_engine_id; | ||||
|             req.Num = 1; | ||||
|             req.Fields = "items(image(contextLink,thumbnailLink),link)"; | ||||
|             req.SearchType = CseResource.ListRequest.SearchTypeEnum.Image; | ||||
|             req.Start = start; | ||||
|  | ||||
|             var search = await req.ExecuteAsync().ConfigureAwait(false); | ||||
|  | ||||
|             return new ImageResult(search.Items[0].Image, search.Items[0].Link); | ||||
|         } | ||||
|  | ||||
|         public IEnumerable<string> Languages => _languageDictionary.Keys.OrderBy(x => x); | ||||
|         private readonly Dictionary<string, string> _languageDictionary = new Dictionary<string, string>() { | ||||
|                     { "afrikaans", "af"}, | ||||
|                     { "albanian", "sq"}, | ||||
|                     { "arabic", "ar"}, | ||||
|                     { "armenian", "hy"}, | ||||
|                     { "azerbaijani", "az"}, | ||||
|                     { "basque", "eu"}, | ||||
|                     { "belarusian", "be"}, | ||||
|                     { "bengali", "bn"}, | ||||
|                     { "bulgarian", "bg"}, | ||||
|                     { "catalan", "ca"}, | ||||
|                     { "chinese-traditional", "zh-TW"}, | ||||
|                     { "chinese-simplified", "zh-CN"}, | ||||
|                     { "chinese", "zh-CN"}, | ||||
|                     { "croatian", "hr"}, | ||||
|                     { "czech", "cs"}, | ||||
|                     { "danish", "da"}, | ||||
|                     { "dutch", "nl"}, | ||||
|                     { "english", "en"}, | ||||
|                     { "esperanto", "eo"}, | ||||
|                     { "estonian", "et"}, | ||||
|                     { "filipino", "tl"}, | ||||
|                     { "finnish", "fi"}, | ||||
|                     { "french", "fr"}, | ||||
|                     { "galician", "gl"}, | ||||
|                     { "german", "de"}, | ||||
|                     { "georgian", "ka"}, | ||||
|                     { "greek", "el"}, | ||||
|                     { "haitian Creole", "ht"}, | ||||
|                     { "hebrew", "iw"}, | ||||
|                     { "hindi", "hi"}, | ||||
|                     { "hungarian", "hu"}, | ||||
|                     { "icelandic", "is"}, | ||||
|                     { "indonesian", "id"}, | ||||
|                     { "irish", "ga"}, | ||||
|                     { "italian", "it"}, | ||||
|                     { "japanese", "ja"}, | ||||
|                     { "korean", "ko"}, | ||||
|                     { "lao", "lo"}, | ||||
|                     { "latin", "la"}, | ||||
|                     { "latvian", "lv"}, | ||||
|                     { "lithuanian", "lt"}, | ||||
|                     { "macedonian", "mk"}, | ||||
|                     { "malay", "ms"}, | ||||
|                     { "maltese", "mt"}, | ||||
|                     { "norwegian", "no"}, | ||||
|                     { "persian", "fa"}, | ||||
|                     { "polish", "pl"}, | ||||
|                     { "portuguese", "pt"}, | ||||
|                     { "romanian", "ro"}, | ||||
|                     { "russian", "ru"}, | ||||
|                     { "serbian", "sr"}, | ||||
|                     { "slovak", "sk"}, | ||||
|                     { "slovenian", "sl"}, | ||||
|                     { "spanish", "es"}, | ||||
|                     { "swahili", "sw"}, | ||||
|                     { "swedish", "sv"}, | ||||
|                     { "tamil", "ta"}, | ||||
|                     { "telugu", "te"}, | ||||
|                     { "thai", "th"}, | ||||
|                     { "turkish", "tr"}, | ||||
|                     { "ukrainian", "uk"}, | ||||
|                     { "urdu", "ur"}, | ||||
|                     { "vietnamese", "vi"}, | ||||
|                     { "welsh", "cy"}, | ||||
|                     { "yiddish", "yi"}, | ||||
|  | ||||
|                     { "af", "af"}, | ||||
|                     { "sq", "sq"}, | ||||
|                     { "ar", "ar"}, | ||||
|                     { "hy", "hy"}, | ||||
|                     { "az", "az"}, | ||||
|                     { "eu", "eu"}, | ||||
|                     { "be", "be"}, | ||||
|                     { "bn", "bn"}, | ||||
|                     { "bg", "bg"}, | ||||
|                     { "ca", "ca"}, | ||||
|                     { "zh-tw", "zh-TW"}, | ||||
|                     { "zh-cn", "zh-CN"}, | ||||
|                     { "hr", "hr"}, | ||||
|                     { "cs", "cs"}, | ||||
|                     { "da", "da"}, | ||||
|                     { "nl", "nl"}, | ||||
|                     { "en", "en"}, | ||||
|                     { "eo", "eo"}, | ||||
|                     { "et", "et"}, | ||||
|                     { "tl", "tl"}, | ||||
|                     { "fi", "fi"}, | ||||
|                     { "fr", "fr"}, | ||||
|                     { "gl", "gl"}, | ||||
|                     { "de", "de"}, | ||||
|                     { "ka", "ka"}, | ||||
|                     { "el", "el"}, | ||||
|                     { "ht", "ht"}, | ||||
|                     { "iw", "iw"}, | ||||
|                     { "hi", "hi"}, | ||||
|                     { "hu", "hu"}, | ||||
|                     { "is", "is"}, | ||||
|                     { "id", "id"}, | ||||
|                     { "ga", "ga"}, | ||||
|                     { "it", "it"}, | ||||
|                     { "ja", "ja"}, | ||||
|                     { "ko", "ko"}, | ||||
|                     { "lo", "lo"}, | ||||
|                     { "la", "la"}, | ||||
|                     { "lv", "lv"}, | ||||
|                     { "lt", "lt"}, | ||||
|                     { "mk", "mk"}, | ||||
|                     { "ms", "ms"}, | ||||
|                     { "mt", "mt"}, | ||||
|                     { "no", "no"}, | ||||
|                     { "fa", "fa"}, | ||||
|                     { "pl", "pl"}, | ||||
|                     { "pt", "pt"}, | ||||
|                     { "ro", "ro"}, | ||||
|                     { "ru", "ru"}, | ||||
|                     { "sr", "sr"}, | ||||
|                     { "sk", "sk"}, | ||||
|                     { "sl", "sl"}, | ||||
|                     { "es", "es"}, | ||||
|                     { "sw", "sw"}, | ||||
|                     { "sv", "sv"}, | ||||
|                     { "ta", "ta"}, | ||||
|                     { "te", "te"}, | ||||
|                     { "th", "th"}, | ||||
|                     { "tr", "tr"}, | ||||
|                     { "uk", "uk"}, | ||||
|                     { "ur", "ur"}, | ||||
|                     { "vi", "vi"}, | ||||
|                     { "cy", "cy"}, | ||||
|                     { "yi", "yi"}, | ||||
|                 }; | ||||
|  | ||||
|         public async Task<string> Translate(string sourceText, string sourceLanguage, string targetLanguage) | ||||
|         { | ||||
|             await Task.Yield(); | ||||
|             string text; | ||||
|  | ||||
|             if (!_languageDictionary.ContainsKey(sourceLanguage) || | ||||
|                !_languageDictionary.ContainsKey(targetLanguage)) | ||||
|                 throw new ArgumentException(); | ||||
|  | ||||
|  | ||||
|             var url = string.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}", | ||||
|                                         ConvertToLanguageCode(sourceLanguage), | ||||
|                                         ConvertToLanguageCode(targetLanguage), | ||||
|                                        WebUtility.UrlEncode(sourceText)); | ||||
|             using (var http = new HttpClient()) | ||||
|             { | ||||
|                 http.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"); | ||||
|                 text = await http.GetStringAsync(url).ConfigureAwait(false); | ||||
|             } | ||||
|  | ||||
|             return (string.Concat(JArray.Parse(text)[0].Select(x => x[0]))); | ||||
|         } | ||||
|  | ||||
|         private string ConvertToLanguageCode(string language) | ||||
|         { | ||||
|             _languageDictionary.TryGetValue(language, out var mode); | ||||
|             return mode; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										93
									
								
								NadekoBot.Core/Services/Impl/ImagesService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								NadekoBot.Core/Services/Impl/ImagesService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| using NLog; | ||||
| using System; | ||||
| using System.Collections.Immutable; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace NadekoBot.Services.Impl | ||||
| { | ||||
|     public class ImagesService : IImagesService | ||||
|     { | ||||
|         private readonly Logger _log; | ||||
|  | ||||
|         private const string _basePath = "data/images/"; | ||||
|  | ||||
|         private const string _headsPath = _basePath + "coins/heads.png"; | ||||
|         private const string _tailsPath = _basePath + "coins/tails.png"; | ||||
|  | ||||
|         private const string _currencyImagesPath = _basePath + "currency"; | ||||
|         private const string _diceImagesPath = _basePath + "dice"; | ||||
|  | ||||
|         private const string _slotBackgroundPath = _basePath + "slots/background2.png"; | ||||
|         private const string _slotNumbersPath = _basePath + "slots/numbers/"; | ||||
|         private const string _slotEmojisPath = _basePath + "slots/emojis/"; | ||||
|  | ||||
|         private const string _wifeMatrixPath = _basePath + "rategirl/wifematrix.png"; | ||||
|         private const string _rategirlDot = _basePath + "rategirl/dot.png"; | ||||
|  | ||||
|         private const string _xpCardPath = _basePath + "xp/xp.png"; | ||||
|  | ||||
|  | ||||
|         public ImmutableArray<byte> Heads { get; private set; } | ||||
|         public ImmutableArray<byte> Tails { get; private set; } | ||||
|          | ||||
|         public ImmutableArray<(string, ImmutableArray<byte>)> Currency { get; private set; } | ||||
|  | ||||
|         public ImmutableArray<ImmutableArray<byte>> Dice { get; private set; } | ||||
|  | ||||
|         public ImmutableArray<byte> SlotBackground { get; private set; } | ||||
|         public ImmutableArray<ImmutableArray<byte>> SlotNumbers { get; private set; } | ||||
|         public ImmutableArray<ImmutableArray<byte>> SlotEmojis { get; private set; } | ||||
|  | ||||
|         public ImmutableArray<byte> WifeMatrix { get; private set; } | ||||
|         public ImmutableArray<byte> RategirlDot { get; private set; } | ||||
|  | ||||
|         public ImmutableArray<byte> XpCard { get; private set; } | ||||
|  | ||||
|         public ImagesService() | ||||
|         { | ||||
|             _log = LogManager.GetCurrentClassLogger(); | ||||
|             this.Reload(); | ||||
|         } | ||||
|  | ||||
|         public void Reload() | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 Heads = File.ReadAllBytes(_headsPath).ToImmutableArray(); | ||||
|                 Tails = File.ReadAllBytes(_tailsPath).ToImmutableArray(); | ||||
|  | ||||
|                 Currency = Directory.GetFiles(_currencyImagesPath) | ||||
|                     .Select(x => (Path.GetFileName(x), File.ReadAllBytes(x).ToImmutableArray())) | ||||
|                     .ToImmutableArray(); | ||||
|  | ||||
|                 Dice = Directory.GetFiles(_diceImagesPath) | ||||
|                                 .OrderBy(x => int.Parse(Path.GetFileNameWithoutExtension(x))) | ||||
|                                 .Select(x => File.ReadAllBytes(x).ToImmutableArray()) | ||||
|                                 .ToImmutableArray(); | ||||
|                  | ||||
|                 SlotBackground = File.ReadAllBytes(_slotBackgroundPath).ToImmutableArray(); | ||||
|  | ||||
|                 SlotNumbers = Directory.GetFiles(_slotNumbersPath) | ||||
|                     .OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f))) | ||||
|                     .Select(x => File.ReadAllBytes(x).ToImmutableArray()) | ||||
|                     .ToImmutableArray(); | ||||
|  | ||||
|                 SlotEmojis = Directory.GetFiles(_slotEmojisPath) | ||||
|                     .OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f))) | ||||
|                     .Select(x => File.ReadAllBytes(x).ToImmutableArray()) | ||||
|                     .ToImmutableArray(); | ||||
|  | ||||
|                 WifeMatrix = File.ReadAllBytes(_wifeMatrixPath).ToImmutableArray(); | ||||
|                 RategirlDot = File.ReadAllBytes(_rategirlDot).ToImmutableArray(); | ||||
|  | ||||
|                 XpCard = File.ReadAllBytes(_xpCardPath).ToImmutableArray(); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 _log.Error(ex); | ||||
|                 throw; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										146
									
								
								NadekoBot.Core/Services/Impl/Localization.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								NadekoBot.Core/Services/Impl/Localization.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| using System.Collections.Concurrent; | ||||
| using System.Collections.Generic; | ||||
| using System.Globalization; | ||||
| using System.Linq; | ||||
| using Discord; | ||||
| using NLog; | ||||
| using NadekoBot.Services.Database.Models; | ||||
| using NadekoBot.Common; | ||||
| using Newtonsoft.Json; | ||||
| using System.IO; | ||||
|  | ||||
| namespace NadekoBot.Services.Impl | ||||
| { | ||||
|     public class Localization : ILocalization | ||||
|     { | ||||
|         private readonly Logger _log; | ||||
|         private readonly DbService _db; | ||||
|  | ||||
|         public ConcurrentDictionary<ulong, CultureInfo> GuildCultureInfos { get; } | ||||
|         public CultureInfo DefaultCultureInfo { get; private set; } = CultureInfo.CurrentCulture; | ||||
|  | ||||
|         private static readonly Dictionary<string, CommandData> _commandData; | ||||
|          | ||||
|         static Localization() | ||||
|         { | ||||
|             _commandData = JsonConvert.DeserializeObject<Dictionary<string, CommandData>>( | ||||
|                 File.ReadAllText("./data/command_strings.json")); | ||||
|         } | ||||
|  | ||||
|         private Localization() { } | ||||
|         public Localization(IBotConfigProvider bcp, IEnumerable<GuildConfig> gcs, DbService db) | ||||
|         { | ||||
|             _log = LogManager.GetCurrentClassLogger(); | ||||
|  | ||||
|             var cultureInfoNames = gcs.ToDictionary(x => x.GuildId, x => x.Locale); | ||||
|             var defaultCulture = bcp.BotConfig.Locale; | ||||
|  | ||||
|             _db = db; | ||||
|  | ||||
|             if (string.IsNullOrWhiteSpace(defaultCulture)) | ||||
|                 DefaultCultureInfo = new CultureInfo("en-US"); | ||||
|             else | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     DefaultCultureInfo = new CultureInfo(defaultCulture); | ||||
|                 } | ||||
|                 catch | ||||
|                 { | ||||
|                     _log.Warn("Unable to load default bot's locale/language. Using en-US."); | ||||
|                     DefaultCultureInfo = new CultureInfo("en-US"); | ||||
|                 } | ||||
|             } | ||||
|             GuildCultureInfos = new ConcurrentDictionary<ulong, CultureInfo>(cultureInfoNames.ToDictionary(x => x.Key, x => | ||||
|               { | ||||
|                   CultureInfo cultureInfo = null; | ||||
|                   try | ||||
|                   { | ||||
|                       if (x.Value == null) | ||||
|                           return null; | ||||
|                       cultureInfo = new CultureInfo(x.Value); | ||||
|                   } | ||||
|                   catch { } | ||||
|                   return cultureInfo; | ||||
|               }).Where(x => x.Value != null)); | ||||
|         } | ||||
|  | ||||
|         public void SetGuildCulture(IGuild guild, CultureInfo ci) => | ||||
|             SetGuildCulture(guild.Id, ci); | ||||
|  | ||||
|         public void SetGuildCulture(ulong guildId, CultureInfo ci) | ||||
|         { | ||||
|             if (ci == DefaultCultureInfo) | ||||
|             { | ||||
|                 RemoveGuildCulture(guildId); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             using (var uow = _db.UnitOfWork) | ||||
|             { | ||||
|                 var gc = uow.GuildConfigs.For(guildId, set => set); | ||||
|                 gc.Locale = ci.Name; | ||||
|                 uow.Complete(); | ||||
|             } | ||||
|  | ||||
|             GuildCultureInfos.AddOrUpdate(guildId, ci, (id, old) => ci); | ||||
|         } | ||||
|  | ||||
|         public void RemoveGuildCulture(IGuild guild) =>  | ||||
|             RemoveGuildCulture(guild.Id); | ||||
|  | ||||
|         public void RemoveGuildCulture(ulong guildId) { | ||||
|  | ||||
|             if (GuildCultureInfos.TryRemove(guildId, out var _)) | ||||
|             { | ||||
|                 using (var uow = _db.UnitOfWork) | ||||
|                 { | ||||
|                     var gc = uow.GuildConfigs.For(guildId, set => set); | ||||
|                     gc.Locale = null; | ||||
|                     uow.Complete(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public void SetDefaultCulture(CultureInfo ci) | ||||
|         { | ||||
|             using (var uow = _db.UnitOfWork) | ||||
|             { | ||||
|                 var bc = uow.BotConfig.GetOrCreate(); | ||||
|                 bc.Locale = ci.Name; | ||||
|                 uow.Complete(); | ||||
|             } | ||||
|             DefaultCultureInfo = ci; | ||||
|         } | ||||
|  | ||||
|         public void ResetDefaultCulture() => | ||||
|             SetDefaultCulture(CultureInfo.CurrentCulture); | ||||
|  | ||||
|         public CultureInfo GetCultureInfo(IGuild guild) => | ||||
|             GetCultureInfo(guild?.Id); | ||||
|  | ||||
|         public CultureInfo GetCultureInfo(ulong? guildId) | ||||
|         { | ||||
|             if (guildId == null) | ||||
|                 return DefaultCultureInfo; | ||||
|             CultureInfo info = null; | ||||
|             GuildCultureInfos.TryGetValue(guildId.Value, out info); | ||||
|             return info ?? DefaultCultureInfo; | ||||
|         } | ||||
|  | ||||
|         public static CommandData LoadCommand(string key) | ||||
|         { | ||||
|             _commandData.TryGetValue(key, out var toReturn); | ||||
|  | ||||
|             if (toReturn == null) | ||||
|                 return new CommandData | ||||
|                 { | ||||
|                     Cmd = key, | ||||
|                     Desc = key, | ||||
|                     Usage = new[] { key }, | ||||
|                 }; | ||||
|  | ||||
|             return toReturn; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										124
									
								
								NadekoBot.Core/Services/Impl/NadekoStrings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								NadekoBot.Core/Services/Impl/NadekoStrings.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Collections.Immutable; | ||||
| using System.Diagnostics; | ||||
| using System.Globalization; | ||||
| using System.IO; | ||||
| using System.Text.RegularExpressions; | ||||
| using Newtonsoft.Json; | ||||
| using NLog; | ||||
|  | ||||
| namespace NadekoBot.Services.Impl | ||||
| { | ||||
|     public class NadekoStrings : INService | ||||
|     { | ||||
|         public const string stringsPath = @"_strings/"; | ||||
|  | ||||
|         private readonly ImmutableDictionary<string, ImmutableDictionary<string, string>> responseStrings; | ||||
|         private readonly Logger _log; | ||||
|         /// <summary> | ||||
|         /// Used as failsafe in case response key doesn't exist in the selected or default language. | ||||
|         /// </summary> | ||||
|         private readonly CultureInfo _usCultureInfo = new CultureInfo("en-US"); | ||||
|         private readonly ILocalization _localization; | ||||
|  | ||||
|         private readonly Regex formatFinder = new Regex(@"{\d}", RegexOptions.Compiled); | ||||
|  | ||||
|         public NadekoStrings(ILocalization loc) | ||||
|         { | ||||
|             _log = LogManager.GetCurrentClassLogger(); | ||||
|             _localization = loc; | ||||
|  | ||||
|             var sw = Stopwatch.StartNew(); | ||||
|             var allLangsDict = new Dictionary<string, ImmutableDictionary<string, string>>(); // lang:(name:value) | ||||
|             foreach (var file in Directory.GetFiles(stringsPath)) | ||||
|             { | ||||
|                 var langDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(file)); | ||||
|  | ||||
|                 allLangsDict.Add(GetLocaleName(file).ToLowerInvariant(), langDict.ToImmutableDictionary()); | ||||
|             } | ||||
|  | ||||
|             responseStrings = allLangsDict.ToImmutableDictionary(); | ||||
|             sw.Stop(); | ||||
|  | ||||
|             _log.Info("Loaded {0} languages in {1:F2}s", | ||||
|                 responseStrings.Count, | ||||
|                 //string.Join(",", responseStrings.Keys), | ||||
|                 sw.Elapsed.TotalSeconds); | ||||
|  | ||||
|             ////improper string format checks | ||||
|             //var compareTo = responseStrings["en-us"] | ||||
|             //    .Select(x => | ||||
|             //    { | ||||
|             //        return (StringKey: x.Key, Placeholders: formatFinder.Matches(x.Value).Cast<Match>().Select(y => y.Value).ToArray()); | ||||
|             //    }) | ||||
|             //    .ToDictionary(x => x.StringKey, x => x.Placeholders); | ||||
|  | ||||
|             //var errors = responseStrings | ||||
|             //    .Select(a => (a.Key, a.Value.Select(x => | ||||
|             //        { | ||||
|             //            if (!compareTo.ContainsKey(x.Key)) | ||||
|             //                return (StringKey: x.Key, Placeholders: new HashSet<string>(), Missing: true); | ||||
|             //            var hs = new HashSet<string>(compareTo[x.Key]); | ||||
|             //            hs.SymmetricExceptWith(formatFinder.Matches(x.Value).Cast<Match>().Select(y => y.Value).ToArray()); | ||||
|             //            return (StringKey: x.Key, Placeholders: hs, Missing: false); | ||||
|             //        }) | ||||
|             //        .Where(x => x.Placeholders.Any() || x.Missing))) | ||||
|             //    .Where(x => x.Item2.Any()); | ||||
|  | ||||
|             //var str = string.Join("\n", errors.Select(x => $"------{x.Item1}------\n" + | ||||
|             //                            string.Join("\n", x.Item2.Select(y => | ||||
|             //                                y.StringKey + ": " + (y.Missing ? "MISSING" : string.Join(", ", y.Placeholders)))))); | ||||
|             //if (!string.IsNullOrWhiteSpace(str)) | ||||
|             //    _log.Warn($"Improperly Formatted strings:\n{str}"); | ||||
|         } | ||||
|  | ||||
|         private string GetLocaleName(string fileName) | ||||
|         { | ||||
|             var dotIndex = fileName.IndexOf('.') + 1; | ||||
|             var secondDotINdex = fileName.LastIndexOf('.'); | ||||
|             return fileName.Substring(dotIndex, secondDotINdex - dotIndex); | ||||
|         } | ||||
|  | ||||
|         private string GetString(string text, CultureInfo cultureInfo) | ||||
|         { | ||||
|             if (!responseStrings.TryGetValue(cultureInfo.Name.ToLowerInvariant(), out ImmutableDictionary<string, string> strings)) | ||||
|                 return null; | ||||
|  | ||||
|             strings.TryGetValue(text, out string val); | ||||
|             return val; | ||||
|         } | ||||
|  | ||||
|         public string GetText(string key, ulong? guildId, string lowerModuleTypeName, params object[] replacements) => | ||||
|             GetText(key, _localization.GetCultureInfo(guildId), lowerModuleTypeName, replacements); | ||||
|  | ||||
|         public string GetText(string key, CultureInfo cultureInfo, string lowerModuleTypeName) | ||||
|         { | ||||
|             var text = GetString(lowerModuleTypeName + "_" + key, cultureInfo); | ||||
|  | ||||
|             if (string.IsNullOrWhiteSpace(text)) | ||||
|             { | ||||
|                 LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + cultureInfo + " response strings. PLEASE REPORT THIS."); | ||||
|                 text = GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} not found!"; | ||||
|                 if (string.IsNullOrWhiteSpace(text)) | ||||
|                     return "I can't tell you if the command is executed, because there was an error printing out the response. Key '" + | ||||
|                         lowerModuleTypeName + "_" + key + "' " + "is missing from resources. Please report this."; | ||||
|             } | ||||
|             return text; | ||||
|         } | ||||
|  | ||||
|         public string GetText(string key, CultureInfo cultureInfo, string lowerModuleTypeName, | ||||
|             params object[] replacements) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 return string.Format(GetText(key, cultureInfo, lowerModuleTypeName), replacements); | ||||
|             } | ||||
|             catch (FormatException) | ||||
|             { | ||||
|                 return "I can't tell you if the command is executed, because there was an error printing out the response. Key '" + | ||||
|                        lowerModuleTypeName + "_" + key + "' " + "is not properly formatted. Please report this."; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										43
									
								
								NadekoBot.Core/Services/Impl/RedisCache.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								NadekoBot.Core/Services/Impl/RedisCache.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| using StackExchange.Redis; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace NadekoBot.Services.Impl | ||||
| { | ||||
|     public class RedisCache : IDataCache | ||||
|     { | ||||
|         private ulong _botid; | ||||
|  | ||||
|         public ConnectionMultiplexer Redis { get; } | ||||
|         private readonly IDatabase _db; | ||||
|  | ||||
|         public RedisCache(ulong botId) | ||||
|         { | ||||
|             _botid = botId; | ||||
|             Redis = ConnectionMultiplexer.Connect("127.0.0.1"); | ||||
|             Redis.PreserveAsyncOrder = false; | ||||
|             _db = Redis.GetDatabase(); | ||||
|         } | ||||
|  | ||||
|         public async Task<(bool Success, byte[] Data)> TryGetImageDataAsync(string key) | ||||
|         { | ||||
|             byte[] x = await _db.StringGetAsync("image_" + key); | ||||
|             return (x != null, x); | ||||
|         } | ||||
|  | ||||
|         public Task SetImageDataAsync(string key, byte[] data) | ||||
|         { | ||||
|             return _db.StringSetAsync("image_" + key, data); | ||||
|         } | ||||
|  | ||||
|         public async Task<(bool Success, string Data)> TryGetAnimeDataAsync(string key) | ||||
|         { | ||||
|             string x = await _db.StringGetAsync("anime_" + key); | ||||
|             return (x != null, x); | ||||
|         } | ||||
|  | ||||
|         public Task SetAnimeDataAsync(string key, string data) | ||||
|         { | ||||
|             return _db.StringSetAsync("anime_" + key, data); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										143
									
								
								NadekoBot.Core/Services/Impl/SoundCloudApiService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								NadekoBot.Core/Services/Impl/SoundCloudApiService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | ||||
| using Newtonsoft.Json; | ||||
| using System; | ||||
| using System.Linq; | ||||
| using System.Net.Http; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace NadekoBot.Services.Impl | ||||
| { | ||||
|     public class SoundCloudApiService : INService | ||||
|     { | ||||
|         private readonly IBotCredentials _creds; | ||||
|  | ||||
|         public SoundCloudApiService(IBotCredentials creds) | ||||
|         { | ||||
|             _creds = creds; | ||||
|         } | ||||
|  | ||||
|         public async Task<SoundCloudVideo> ResolveVideoAsync(string url) | ||||
|         { | ||||
|             if (string.IsNullOrWhiteSpace(url)) | ||||
|                 throw new ArgumentNullException(nameof(url)); | ||||
|  | ||||
|             string response = ""; | ||||
|  | ||||
|             using (var http = new HttpClient()) | ||||
|             { | ||||
|                 response = await http.GetStringAsync($"https://scapi.nadekobot.me/resolve?url={url}").ConfigureAwait(false); | ||||
|             } | ||||
|                  | ||||
|  | ||||
|             var responseObj = JsonConvert.DeserializeObject<SoundCloudVideo>(response); | ||||
|             if (responseObj?.Kind != "track") | ||||
|                 throw new InvalidOperationException("Url is either not a track, or it doesn't exist."); | ||||
|  | ||||
|             return responseObj; | ||||
|         } | ||||
|  | ||||
|         public bool IsSoundCloudLink(string url) => | ||||
|             System.Text.RegularExpressions.Regex.IsMatch(url, "(.*)(soundcloud.com|snd.sc)(.*)"); | ||||
|  | ||||
|         public async Task<SoundCloudVideo> GetVideoByQueryAsync(string query) | ||||
|         { | ||||
|             if (string.IsNullOrWhiteSpace(query)) | ||||
|                 throw new ArgumentNullException(nameof(query)); | ||||
|  | ||||
|             var response = ""; | ||||
|             using (var http = new HttpClient()) | ||||
|             { | ||||
|                 response = await http.GetStringAsync($"https://scapi.nadekobot.me/tracks?q={Uri.EscapeDataString(query)}").ConfigureAwait(false); | ||||
|             } | ||||
|  | ||||
|             var responseObj = JsonConvert.DeserializeObject<SoundCloudVideo[]>(response).Where(s => s.Streamable).FirstOrDefault(); | ||||
|             if (responseObj?.Kind != "track") | ||||
|                 throw new InvalidOperationException("Query yielded no results."); | ||||
|  | ||||
|             return responseObj; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public class SoundCloudVideo | ||||
|     { | ||||
|         public string Kind { get; set; } = ""; | ||||
|         public long Id { get; set; } = 0; | ||||
|         public SoundCloudUser User { get; set; } = new SoundCloudUser(); | ||||
|         public string Title { get; set; } = ""; | ||||
|         [JsonIgnore] | ||||
|         public string FullName => User.Name + " - " + Title; | ||||
|         public bool Streamable { get; set; } = false; | ||||
|         public int Duration { get; set; } | ||||
|         [JsonProperty("permalink_url")] | ||||
|         public string TrackLink { get; set; } = ""; | ||||
|         public string artwork_url { get; set; } = ""; | ||||
|         public async Task<string> StreamLink() | ||||
|         { | ||||
|             using (var http = new HttpClient()) | ||||
|             { | ||||
|                 return await http.GetStringAsync($"http://scapi.nadekobot.me/stream/{Id}"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     public class SoundCloudUser | ||||
|     { | ||||
|         [JsonProperty("username")] | ||||
|         public string Name { get; set; } | ||||
|     } | ||||
|     /* | ||||
|     {"kind":"track", | ||||
|     "id":238888167, | ||||
|     "created_at":"2015/12/24 01:04:52 +0000", | ||||
|     "user_id":43141975, | ||||
|     "duration":120852, | ||||
|     "commentable":true, | ||||
|     "state":"finished", | ||||
|     "original_content_size":4834829, | ||||
|     "last_modified":"2015/12/24 01:17:59 +0000", | ||||
|     "sharing":"public", | ||||
|     "tag_list":"Funky", | ||||
|     "permalink":"18-fd", | ||||
|     "streamable":true, | ||||
|     "embeddable_by":"all", | ||||
|     "downloadable":false, | ||||
|     "purchase_url":null, | ||||
|     "label_id":null, | ||||
|     "purchase_title":null, | ||||
|     "genre":"Disco", | ||||
|     "title":"18 Ж", | ||||
|     "description":"", | ||||
|     "label_name":null, | ||||
|     "release":null, | ||||
|     "track_type":null, | ||||
|     "key_signature":null, | ||||
|     "isrc":null, | ||||
|     "video_url":null, | ||||
|     "bpm":null, | ||||
|     "release_year":null, | ||||
|     "release_month":null, | ||||
|     "release_day":null, | ||||
|     "original_format":"mp3", | ||||
|     "license":"all-rights-reserved", | ||||
|     "uri":"https://api.soundcloud.com/tracks/238888167", | ||||
|     "user":{ | ||||
|         "id":43141975, | ||||
|         "kind":"user", | ||||
|         "permalink":"mrb00gi", | ||||
|         "username":"Mrb00gi", | ||||
|         "last_modified":"2015/12/01 16:06:57 +0000", | ||||
|         "uri":"https://api.soundcloud.com/users/43141975", | ||||
|         "permalink_url":"http://soundcloud.com/mrb00gi", | ||||
|         "avatar_url":"https://a1.sndcdn.com/images/default_avatar_large.png" | ||||
|         }, | ||||
|     "permalink_url":"http://soundcloud.com/mrb00gi/18-fd", | ||||
|     "artwork_url":null, | ||||
|     "waveform_url":"https://w1.sndcdn.com/gsdLfvEW1cUK_m.png", | ||||
|     "stream_url":"https://api.soundcloud.com/tracks/238888167/stream", | ||||
|     "playback_count":7, | ||||
|     "download_count":0, | ||||
|     "favoritings_count":1, | ||||
|     "comment_count":0, | ||||
|     "attachments_uri":"https://api.soundcloud.com/tracks/238888167/attachments"} | ||||
|  | ||||
|     */ | ||||
|  | ||||
| } | ||||
							
								
								
									
										24
									
								
								NadekoBot.Core/Services/Impl/StartingGuildsListService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								NadekoBot.Core/Services/Impl/StartingGuildsListService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| using Discord.WebSocket; | ||||
| using System.Collections.Generic; | ||||
| using System.Collections.Immutable; | ||||
| using System.Linq; | ||||
| using System.Collections; | ||||
|  | ||||
| namespace NadekoBot.Services.Impl | ||||
| { | ||||
|     public class StartingGuildsService : IEnumerable<long>, INService | ||||
|     { | ||||
|         private readonly ImmutableList<long> _guilds; | ||||
|  | ||||
|         public StartingGuildsService(DiscordSocketClient client) | ||||
|         { | ||||
|             this._guilds = client.Guilds.Select(x => (long)x.Id).ToImmutableList(); | ||||
|         } | ||||
|  | ||||
|         public IEnumerator<long> GetEnumerator() => | ||||
|             _guilds.GetEnumerator(); | ||||
|  | ||||
|         IEnumerator IEnumerable.GetEnumerator() => | ||||
|             _guilds.GetEnumerator(); | ||||
|     } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user