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