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