Killed history

This commit is contained in:
Kwoth
2021-09-06 21:29:22 +02:00
commit 7aca29ae8a
950 changed files with 366651 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace NadekoBot.Common
{
public class AsyncLazy<T> : Lazy<Task<T>>
{
public AsyncLazy(Func<T> valueFactory) :
base(() => Task.Run(valueFactory))
{ }
public AsyncLazy(Func<Task<T>> taskFactory) :
base(() => Task.Run(taskFactory))
{ }
public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); }
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using Discord.Commands;
using NadekoBot.Core.Services.Impl;
namespace NadekoBot.Common.Attributes
{
[AttributeUsage(AttributeTargets.Method)]
public sealed class AliasesAttribute : AliasAttribute
{
public AliasesAttribute([CallerMemberName] string memberName = "")
: base(CommandNameLoadHelper.GetAliasesFor(memberName))
{
}
}
}

View File

@@ -0,0 +1,15 @@
using Discord.Commands;
namespace Discord
{
public class BotPermAttribute : RequireBotPermissionAttribute
{
public BotPermAttribute(GuildPerm permission) : base((GuildPermission)permission)
{
}
public BotPermAttribute(ChannelPerm permission) : base((ChannelPermission)permission)
{
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace NadekoBot.Common.Attributes
{
public static class CommandNameLoadHelper
{
private static YamlDotNet.Serialization.IDeserializer _deserializer
= new YamlDotNet.Serialization.Deserializer();
public static Lazy<Dictionary<string, string[]>> LazyCommandAliases
= new Lazy<Dictionary<string, string[]>>(() => LoadCommandNames());
public static Dictionary<string, string[]> LoadCommandNames(string aliasesFilePath = "data/aliases.yml")
{
var text = File.ReadAllText(aliasesFilePath);
return _deserializer.Deserialize<Dictionary<string, string[]>>(text);
}
public static string[] GetAliasesFor(string methodName)
=> LazyCommandAliases.Value.TryGetValue(methodName.ToLowerInvariant(), out var aliases) && aliases.Length > 1
? aliases.Skip(1).ToArray()
: Array.Empty<string>();
public static string GetCommandNameFor(string methodName)
{
methodName = methodName.ToLowerInvariant();
var toReturn = LazyCommandAliases.Value.TryGetValue(methodName, out var aliases) && aliases.Length > 0
? aliases[0]
: methodName;
return toReturn;
}
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Runtime.CompilerServices;
using Discord.Commands;
using NadekoBot.Core.Services.Impl;
namespace NadekoBot.Common.Attributes
{
[AttributeUsage(AttributeTargets.Method)]
public sealed class DescriptionAttribute : SummaryAttribute
{
// Localization.LoadCommand(memberName.ToLowerInvariant()).Desc
public DescriptionAttribute(string text = "") : base(text)
{
}
}
}

View File

@@ -0,0 +1,9 @@
namespace Discord.Commands
{
public class LeftoverAttribute : RemainderAttribute
{
public LeftoverAttribute()
{
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Runtime.CompilerServices;
using Discord.Commands;
using NadekoBot.Core.Services.Impl;
namespace NadekoBot.Common.Attributes
{
[AttributeUsage(AttributeTargets.Method)]
public sealed class NadekoCommandAttribute : CommandAttribute
{
public NadekoCommandAttribute([CallerMemberName] string memberName="")
: base(CommandNameLoadHelper.GetCommandNameFor(memberName))
{
this.MethodName = memberName.ToLowerInvariant();
}
public string MethodName { get; }
}
}

View File

@@ -0,0 +1,14 @@
using System;
using Discord.Commands;
namespace NadekoBot.Common.Attributes
{
[AttributeUsage(AttributeTargets.Class)]
sealed class NadekoModuleAttribute : GroupAttribute
{
public NadekoModuleAttribute(string moduleName) : base(moduleName)
{
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
namespace NadekoBot.Common.Attributes
{
[AttributeUsage(AttributeTargets.Method)]
public sealed class NadekoOptionsAttribute : Attribute
{
public Type OptionType { get; set; }
public NadekoOptionsAttribute(Type t)
{
this.OptionType = t;
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Threading.Tasks;
using Discord.Commands;
using NadekoBot.Core.Services;
using Microsoft.Extensions.DependencyInjection;
namespace NadekoBot.Common.Attributes
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public sealed class OwnerOnlyAttribute : PreconditionAttribute
{
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo executingCommand, IServiceProvider services)
{
var creds = services.GetService<IBotCredentials>();
return Task.FromResult((creds.IsOwner(context.User) || context.Client.CurrentUser.Id == context.User.Id ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner")));
}
}
}

View File

@@ -0,0 +1,38 @@
using Discord.Commands;
using NadekoBot.Core.Services;
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
namespace NadekoBot.Core.Common.Attributes
{
[AttributeUsage(AttributeTargets.Method)]
public sealed class RatelimitAttribute : PreconditionAttribute
{
public int Seconds { get; }
public RatelimitAttribute(int seconds)
{
if (seconds <= 0)
throw new ArgumentOutOfRangeException(nameof(seconds));
Seconds = seconds;
}
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
{
if (Seconds == 0)
return Task.FromResult(PreconditionResult.FromSuccess());
var cache = services.GetService<IDataCache>();
var rem = cache.TryAddRatelimit(context.User.Id, command.Name, Seconds);
if(rem == null)
return Task.FromResult(PreconditionResult.FromSuccess());
var msgContent = $"You can use this command again in {rem.Value.TotalSeconds:F1}s.";
return Task.FromResult(PreconditionResult.FromError(msgContent));
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Runtime.CompilerServices;
using Discord.Commands;
using NadekoBot.Core.Services.Impl;
using Newtonsoft.Json;
namespace NadekoBot.Common.Attributes
{
[AttributeUsage(AttributeTargets.Method)]
public sealed class UsageAttribute : RemarksAttribute
{
// public static string GetUsage(string memberName)
// {
// var usage = Localization.LoadCommand(memberName.ToLowerInvariant()).Usage;
// return JsonConvert.SerializeObject(usage);
// }
public UsageAttribute(string text = "") : base(text)
{
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Threading.Tasks;
using Discord.Commands;
using Microsoft.Extensions.DependencyInjection;
using NadekoBot.Modules.Administration.Services;
namespace Discord
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class UserPermAttribute : PreconditionAttribute
{
public RequireUserPermissionAttribute UserPermissionAttribute { get; }
public UserPermAttribute(GuildPerm permission)
{
UserPermissionAttribute = new RequireUserPermissionAttribute((GuildPermission)permission);
}
public UserPermAttribute(ChannelPerm permission)
{
UserPermissionAttribute = new RequireUserPermissionAttribute((ChannelPermission)permission);
}
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
{
var permService = services.GetService<DiscordPermOverrideService>();
if (permService.TryGetOverrides(context.Guild?.Id ?? 0, command.Name.ToUpperInvariant(), out var _))
return Task.FromResult(PreconditionResult.FromSuccess());
return UserPermissionAttribute.CheckPermissionsAsync(context, command, services);
}
}
}

View File

@@ -0,0 +1,26 @@
namespace NadekoBot.Common
{
public enum BotConfigEditType
{
/// <summary>
/// The amount of currency awarded to the winner of the trivia game.
/// Default is 0.
/// </summary>
TriviaCurrencyReward,
/// <summary>
/// Users can't start trivia games which have smaller win requirement than specified by this setting.
/// Default is 0.
/// </summary>
MinimumTriviaWinReq,
/// <summary>
/// The amount of XP the user receives when they send a message (which is not too short).
/// Default is 3.
/// </summary>
XpPerMessage,
/// <summary>
/// This value represents how often the user can receive XP from sending messages.
/// Default is 5.
/// </summary>
XpMinutesTimeout,
}
}

View File

@@ -0,0 +1,126 @@
using Discord;
using NadekoBot.Extensions;
using Newtonsoft.Json;
using System;
namespace NadekoBot.Common
{
public class CREmbed
{
public CREmbedAuthor Author { get; set; }
public string PlainText { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Url { get; set; }
public CREmbedFooter Footer { get; set; }
public string Thumbnail { get; set; }
public string Image { get; set; }
public CREmbedField[] Fields { get; set; }
public uint Color { get; set; } = 7458112;
public bool IsValid =>
IsEmbedValid || !string.IsNullOrWhiteSpace(PlainText);
public bool IsEmbedValid =>
!string.IsNullOrWhiteSpace(Title) ||
!string.IsNullOrWhiteSpace(Description) ||
!string.IsNullOrWhiteSpace(Url) ||
!string.IsNullOrWhiteSpace(Thumbnail) ||
!string.IsNullOrWhiteSpace(Image) ||
(Footer != null && (!string.IsNullOrWhiteSpace(Footer.Text) || !string.IsNullOrWhiteSpace(Footer.IconUrl))) ||
(Fields != null && Fields.Length > 0);
public EmbedBuilder ToEmbed()
{
var embed = new EmbedBuilder();
if (!string.IsNullOrWhiteSpace(Title))
embed.WithTitle(Title);
if (!string.IsNullOrWhiteSpace(Description))
embed.WithDescription(Description);
if (Url != null && Uri.IsWellFormedUriString(Url, UriKind.Absolute))
embed.WithUrl(Url);
embed.WithColor(new Discord.Color(Color));
if (Footer != null)
embed.WithFooter(efb =>
{
efb.WithText(Footer.Text);
if (Uri.IsWellFormedUriString(Footer.IconUrl, UriKind.Absolute))
efb.WithIconUrl(Footer.IconUrl);
});
if (Thumbnail != null && Uri.IsWellFormedUriString(Thumbnail, UriKind.Absolute))
embed.WithThumbnailUrl(Thumbnail);
if (Image != null && Uri.IsWellFormedUriString(Image, UriKind.Absolute))
embed.WithImageUrl(Image);
if (Author != null && !string.IsNullOrWhiteSpace(Author.Name))
{
if (!Uri.IsWellFormedUriString(Author.IconUrl, UriKind.Absolute))
Author.IconUrl = null;
if (!Uri.IsWellFormedUriString(Author.Url, UriKind.Absolute))
Author.Url = null;
embed.WithAuthor(Author.Name, Author.IconUrl, Author.Url);
}
if (Fields != null)
foreach (var f in Fields)
{
if (!string.IsNullOrWhiteSpace(f.Name) && !string.IsNullOrWhiteSpace(f.Value))
embed.AddField(efb => efb.WithName(f.Name).WithValue(f.Value).WithIsInline(f.Inline));
}
return embed;
}
public static bool TryParse(string input, out CREmbed embed)
{
embed = null;
if (string.IsNullOrWhiteSpace(input) || !input.Trim().StartsWith('{'))
return false;
try
{
var crembed = JsonConvert.DeserializeObject<CREmbed>(input);
if (crembed.Fields != null && crembed.Fields.Length > 0)
foreach (var f in crembed.Fields)
{
f.Name = f.Name.TrimTo(256);
f.Value = f.Value.TrimTo(1024);
}
if (!crembed.IsValid)
return false;
embed = crembed;
return true;
}
catch
{
return false;
}
}
}
public class CREmbedField
{
public string Name { get; set; }
public string Value { get; set; }
public bool Inline { get; set; }
}
public class CREmbedFooter
{
public string Text { get; set; }
public string IconUrl { get; set; }
[JsonProperty("icon_url")]
private string Icon_Url { set => IconUrl = value; }
}
public class CREmbedAuthor
{
public string Name { get; set; }
public string IconUrl { get; set; }
[JsonProperty("icon_url")]
private string Icon_Url { set => IconUrl = value; }
public string Url { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
using Newtonsoft.Json;
namespace NadekoBot.Core.Common
{
public class CmdStrings
{
public string[] Usages { get; }
public string Description { get; }
[JsonConstructor]
public CmdStrings(
[JsonProperty("args")]string[] usages,
[JsonProperty("desc")]string description
)
{
Usages = usages;
Description = description;
}
}
}

View File

@@ -0,0 +1,772 @@
// License MIT
// Source: https://github.com/i3arnon/ConcurrentHashSet
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace NadekoBot.Common.Collections
{
/// <summary>
/// Represents a thread-safe hash-based unique collection.
/// </summary>
/// <typeparam name="T">The type of the items in the collection.</typeparam>
/// <remarks>
/// All public members of <see cref="ConcurrentHashSet{T}"/> are thread-safe and may be used
/// concurrently from multiple threads.
/// </remarks>
[DebuggerDisplay("Count = {Count}")]
public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T>
{
private const int DefaultCapacity = 31;
private const int MaxLockNumber = 1024;
private readonly IEqualityComparer<T> _comparer;
private readonly bool _growLockArray;
private int _budget;
private volatile Tables _tables;
private static int DefaultConcurrencyLevel => PlatformHelper.ProcessorCount;
/// <summary>
/// Gets the number of items contained in the <see
/// cref="ConcurrentHashSet{T}"/>.
/// </summary>
/// <value>The number of items contained in the <see
/// cref="ConcurrentHashSet{T}"/>.</value>
/// <remarks>Count has snapshot semantics and represents the number of items in the <see
/// cref="ConcurrentHashSet{T}"/>
/// at the moment when Count was accessed.</remarks>
public int Count
{
get
{
var count = 0;
var acquiredLocks = 0;
try
{
AcquireAllLocks(ref acquiredLocks);
for (var i = 0; i < _tables.CountPerLock.Length; i++)
{
count += _tables.CountPerLock[i];
}
}
finally
{
ReleaseLocks(0, acquiredLocks);
}
return count;
}
}
/// <summary>
/// Gets a value that indicates whether the <see cref="ConcurrentHashSet{T}"/> is empty.
/// </summary>
/// <value>true if the <see cref="ConcurrentHashSet{T}"/> is empty; otherwise,
/// false.</value>
public bool IsEmpty
{
get
{
var acquiredLocks = 0;
try
{
AcquireAllLocks(ref acquiredLocks);
for (var i = 0; i < _tables.CountPerLock.Length; i++)
{
if (_tables.CountPerLock[i] != 0)
{
return false;
}
}
}
finally
{
ReleaseLocks(0, acquiredLocks);
}
return true;
}
}
/// <summary>
/// Initializes a new instance of the <see
/// cref="ConcurrentHashSet{T}"/>
/// class that is empty, has the default concurrency level, has the default initial capacity, and
/// uses the default comparer for the item type.
/// </summary>
public ConcurrentHashSet()
: this(DefaultConcurrencyLevel, DefaultCapacity, true, EqualityComparer<T>.Default)
{
}
/// <summary>
/// Initializes a new instance of the <see
/// cref="ConcurrentHashSet{T}"/>
/// class that is empty, has the specified concurrency level and capacity, and uses the default
/// comparer for the item type.
/// </summary>
/// <param name="concurrencyLevel">The estimated number of threads that will update the
/// <see cref="ConcurrentHashSet{T}"/> concurrently.</param>
/// <param name="capacity">The initial number of elements that the <see
/// cref="ConcurrentHashSet{T}"/>
/// can contain.</param>
/// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="concurrencyLevel"/> is
/// less than 1.</exception>
/// <exception cref="T:System.ArgumentOutOfRangeException"> <paramref name="capacity"/> is less than
/// 0.</exception>
public ConcurrentHashSet(int concurrencyLevel, int capacity)
: this(concurrencyLevel, capacity, false, EqualityComparer<T>.Default)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ConcurrentHashSet{T}"/>
/// class that contains elements copied from the specified <see
/// cref="T:System.Collections.IEnumerable{T}"/>, has the default concurrency
/// level, has the default initial capacity, and uses the default comparer for the item type.
/// </summary>
/// <param name="collection">The <see
/// cref="T:System.Collections.IEnumerable{T}"/> whose elements are copied to
/// the new
/// <see cref="ConcurrentHashSet{T}"/>.</param>
/// <exception cref="T:System.ArgumentNullException"><paramref name="collection"/> is a null reference.</exception>
public ConcurrentHashSet(IEnumerable<T> collection)
: this(collection, EqualityComparer<T>.Default)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ConcurrentHashSet{T}"/>
/// class that is empty, has the specified concurrency level and capacity, and uses the specified
/// <see cref="T:System.Collections.Generic.IEqualityComparer{T}"/>.
/// </summary>
/// <param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer{T}"/>
/// implementation to use when comparing items.</param>
/// <exception cref="T:System.ArgumentNullException"><paramref name="comparer"/> is a null reference.</exception>
public ConcurrentHashSet(IEqualityComparer<T> comparer)
: this(DefaultConcurrencyLevel, DefaultCapacity, true, comparer)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ConcurrentHashSet{T}"/>
/// class that contains elements copied from the specified <see
/// cref="T:System.Collections.IEnumerable"/>, has the default concurrency level, has the default
/// initial capacity, and uses the specified
/// <see cref="T:System.Collections.Generic.IEqualityComparer{T}"/>.
/// </summary>
/// <param name="collection">The <see
/// cref="T:System.Collections.IEnumerable{T}"/> whose elements are copied to
/// the new
/// <see cref="ConcurrentHashSet{T}"/>.</param>
/// <param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer{T}"/>
/// implementation to use when comparing items.</param>
/// <exception cref="T:System.ArgumentNullException"><paramref name="collection"/> is a null reference
/// (Nothing in Visual Basic). -or-
/// <paramref name="comparer"/> is a null reference (Nothing in Visual Basic).
/// </exception>
public ConcurrentHashSet(IEnumerable<T> collection, IEqualityComparer<T> comparer)
: this(comparer)
{
if (collection == null) throw new ArgumentNullException(nameof(collection));
InitializeFromCollection(collection);
}
/// <summary>
/// Initializes a new instance of the <see cref="ConcurrentHashSet{T}"/>
/// class that contains elements copied from the specified <see cref="T:System.Collections.IEnumerable"/>,
/// has the specified concurrency level, has the specified initial capacity, and uses the specified
/// <see cref="T:System.Collections.Generic.IEqualityComparer{T}"/>.
/// </summary>
/// <param name="concurrencyLevel">The estimated number of threads that will update the
/// <see cref="ConcurrentHashSet{T}"/> concurrently.</param>
/// <param name="collection">The <see cref="T:System.Collections.IEnumerable{T}"/> whose elements are copied to the new
/// <see cref="ConcurrentHashSet{T}"/>.</param>
/// <param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer{T}"/> implementation to use
/// when comparing items.</param>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="collection"/> is a null reference.
/// -or-
/// <paramref name="comparer"/> is a null reference.
/// </exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">
/// <paramref name="concurrencyLevel"/> is less than 1.
/// </exception>
public ConcurrentHashSet(int concurrencyLevel, IEnumerable<T> collection, IEqualityComparer<T> comparer)
: this(concurrencyLevel, DefaultCapacity, false, comparer)
{
if (collection == null) throw new ArgumentNullException(nameof(collection));
if (comparer == null) throw new ArgumentNullException(nameof(comparer));
InitializeFromCollection(collection);
}
/// <summary>
/// Initializes a new instance of the <see cref="ConcurrentHashSet{T}"/>
/// class that is empty, has the specified concurrency level, has the specified initial capacity, and
/// uses the specified <see cref="T:System.Collections.Generic.IEqualityComparer{T}"/>.
/// </summary>
/// <param name="concurrencyLevel">The estimated number of threads that will update the
/// <see cref="ConcurrentHashSet{T}"/> concurrently.</param>
/// <param name="capacity">The initial number of elements that the <see
/// cref="ConcurrentHashSet{T}"/>
/// can contain.</param>
/// <param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer{T}"/>
/// implementation to use when comparing items.</param>
/// <exception cref="T:System.ArgumentOutOfRangeException">
/// <paramref name="concurrencyLevel"/> is less than 1. -or-
/// <paramref name="capacity"/> is less than 0.
/// </exception>
/// <exception cref="T:System.ArgumentNullException"><paramref name="comparer"/> is a null reference.</exception>
public ConcurrentHashSet(int concurrencyLevel, int capacity, IEqualityComparer<T> comparer)
: this(concurrencyLevel, capacity, false, comparer)
{
}
private ConcurrentHashSet(int concurrencyLevel, int capacity, bool growLockArray, IEqualityComparer<T> comparer)
{
if (concurrencyLevel < 1) throw new ArgumentOutOfRangeException(nameof(concurrencyLevel));
if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity));
// The capacity should be at least as large as the concurrency level. Otherwise, we would have locks that don't guard
// any buckets.
if (capacity < concurrencyLevel)
{
capacity = concurrencyLevel;
}
var locks = new object[concurrencyLevel];
for (var i = 0; i < locks.Length; i++)
{
locks[i] = new object();
}
var countPerLock = new int[locks.Length];
var buckets = new Node[capacity];
_tables = new Tables(buckets, locks, countPerLock);
_growLockArray = growLockArray;
_budget = buckets.Length / locks.Length;
_comparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
}
/// <summary>
/// Adds the specified item to the <see cref="ConcurrentHashSet{T}"/>.
/// </summary>
/// <param name="item">The item to add.</param>
/// <returns>true if the items was added to the <see cref="ConcurrentHashSet{T}"/>
/// successfully; false if it already exists.</returns>
/// <exception cref="T:System.OverflowException">The <see cref="ConcurrentHashSet{T}"/>
/// contains too many items.</exception>
public bool Add(T item) =>
AddInternal(item, _comparer.GetHashCode(item), true);
/// <summary>
/// Removes all items from the <see cref="ConcurrentHashSet{T}"/>.
/// </summary>
public void Clear()
{
var locksAcquired = 0;
try
{
AcquireAllLocks(ref locksAcquired);
var newTables = new Tables(new Node[DefaultCapacity], _tables.Locks, new int[_tables.CountPerLock.Length]);
_tables = newTables;
_budget = Math.Max(1, newTables.Buckets.Length / newTables.Locks.Length);
}
finally
{
ReleaseLocks(0, locksAcquired);
}
}
/// <summary>
/// Determines whether the <see cref="ConcurrentHashSet{T}"/> contains the specified
/// item.
/// </summary>
/// <param name="item">The item to locate in the <see cref="ConcurrentHashSet{T}"/>.</param>
/// <returns>true if the <see cref="ConcurrentHashSet{T}"/> contains the item; otherwise, false.</returns>
public bool Contains(T item)
{
var hashcode = _comparer.GetHashCode(item);
// We must capture the _buckets field in a local variable. It is set to a new table on each table resize.
var tables = _tables;
var bucketNo = GetBucket(hashcode, tables.Buckets.Length);
// We can get away w/out a lock here.
// The Volatile.Read ensures that the load of the fields of 'n' doesn't move before the load from buckets[i].
var current = Volatile.Read(ref tables.Buckets[bucketNo]);
while (current != null)
{
if (hashcode == current.Hashcode && _comparer.Equals(current.Item, item))
{
return true;
}
current = current.Next;
}
return false;
}
/// <summary>
/// Attempts to remove the item from the <see cref="ConcurrentHashSet{T}"/>.
/// </summary>
/// <param name="item">The item to remove.</param>
/// <returns>true if an item was removed successfully; otherwise, false.</returns>
public bool TryRemove(T item)
{
var hashcode = _comparer.GetHashCode(item);
while (true)
{
var tables = _tables;
GetBucketAndLockNo(hashcode, out var bucketNo, out var lockNo, tables.Buckets.Length, tables.Locks.Length);
lock (tables.Locks[lockNo])
{
// If the table just got resized, we may not be holding the right lock, and must retry.
// This should be a rare occurrence.
if (tables != _tables)
{
continue;
}
Node previous = null;
for (var current = tables.Buckets[bucketNo]; current != null; current = current.Next)
{
Debug.Assert((previous == null && current == tables.Buckets[bucketNo]) || previous.Next == current);
if (hashcode == current.Hashcode && _comparer.Equals(current.Item, item))
{
if (previous == null)
{
Volatile.Write(ref tables.Buckets[bucketNo], current.Next);
}
else
{
previous.Next = current.Next;
}
tables.CountPerLock[lockNo]--;
return true;
}
previous = current;
}
}
return false;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
/// <summary>Returns an enumerator that iterates through the <see
/// cref="ConcurrentHashSet{T}"/>.</summary>
/// <returns>An enumerator for the <see cref="ConcurrentHashSet{T}"/>.</returns>
/// <remarks>
/// The enumerator returned from the collection is safe to use concurrently with
/// reads and writes to the collection, however it does not represent a moment-in-time snapshot
/// of the collection. The contents exposed through the enumerator may contain modifications
/// made to the collection after <see cref="GetEnumerator"/> was called.
/// </remarks>
public IEnumerator<T> GetEnumerator()
{
var buckets = _tables.Buckets;
for (var i = 0; i < buckets.Length; i++)
{
// The Volatile.Read ensures that the load of the fields of 'current' doesn't move before the load from buckets[i].
var current = Volatile.Read(ref buckets[i]);
while (current != null)
{
yield return current.Item;
current = current.Next;
}
}
}
void ICollection<T>.Add(T item) => Add(item);
bool ICollection<T>.IsReadOnly => false;
void ICollection<T>.CopyTo(T[] array, int arrayIndex)
{
if (array == null) throw new ArgumentNullException(nameof(array));
if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex));
var locksAcquired = 0;
try
{
AcquireAllLocks(ref locksAcquired);
var count = 0;
for (var i = 0; i < _tables.Locks.Length && count >= 0; i++)
{
count += _tables.CountPerLock[i];
}
if (array.Length - count < arrayIndex || count < 0) //"count" itself or "count + arrayIndex" can overflow
{
throw new ArgumentException("The index is equal to or greater than the length of the array, or the number of elements in the set is greater than the available space from index to the end of the destination array.");
}
CopyToItems(array, arrayIndex);
}
finally
{
ReleaseLocks(0, locksAcquired);
}
}
bool ICollection<T>.Remove(T item) => TryRemove(item);
private void InitializeFromCollection(IEnumerable<T> collection)
{
foreach (var item in collection)
{
AddInternal(item, _comparer.GetHashCode(item), false);
}
if (_budget == 0)
{
_budget = _tables.Buckets.Length / _tables.Locks.Length;
}
}
private bool AddInternal(T item, int hashcode, bool acquireLock)
{
while (true)
{
var tables = _tables;
GetBucketAndLockNo(hashcode, out var bucketNo, out var lockNo, tables.Buckets.Length, tables.Locks.Length);
var resizeDesired = false;
var lockTaken = false;
try
{
if (acquireLock)
Monitor.Enter(tables.Locks[lockNo], ref lockTaken);
// If the table just got resized, we may not be holding the right lock, and must retry.
// This should be a rare occurrence.
if (tables != _tables)
{
continue;
}
// Try to find this item in the bucket
Node previous = null;
for (var current = tables.Buckets[bucketNo]; current != null; current = current.Next)
{
Debug.Assert((previous == null && current == tables.Buckets[bucketNo]) || previous.Next == current);
if (hashcode == current.Hashcode && _comparer.Equals(current.Item, item))
{
return false;
}
previous = current;
}
// The item was not found in the bucket. Insert the new item.
Volatile.Write(ref tables.Buckets[bucketNo], new Node(item, hashcode, tables.Buckets[bucketNo]));
checked
{
tables.CountPerLock[lockNo]++;
}
//
// If the number of elements guarded by this lock has exceeded the budget, resize the bucket table.
// It is also possible that GrowTable will increase the budget but won't resize the bucket table.
// That happens if the bucket table is found to be poorly utilized due to a bad hash function.
//
if (tables.CountPerLock[lockNo] > _budget)
{
resizeDesired = true;
}
}
finally
{
if (lockTaken)
Monitor.Exit(tables.Locks[lockNo]);
}
//
// The fact that we got here means that we just performed an insertion. If necessary, we will grow the table.
//
// Concurrency notes:
// - Notice that we are not holding any locks at when calling GrowTable. This is necessary to prevent deadlocks.
// - As a result, it is possible that GrowTable will be called unnecessarily. But, GrowTable will obtain lock 0
// and then verify that the table we passed to it as the argument is still the current table.
//
if (resizeDesired)
{
GrowTable(tables);
}
return true;
}
}
private static int GetBucket(int hashcode, int bucketCount)
{
var bucketNo = (hashcode & 0x7fffffff) % bucketCount;
Debug.Assert(bucketNo >= 0 && bucketNo < bucketCount);
return bucketNo;
}
private static void GetBucketAndLockNo(int hashcode, out int bucketNo, out int lockNo, int bucketCount, int lockCount)
{
bucketNo = (hashcode & 0x7fffffff) % bucketCount;
lockNo = bucketNo % lockCount;
Debug.Assert(bucketNo >= 0 && bucketNo < bucketCount);
Debug.Assert(lockNo >= 0 && lockNo < lockCount);
}
private void GrowTable(Tables tables)
{
const int maxArrayLength = 0X7FEFFFFF;
var locksAcquired = 0;
try
{
// The thread that first obtains _locks[0] will be the one doing the resize operation
AcquireLocks(0, 1, ref locksAcquired);
// Make sure nobody resized the table while we were waiting for lock 0:
if (tables != _tables)
{
// We assume that since the table reference is different, it was already resized (or the budget
// was adjusted). If we ever decide to do table shrinking, or replace the table for other reasons,
// we will have to revisit this logic.
return;
}
// Compute the (approx.) total size. Use an Int64 accumulation variable to avoid an overflow.
long approxCount = 0;
for (var i = 0; i < tables.CountPerLock.Length; i++)
{
approxCount += tables.CountPerLock[i];
}
//
// If the bucket array is too empty, double the budget instead of resizing the table
//
if (approxCount < tables.Buckets.Length / 4)
{
_budget = 2 * _budget;
if (_budget < 0)
{
_budget = int.MaxValue;
}
return;
}
// Compute the new table size. We find the smallest integer larger than twice the previous table size, and not divisible by
// 2,3,5 or 7. We can consider a different table-sizing policy in the future.
var newLength = 0;
var maximizeTableSize = false;
try
{
checked
{
// Double the size of the buckets table and add one, so that we have an odd integer.
newLength = tables.Buckets.Length * 2 + 1;
// Now, we only need to check odd integers, and find the first that is not divisible
// by 3, 5 or 7.
while (newLength % 3 == 0 || newLength % 5 == 0 || newLength % 7 == 0)
{
newLength += 2;
}
Debug.Assert(newLength % 2 != 0);
if (newLength > maxArrayLength)
{
maximizeTableSize = true;
}
}
}
catch (OverflowException)
{
maximizeTableSize = true;
}
if (maximizeTableSize)
{
newLength = maxArrayLength;
// We want to make sure that GrowTable will not be called again, since table is at the maximum size.
// To achieve that, we set the budget to int.MaxValue.
//
// (There is one special case that would allow GrowTable() to be called in the future:
// calling Clear() on the ConcurrentHashSet will shrink the table and lower the budget.)
_budget = int.MaxValue;
}
// Now acquire all other locks for the table
AcquireLocks(1, tables.Locks.Length, ref locksAcquired);
var newLocks = tables.Locks;
// Add more locks
if (_growLockArray && tables.Locks.Length < MaxLockNumber)
{
newLocks = new object[tables.Locks.Length * 2];
Array.Copy(tables.Locks, 0, newLocks, 0, tables.Locks.Length);
for (var i = tables.Locks.Length; i < newLocks.Length; i++)
{
newLocks[i] = new object();
}
}
var newBuckets = new Node[newLength];
var newCountPerLock = new int[newLocks.Length];
// Copy all data into a new table, creating new nodes for all elements
for (var i = 0; i < tables.Buckets.Length; i++)
{
var current = tables.Buckets[i];
while (current != null)
{
var next = current.Next;
GetBucketAndLockNo(current.Hashcode, out var newBucketNo, out var newLockNo, newBuckets.Length, newLocks.Length);
newBuckets[newBucketNo] = new Node(current.Item, current.Hashcode, newBuckets[newBucketNo]);
checked
{
newCountPerLock[newLockNo]++;
}
current = next;
}
}
// Adjust the budget
_budget = Math.Max(1, newBuckets.Length / newLocks.Length);
// Replace tables with the new versions
_tables = new Tables(newBuckets, newLocks, newCountPerLock);
}
finally
{
// Release all locks that we took earlier
ReleaseLocks(0, locksAcquired);
}
}
public int RemoveWhere(Func<T, bool> predicate)
{
var elems = this.Where(predicate);
var removed = 0;
foreach (var elem in elems)
{
if (this.TryRemove(elem))
removed++;
}
return removed;
}
private void AcquireAllLocks(ref int locksAcquired)
{
// First, acquire lock 0
AcquireLocks(0, 1, ref locksAcquired);
// Now that we have lock 0, the _locks array will not change (i.e., grow),
// and so we can safely read _locks.Length.
AcquireLocks(1, _tables.Locks.Length, ref locksAcquired);
Debug.Assert(locksAcquired == _tables.Locks.Length);
}
private void AcquireLocks(int fromInclusive, int toExclusive, ref int locksAcquired)
{
Debug.Assert(fromInclusive <= toExclusive);
var locks = _tables.Locks;
for (var i = fromInclusive; i < toExclusive; i++)
{
var lockTaken = false;
try
{
Monitor.Enter(locks[i], ref lockTaken);
}
finally
{
if (lockTaken)
{
locksAcquired++;
}
}
}
}
private void ReleaseLocks(int fromInclusive, int toExclusive)
{
Debug.Assert(fromInclusive <= toExclusive);
for (var i = fromInclusive; i < toExclusive; i++)
{
Monitor.Exit(_tables.Locks[i]);
}
}
private void CopyToItems(T[] array, int index)
{
var buckets = _tables.Buckets;
for (var i = 0; i < buckets.Length; i++)
{
for (var current = buckets[i]; current != null; current = current.Next)
{
array[index] = current.Item;
index++; //this should never flow, CopyToItems is only called when there's no overflow risk
}
}
}
private sealed class Tables
{
public readonly Node[] Buckets;
public readonly object[] Locks;
public volatile int[] CountPerLock;
public Tables(Node[] buckets, object[] locks, int[] countPerLock)
{
Buckets = buckets;
Locks = locks;
CountPerLock = countPerLock;
}
}
private sealed class Node
{
public readonly T Item;
public readonly int Hashcode;
public volatile Node Next;
public Node(T item, int hashcode, Node next)
{
Item = item;
Hashcode = hashcode;
Next = next;
}
}
}
}

View File

@@ -0,0 +1,77 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace NadekoBot.Common.Collections
{
public static class DisposableReadOnlyListExtensions
{
public static IDisposableReadOnlyList<T> AsDisposable<T>(this IReadOnlyList<T> arr) where T : IDisposable
=> new DisposableReadOnlyList<T>(arr);
public static IDisposableReadOnlyList<KeyValuePair<TKey, TValue>> AsDisposable<TKey, TValue>(this IReadOnlyList<KeyValuePair<TKey, TValue>> arr) where TValue : IDisposable
=> new DisposableReadOnlyList<TKey, TValue>(arr);
}
public interface IDisposableReadOnlyList<T> : IReadOnlyList<T>, IDisposable
{
}
public sealed class DisposableReadOnlyList<T> : IDisposableReadOnlyList<T>
where T : IDisposable
{
private readonly IReadOnlyList<T> _arr;
public int Count => _arr.Count;
public T this[int index] => _arr[index];
public DisposableReadOnlyList(IReadOnlyList<T> arr)
{
this._arr = arr;
}
public IEnumerator<T> GetEnumerator()
=> _arr.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
=> _arr.GetEnumerator();
public void Dispose()
{
foreach (var item in _arr)
{
item.Dispose();
}
}
}
public sealed class DisposableReadOnlyList<T, U> : IDisposableReadOnlyList<KeyValuePair<T, U>>
where U : IDisposable
{
private readonly IReadOnlyList<KeyValuePair<T, U>> _arr;
public int Count => _arr.Count;
KeyValuePair<T, U> IReadOnlyList<KeyValuePair<T, U>>.this[int index] => _arr[index];
public DisposableReadOnlyList(IReadOnlyList<KeyValuePair<T, U>> arr)
{
this._arr = arr;
}
public IEnumerator<KeyValuePair<T, U>> GetEnumerator() =>
_arr.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() =>
_arr.GetEnumerator();
public void Dispose()
{
foreach (var item in _arr)
{
item.Value.Dispose();
}
}
}
}

View File

@@ -0,0 +1,141 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NadekoBot.Core.Services.Database.Models;
namespace NadekoBot.Common.Collections
{
public class IndexedCollection<T> : IList<T> where T : class, IIndexed
{
public List<T> Source { get; }
private readonly object _locker = new object();
public int Count => Source.Count;
public bool IsReadOnly => false;
public int IndexOf(T item) => item.Index;
public IndexedCollection()
{
Source = new List<T>();
}
public IndexedCollection(IEnumerable<T> source)
{
lock (_locker)
{
Source = source.OrderBy(x => x.Index).ToList();
UpdateIndexes();
}
}
public void UpdateIndexes()
{
lock (_locker)
{
for (var i = 0; i < Source.Count; i++)
{
if (Source[i].Index != i)
Source[i].Index = i;
}
}
}
public static implicit operator List<T>(IndexedCollection<T> x) =>
x.Source;
public List<T> ToList() => Source.ToList();
public IEnumerator<T> GetEnumerator() =>
Source.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() =>
Source.GetEnumerator();
public void Add(T item)
{
lock (_locker)
{
item.Index = Source.Count;
Source.Add(item);
}
}
public virtual void Clear()
{
lock (_locker)
{
Source.Clear();
}
}
public bool Contains(T item)
{
lock (_locker)
{
return Source.Contains(item);
}
}
public void CopyTo(T[] array, int arrayIndex)
{
lock (_locker)
{
Source.CopyTo(array, arrayIndex);
}
}
public virtual bool Remove(T item)
{
bool removed;
lock (_locker)
{
if (removed = Source.Remove(item))
{
for (int i = 0; i < Source.Count; i++)
{
if (Source[i].Index != i)
Source[i].Index = i;
}
}
}
return removed;
}
public virtual void Insert(int index, T item)
{
lock (_locker)
{
Source.Insert(index, item);
for (int i = index; i < Source.Count; i++)
{
Source[i].Index = i;
}
}
}
public virtual void RemoveAt(int index)
{
lock (_locker)
{
Source.RemoveAt(index);
for (int i = index; i < Source.Count; i++)
{
Source[i].Index = i;
}
}
}
public virtual T this[int index]
{
get { return Source[index]; }
set
{
lock (_locker)
{
value.Index = index;
Source[index] = value;
}
}
}
}
}

View File

@@ -0,0 +1,9 @@
namespace NadekoBot.Common
{
public class CommandData
{
public string Cmd { get; set; }
public string Desc { get; set; }
public string[] Usage { get; set; }
}
}

View File

@@ -0,0 +1,166 @@
using System.Collections.Generic;
using System.Globalization;
using NadekoBot.Common.Yml;
using SixLabors.ImageSharp.PixelFormats;
using YamlDotNet.Core;
using YamlDotNet.Serialization;
namespace NadekoBot.Core.Common.Configs
{
public sealed class BotConfig
{
[Comment(@"DO NOT CHANGE")]
public int Version { get; set; }
[Comment(@"Most commands, when executed, have a small colored line
next to the response. The color depends whether the command
is completed, errored or in progress (pending)
Color settings below are for the color of those lines.
To get color's hex, you can go here https://htmlcolorcodes.com/
and copy the hex code fo your selected color (marked as #)")]
public ColorConfig Color { get; set; }
[Comment("Default bot language. It has to be in the list of supported languages (.langli)")]
public CultureInfo DefaultLocale { get; set; }
[Comment(@"Style in which executed commands will show up in the console.
Allowed values: Simple, Normal, None")]
public ConsoleOutputType ConsoleOutputType { get; set; }
// [Comment(@"For what kind of updates will the bot check.
// Allowed values: Release, Commit, None")]
// public UpdateCheckType CheckForUpdates { get; set; }
// [Comment(@"How often will the bot check for updates, in hours")]
// public int CheckUpdateInterval { get; set; }
[Comment(@"Do you want any messages sent by users in Bot's DM to be forwarded to the owner(s)?")]
public bool ForwardMessages { get; set; }
[Comment(@"Do you want the message to be forwarded only to the first owner specified in the list of owners (in creds.yml),
or all owners? (this might cause the bot to lag if there's a lot of owners specified)")]
public bool ForwardToAllOwners { get; set; }
[Comment(@"When a user DMs the bot with a message which is not a command
they will receive this message. Leave empty for no response. The string which will be sent whenever someone DMs the bot.
Supports embeds. How it looks: https://puu.sh/B0BLV.png")]
[YamlMember(ScalarStyle = ScalarStyle.Literal)]
public string DmHelpText { get; set; }
[Comment(@"This is the response for the .h command")]
[YamlMember(ScalarStyle = ScalarStyle.Literal)]
public string HelpText { get; set; }
[Comment(@"List of modules and commands completely blocked on the bot")]
public BlockedConfig Blocked { get; set; }
[Comment(@"Which string will be used to recognize the commands")]
public string Prefix { get; set; }
[Comment(@"Toggles whether your bot will group greet/bye messages into a single message every 5 seconds.
1st user who joins will get greeted immediately
If more users join within the next 5 seconds, they will be greeted in groups of 5.
This will cause %user.mention% and other placeholders to be replaced with multiple users.
Keep in mind this might break some of your embeds - for example if you have %user.avatar% in the thumbnail,
it will become invalid, as it will resolve to a list of avatars of grouped users.
note: This setting is primarily used if you're afraid of raids, or you're running medium/large bots where some
servers might get hundreds of people join at once. This is used to prevent the bot from getting ratelimited,
and (slightly) reduce the greet spam in those servers.")]
public bool GroupGreets { get; set; }
[Comment(@"Whether the bot will rotate through all specified statuses.
This setting can be changed via .rots command.
See RotatingStatuses submodule in Administration.")]
public bool RotateStatuses { get; set; }
// [Comment(@"Whether the prefix will be a suffix, or prefix.
// For example, if your prefix is ! you will run a command called 'cash' by typing either
// '!cash @Someone' if your prefixIsSuffix: false or
// 'cash @Someone!' if your prefixIsSuffix: true")]
// public bool PrefixIsSuffix { get; set; }
// public string Prefixed(string text) => PrefixIsSuffix
// ? text + Prefix
// : Prefix + text;
public string Prefixed(string text)
=> Prefix + text;
public BotConfig()
{
Version = 1;
var color = new ColorConfig();
Color = color;
DefaultLocale = new CultureInfo("en-US");
ConsoleOutputType = ConsoleOutputType.Normal;
ForwardMessages = false;
ForwardToAllOwners = false;
DmHelpText = @"{""description"": ""Type `%prefix%h` for help.""}";
HelpText = @"{
""title"": ""To invite me to your server, use this link"",
""description"": ""https://discordapp.com/oauth2/authorize?client_id={0}&scope=bot&permissions=66186303"",
""color"": 53380,
""thumbnail"": ""https://i.imgur.com/nKYyqMK.png"",
""fields"": [
{
""name"": ""Useful help commands"",
""value"": ""`%bot.prefix%modules` Lists all bot modules.
`%prefix%h CommandName` Shows some help about a specific command.
`%prefix%commands ModuleName` Lists all commands in a module."",
""inline"": false
},
{
""name"": ""List of all Commands"",
""value"": ""https://nadeko.bot/commands"",
""inline"": false
},
{
""name"": ""Nadeko Support Server"",
""value"": ""https://discord.nadeko.bot/ "",
""inline"": true
}
]
}";
var blocked = new BlockedConfig();
Blocked = blocked;
Prefix = ".";
RotateStatuses = false;
GroupGreets = false;
}
}
public class BlockedConfig
{
public HashSet<string> Commands { get; set; }
public HashSet<string> Modules { get; set; }
public BlockedConfig()
{
Modules = new HashSet<string>();
Commands = new HashSet<string>();
}
}
public class ColorConfig
{
[Comment(@"Color used for embed responses when command successfully executes")]
public Rgba32 Ok { get; set; }
[Comment(@"Color used for embed responses when command has an error")]
public Rgba32 Error { get; set; }
[Comment(@"Color used for embed responses while command is doing work or is in progress")]
public Rgba32 Pending { get; set; }
public ColorConfig()
{
Ok = Rgba32.ParseHex("00e584");
Error = Rgba32.ParseHex("ee281f");
Pending = Rgba32.ParseHex("faa61a");
}
}
public enum ConsoleOutputType
{
Normal = 0,
Simple = 1,
None = 2,
}
}

View File

@@ -0,0 +1,18 @@
namespace NadekoBot.Core.Common.Configs
{
/// <summary>
/// Base interface for available config serializers
/// </summary>
public interface IConfigSeria
{
/// <summary>
/// Serialize the object to string
/// </summary>
public string Serialize<T>(T obj);
/// <summary>
/// Deserialize string data into an object of the specified type
/// </summary>
public T Deserialize<T>(string data);
}
}

View File

@@ -0,0 +1,43 @@
using NadekoBot.Core.Services;
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using Discord;
namespace NadekoBot.Core.Common
{
public class DownloadTracker : INService
{
private ConcurrentDictionary<ulong, DateTime> LastDownloads { get; } = new ConcurrentDictionary<ulong, DateTime>();
private SemaphoreSlim downloadUsersSemaphore = new SemaphoreSlim(1, 1);
/// <summary>
/// Ensures all users on the specified guild were downloaded within the last hour.
/// </summary>
/// <param name="guild">Guild to check and potentially download users from</param>
/// <returns>Task representing download state</returns>
public async Task EnsureUsersDownloadedAsync(IGuild guild)
{
await downloadUsersSemaphore.WaitAsync();
try
{
var now = DateTime.UtcNow;
// download once per hour at most
var added = LastDownloads.AddOrUpdate(
guild.Id,
now,
(key, old) => (now - old) > TimeSpan.FromHours(1) ? now : old);
// means that this entry was just added - download the users
if (added == now)
await guild.DownloadUsersAsync();
}
finally
{
downloadUsersSemaphore.Release();
}
}
}
}

View File

@@ -0,0 +1,69 @@
using System;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using NadekoBot.Core.Common;
using NadekoBot.Core.Modules.Music;
using NadekoBot.Core.Services;
using NadekoBot.Modules.Administration.Services;
using NadekoBot.Modules.Music.Resolvers;
using NadekoBot.Modules.Music.Services;
namespace NadekoBot.Extensions
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddBotStringsServices(this IServiceCollection services)
=> services
.AddSingleton<IStringsSource, LocalFileStringsSource>()
.AddSingleton<IBotStringsProvider, LocalBotStringsProvider>()
.AddSingleton<IBotStrings, BotStrings>();
public static IServiceCollection AddConfigServices(this IServiceCollection services)
{
var baseType = typeof(ConfigServiceBase<>);
foreach (var type in Assembly.GetCallingAssembly().ExportedTypes.Where(x => x.IsSealed))
{
if (type.BaseType?.IsGenericType == true && type.BaseType.GetGenericTypeDefinition() == baseType)
{
services.AddSingleton(type);
services.AddSingleton(x => (IConfigService)x.GetRequiredService(type));
}
}
return services;
}
public static IServiceCollection AddConfigMigrators(this IServiceCollection services)
=> services.AddSealedSubclassesOf(typeof(IConfigMigrator));
public static IServiceCollection AddMusic(this IServiceCollection services)
=> services
.AddSingleton<IMusicService, MusicService>()
.AddSingleton<ITrackResolveProvider, TrackResolveProvider>()
.AddSingleton<IYoutubeResolver, YtdlYoutubeResolver>()
.AddSingleton<ISoundcloudResolver, SoundcloudResolver>()
.AddSingleton<ILocalTrackResolver, LocalTrackResolver>()
.AddSingleton<IRadioResolver, RadioResolver>()
.AddSingleton<ITrackCacher, RedisTrackCacher>()
.AddSingleton<YtLoader>()
.AddSingleton<IPlaceholderProvider>(svc => svc.GetService<IMusicService>());
// consider using scrutor, because slightly different versions
// of this might be needed in several different places
public static IServiceCollection AddSealedSubclassesOf(this IServiceCollection services, Type baseType)
{
var subTypes = Assembly.GetCallingAssembly()
.ExportedTypes
.Where(type => type.IsSealed && baseType.IsAssignableFrom(type));
foreach (var subType in subTypes)
{
services.AddSingleton(baseType, subType);
}
return services;
}
}
}

View File

@@ -0,0 +1,255 @@
using System;
namespace Discord
{
// just a copy paste from discord.net in order to rename it, for compatibility iwth v3 which is gonna use custom lib
// Summary:
// Defines the available permissions for a channel.
[Flags]
public enum GuildPerm : ulong
{
//
// Summary:
// Allows creation of instant invites.
CreateInstantInvite = 1,
//
// Summary:
// Allows kicking members.
//
// Remarks:
// This permission requires the owner account to use two-factor authentication when
// used on a guild that has server-wide 2FA enabled.
KickMembers = 2,
//
// Summary:
// Allows banning members.
//
// Remarks:
// This permission requires the owner account to use two-factor authentication when
// used on a guild that has server-wide 2FA enabled.
BanMembers = 4,
//
// Summary:
// Allows all permissions and bypasses channel permission overwrites.
//
// Remarks:
// This permission requires the owner account to use two-factor authentication when
// used on a guild that has server-wide 2FA enabled.
Administrator = 8,
//
// Summary:
// Allows management and editing of channels.
//
// Remarks:
// This permission requires the owner account to use two-factor authentication when
// used on a guild that has server-wide 2FA enabled.
ManageChannels = 16,
//
// Summary:
// Allows management and editing of the guild.
//
// Remarks:
// This permission requires the owner account to use two-factor authentication when
// used on a guild that has server-wide 2FA enabled.
ManageGuild = 32,
//
// Summary:
// Allows for the addition of reactions to messages.
AddReactions = 64,
//
// Summary:
// Allows for viewing of audit logs.
ViewAuditLog = 128,
PrioritySpeaker = 256,
ReadMessages = 1024,
ViewChannel = 1024,
SendMessages = 2048,
//
// Summary:
// Allows for sending of text-to-speech messages.
SendTTSMessages = 4096,
//
// Summary:
// Allows for deletion of other users messages.
//
// Remarks:
// This permission requires the owner account to use two-factor authentication when
// used on a guild that has server-wide 2FA enabled.
ManageMessages = 8192,
//
// Summary:
// Allows links sent by users with this permission will be auto-embedded.
EmbedLinks = 16384,
//
// Summary:
// Allows for uploading images and files.
AttachFiles = 32768,
//
// Summary:
// Allows for reading of message history.
ReadMessageHistory = 65536,
//
// Summary:
// Allows for using the @everyone tag to notify all users in a channel, and the
// @here tag to notify all online users in a channel.
MentionEveryone = 131072,
//
// Summary:
// Allows the usage of custom emojis from other servers.
UseExternalEmojis = 262144,
//
// Summary:
// Allows for joining of a voice channel.
Connect = 1048576,
//
// Summary:
// Allows for speaking in a voice channel.
Speak = 2097152,
//
// Summary:
// Allows for muting members in a voice channel.
MuteMembers = 4194304,
//
// Summary:
// Allows for deafening of members in a voice channel.
DeafenMembers = 8388608,
//
// Summary:
// Allows for moving of members between voice channels.
MoveMembers = 16777216,
//
// Summary:
// Allows for using voice-activity-detection in a voice channel.
UseVAD = 33554432,
//
// Summary:
// Allows for modification of own nickname.
ChangeNickname = 67108864,
//
// Summary:
// Allows for modification of other users nicknames.
ManageNicknames = 134217728,
//
// Summary:
// Allows management and editing of roles.
//
// Remarks:
// This permission requires the owner account to use two-factor authentication when
// used on a guild that has server-wide 2FA enabled.
ManageRoles = 268435456,
//
// Summary:
// Allows management and editing of webhooks.
//
// Remarks:
// This permission requires the owner account to use two-factor authentication when
// used on a guild that has server-wide 2FA enabled.
ManageWebhooks = 536870912,
//
// Summary:
// Allows management and editing of emojis.
//
// Remarks:
// This permission requires the owner account to use two-factor authentication when
// used on a guild that has server-wide 2FA enabled.
ManageEmojis = 1073741824
}
//
// Summary:
// Defines the available permissions for a channel.
[Flags]
public enum ChannelPerm : ulong
{
//
// Summary:
// Allows creation of instant invites.
CreateInstantInvite = 1,
//
// Summary:
// Allows management and editing of channels.
ManageChannel = 16,
//
// Summary:
// Allows for the addition of reactions to messages.
AddReactions = 64,
PrioritySpeaker = 256,
//
// Summary:
// Allows for reading of messages. This flag is obsolete, use Discord.ChannelPermission.ViewChannel
// instead.
ReadMessages = 1024,
//
// Summary:
// Allows guild members to view a channel, which includes reading messages in text
// channels.
ViewChannel = 1024,
//
// Summary:
// Allows for sending messages in a channel.
SendMessages = 2048,
//
// Summary:
// Allows for sending of text-to-speech messages.
SendTTSMessages = 4096,
//
// Summary:
// Allows for deletion of other users messages.
ManageMessages = 8192,
//
// Summary:
// Allows links sent by users with this permission will be auto-embedded.
EmbedLinks = 16384,
//
// Summary:
// Allows for uploading images and files.
AttachFiles = 32768,
//
// Summary:
// Allows for reading of message history.
ReadMessageHistory = 65536,
//
// Summary:
// Allows for using the @everyone tag to notify all users in a channel, and the
// @here tag to notify all online users in a channel.
MentionEveryone = 131072,
//
// Summary:
// Allows the usage of custom emojis from other servers.
UseExternalEmojis = 262144,
//
// Summary:
// Allows for joining of a voice channel.
Connect = 1048576,
//
// Summary:
// Allows for speaking in a voice channel.
Speak = 2097152,
//
// Summary:
// Allows for muting members in a voice channel.
MuteMembers = 4194304,
//
// Summary:
// Allows for deafening of members in a voice channel.
DeafenMembers = 8388608,
//
// Summary:
// Allows for moving of members between voice channels.
MoveMembers = 16777216,
//
// Summary:
// Allows for using voice-activity-detection in a voice channel.
UseVAD = 33554432,
//
// Summary:
// Allows management and editing of roles.
ManageRoles = 268435456,
//
// Summary:
// Allows management and editing of webhooks.
ManageWebhooks = 536870912
}
}

View File

@@ -0,0 +1,15 @@
using System;
namespace NadekoBot.Core.Common
{
public static class Helpers
{
public static void ReadErrorAndExit(int exitCode)
{
if (!Console.IsInputRedirected)
Console.ReadKey();
Environment.Exit(exitCode);
}
}
}

View File

@@ -0,0 +1,7 @@
namespace NadekoBot.Core.Common
{
public interface INadekoCommandOptions
{
void NormalizeOptions();
}
}

View File

@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
namespace NadekoBot.Core.Common
{
public interface IPlaceholderProvider
{
public IEnumerable<(string Name, Func<string> Func)> GetPlaceholders();
}
}

View File

@@ -0,0 +1,49 @@
using System;
namespace NadekoBot.Core.Common
{
public class ImageUrls
{
public int Version { get; set; } = 2;
public CoinData Coins { get; set; }
public Uri[] Currency { get; set; }
public Uri[] Dice { get; set; }
public RategirlData Rategirl { get; set; }
public XpData Xp { get; set; }
//new
public RipData Rip { get; set; }
public SlotData Slots { get; set; }
public class RipData
{
public Uri Bg { get; set; }
public Uri Overlay { get; set; }
}
public class SlotData
{
public Uri[] Emojis { get; set; }
public Uri[] Numbers { get; set; }
public Uri Bg { get; set; }
}
public class CoinData
{
public Uri[] Heads { get; set; }
public Uri[] Tails { get; set; }
}
public class RategirlData
{
public Uri Matrix { get; set; }
public Uri Dot { get; set; }
}
public class XpData
{
public Uri Bg { get; set; }
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
using SixLabors.ImageSharp.PixelFormats;
namespace NadekoBot.Core.Common.JsonConverters
{
public class Rgba32Converter : JsonConverter<Rgba32>
{
public override Rgba32 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return Rgba32.ParseHex(reader.GetString());
}
public override void Write(Utf8JsonWriter writer, Rgba32 value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToHex());
}
}
public class CultureInfoConverter : JsonConverter<CultureInfo>
{
public override CultureInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new CultureInfo(reader.GetString());
}
public override void Write(Utf8JsonWriter writer, CultureInfo value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.Name);
}
}
}

View File

@@ -0,0 +1,98 @@
using System;
using System.Runtime.CompilerServices;
namespace NadekoBot.Core.Common
{
// needs proper invalid input check (character array input out of range)
// needs negative number support
public readonly struct kwum : IEquatable<kwum>
{
private readonly int _value;
private const string ValidCharacters = "23456789abcdefghijkmnpqrstuvwxyz";
public kwum(int num)
=> _value = num;
public kwum(in char c)
{
if (!IsValidChar(c))
throw new ArgumentException("Character needs to be a valid kwum character.", nameof(c));
_value = InternalCharToValue(c);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int InternalCharToValue(in char c)
=> ValidCharacters.IndexOf(c);
public kwum(in ReadOnlySpan<char> input)
{;
_value = 0;
for (var index = 0; index < input.Length; index++)
{
var c = input[index];
if (!IsValidChar(c))
throw new ArgumentException("All characters need to be a valid kwum characters.", nameof(input));
_value += ValidCharacters.IndexOf(c) * (int)Math.Pow(ValidCharacters.Length, input.Length - index - 1);
}
}
public static bool TryParse(in ReadOnlySpan<char> input, out kwum value)
{
value = default;
foreach(var c in input)
if (!IsValidChar(c))
return false;
value = new kwum(input);
return true;
}
public static kwum operator +(kwum left, kwum right)
=> new kwum(left._value + right._value);
public static bool operator ==(kwum left, kwum right)
=> left._value == right._value;
public static bool operator !=(kwum left, kwum right)
=> !(left == right);
public static implicit operator long(kwum kwum)
=> kwum._value;
public static implicit operator int(kwum kwum)
=> kwum._value;
public static implicit operator kwum(int num)
=> new kwum(num);
public static bool IsValidChar(char c)
=> ValidCharacters.Contains(c);
public override string ToString()
{
var count = ValidCharacters.Length;
var localValue = _value;
var arrSize = (int)Math.Log(localValue, count) + 1;
Span<char> chars = new char[arrSize];
while (localValue > 0)
{
localValue = Math.DivRem(localValue, count, out var rem);
chars[--arrSize] = ValidCharacters[(int)rem];
}
return new string(chars);
}
public override bool Equals(object obj)
=> obj is kwum kw && kw == this;
public bool Equals(kwum other)
=> other == this;
public override int GetHashCode()
{
return _value.GetHashCode();
}
}
}

View File

@@ -0,0 +1,14 @@
using CommandLine;
namespace NadekoBot.Core.Common
{
public class LbOpts : INadekoCommandOptions
{
[Option('c', "clean", Default = false, HelpText = "Only show users who are on the server.")]
public bool Clean { get; set; }
public void NormalizeOptions()
{
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
using System.Net;
using System.Runtime.CompilerServices;
using Discord.Net;
using Serilog;
namespace NadekoBot.Core.Common
{
public class LoginErrorHandler
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Handle(Exception ex)
{
Log.Fatal(ex, "A fatal error has occurred while attempting to connect to Discord");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Handle(HttpException ex)
{
switch (ex.HttpCode)
{
case HttpStatusCode.Unauthorized:
Log.Error("Your bot token is wrong.\n" +
"You can find the bot token under the Bot tab in the developer page.\n" +
"Fix your token in the credentials file and restart the bot");
break;
case HttpStatusCode.BadRequest:
Log.Error("Something has been incorrectly formatted in your credentials file.\n" +
"Use the JSON Guide as reference to fix it and restart the bot.");
Log.Error("If you are on Linux, make sure Redis is installed and running");
break;
case HttpStatusCode.RequestTimeout:
Log.Error("The request timed out. Make sure you have no external program blocking the bot " +
"from connecting to the internet");
break;
case HttpStatusCode.ServiceUnavailable:
case HttpStatusCode.InternalServerError:
Log.Error("Discord is having internal issues. Please, try again later");
break;
case HttpStatusCode.TooManyRequests:
Log.Error("Your bot has been ratelimited by Discord. Please, try again later.\n" +
"Global ratelimits usually last for an hour");
break;
default:
Log.Warning("An error occurred while attempting to connect to Discord");
break;
}
Log.Fatal(ex.ToString());
}
}
}

View File

@@ -0,0 +1,23 @@
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
namespace NadekoBot.Common.ModuleBehaviors
{
/// <summary>
/// Implemented by modules which block execution before anything is executed
/// </summary>
public interface IEarlyBehavior
{
int Priority { get; }
ModuleBehaviorType BehaviorType { get; }
Task<bool> RunBehavior(DiscordSocketClient client, IGuild guild, IUserMessage msg);
}
public enum ModuleBehaviorType
{
Blocker,
Executor,
}
}

View File

@@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Discord;
namespace NadekoBot.Common.ModuleBehaviors
{
public interface IInputTransformer
{
Task<string> TransformInput(IGuild guild, IMessageChannel channel, IUser user, string input);
}
}

View File

@@ -0,0 +1,14 @@
using System.Threading.Tasks;
using Discord.Commands;
using Discord.WebSocket;
namespace NadekoBot.Common.ModuleBehaviors
{
public interface ILateBlocker
{
public int Priority { get; }
Task<bool> TryBlockLate(DiscordSocketClient client, ICommandContext context,
string moduleName, CommandInfo command);
}
}

View File

@@ -0,0 +1,14 @@
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
namespace NadekoBot.Common.ModuleBehaviors
{
/// <summary>
/// Last thing to be executed, won't stop further executions
/// </summary>
public interface ILateExecutor
{
Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg);
}
}

View File

@@ -0,0 +1,34 @@
using Discord;
using Discord.WebSocket;
using System.Threading.Tasks;
namespace NadekoBot.Common.ModuleBehaviors
{
public struct ModuleBehaviorResult
{
public bool Blocked { get; set; }
public string NewInput { get; set; }
public static ModuleBehaviorResult None() => new ModuleBehaviorResult
{
Blocked = false,
NewInput = null,
};
public static ModuleBehaviorResult FromBlocked(bool blocked) => new ModuleBehaviorResult
{
Blocked = blocked,
NewInput = null,
};
}
public interface IModuleBehavior
{
/// <summary>
/// Negative priority means it will try to apply as early as possible
/// Positive priority menas it will try to apply as late as possible
/// </summary>
int Priority { get; }
Task<ModuleBehaviorResult> ApplyBehavior(DiscordSocketClient client, IGuild guild, IUserMessage msg);
}
}

View File

@@ -0,0 +1,16 @@
using System.Threading.Tasks;
namespace NadekoBot.Common.ModuleBehaviors
{
/// <summary>
/// All services which need to execute something after
/// the bot is ready should implement this interface
/// </summary>
public interface IReadyExecutor
{
/// <summary>
/// Executed when bot is ready
/// </summary>
public Task OnReadyAsync();
}
}

View File

@@ -0,0 +1,155 @@
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using NadekoBot.Core.Services;
using NadekoBot.Extensions;
using System.Globalization;
using System.Threading.Tasks;
namespace NadekoBot.Modules
{
public abstract class NadekoModule : ModuleBase
{
protected CultureInfo _cultureInfo { get; set; }
public IBotStrings Strings { get; set; }
public CommandHandler CmdHandler { get; set; }
public ILocalization Localization { get; set; }
public string Prefix => CmdHandler.GetPrefix(ctx.Guild);
protected ICommandContext ctx => Context;
protected NadekoModule()
{
}
protected override void BeforeExecute(CommandInfo cmd)
{
_cultureInfo = Localization.GetCultureInfo(ctx.Guild?.Id);
}
protected string GetText(string key) =>
Strings.GetText(key, _cultureInfo);
protected string GetText(string key, params object[] args) =>
Strings.GetText(key, _cultureInfo, args);
public Task<IUserMessage> ErrorLocalizedAsync(string textKey, params object[] args)
{
var text = GetText(textKey, args);
return ctx.Channel.SendErrorAsync(text);
}
public Task<IUserMessage> ReplyErrorLocalizedAsync(string textKey, params object[] args)
{
var text = GetText(textKey, args);
return ctx.Channel.SendErrorAsync(Format.Bold(ctx.User.ToString()) + " " + text);
}
public Task<IUserMessage> ReplyPendingLocalizedAsync(string textKey, params object[] args)
{
var text = GetText(textKey, args);
return ctx.Channel.SendPendingAsync(Format.Bold(ctx.User.ToString()) + " " + text);
}
public Task<IUserMessage> ConfirmLocalizedAsync(string textKey, params object[] args)
{
var text = GetText(textKey, args);
return ctx.Channel.SendConfirmAsync(text);
}
public Task<IUserMessage> ReplyConfirmLocalizedAsync(string textKey, params object[] args)
{
var text = GetText(textKey, args);
return ctx.Channel.SendConfirmAsync(Format.Bold(ctx.User.ToString()) + " " + text);
}
public async Task<bool> PromptUserConfirmAsync(EmbedBuilder embed)
{
embed
.WithPendingColor()
.WithFooter("yes/no");
var msg = await ctx.Channel.EmbedAsync(embed).ConfigureAwait(false);
try
{
var input = await GetUserInputAsync(ctx.User.Id, ctx.Channel.Id).ConfigureAwait(false);
input = input?.ToUpperInvariant();
if (input != "YES" && input != "Y")
{
return false;
}
return true;
}
finally
{
var _ = Task.Run(() => msg.DeleteAsync());
}
}
// TypeConverter typeConverter = TypeDescriptor.GetConverter(propType); ?
public async Task<string> GetUserInputAsync(ulong userId, ulong channelId)
{
var userInputTask = new TaskCompletionSource<string>();
var dsc = (DiscordSocketClient)ctx.Client;
try
{
dsc.MessageReceived += MessageReceived;
if ((await Task.WhenAny(userInputTask.Task, Task.Delay(10000)).ConfigureAwait(false)) != userInputTask.Task)
{
return null;
}
return await userInputTask.Task.ConfigureAwait(false);
}
finally
{
dsc.MessageReceived -= MessageReceived;
}
Task MessageReceived(SocketMessage arg)
{
var _ = Task.Run(() =>
{
if (!(arg is SocketUserMessage userMsg) ||
!(userMsg.Channel is ITextChannel chan) ||
userMsg.Author.Id != userId ||
userMsg.Channel.Id != channelId)
{
return Task.CompletedTask;
}
if (userInputTask.TrySetResult(arg.Content))
{
userMsg.DeleteAfter(1);
}
return Task.CompletedTask;
});
return Task.CompletedTask;
}
}
}
public abstract class NadekoModule<TService> : NadekoModule
{
public TService _service { get; set; }
protected NadekoModule() : base()
{
}
}
public abstract class NadekoSubmodule : NadekoModule
{
protected NadekoSubmodule() : base() { }
}
public abstract class NadekoSubmodule<TService> : NadekoModule<TService>
{
protected NadekoSubmodule() : base()
{
}
}
}

View File

@@ -0,0 +1,7 @@
namespace NadekoBot.Modules
{
public static class NadekoModuleExtensions
{
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Security.Cryptography;
namespace NadekoBot.Common
{
public class NadekoRandom : Random
{
readonly RandomNumberGenerator _rng;
public NadekoRandom() : base()
{
_rng = RandomNumberGenerator.Create();
}
public override int Next()
{
var bytes = new byte[sizeof(int)];
_rng.GetBytes(bytes);
return Math.Abs(BitConverter.ToInt32(bytes, 0));
}
public override int Next(int maxValue)
{
if (maxValue <= 0)
throw new ArgumentOutOfRangeException(nameof(maxValue));
var bytes = new byte[sizeof(int)];
_rng.GetBytes(bytes);
return Math.Abs(BitConverter.ToInt32(bytes, 0)) % maxValue;
}
public override int Next(int minValue, int maxValue)
{
if (minValue > maxValue)
throw new ArgumentOutOfRangeException(nameof(maxValue));
if (minValue == maxValue)
return minValue;
var bytes = new byte[sizeof(int)];
_rng.GetBytes(bytes);
var sign = Math.Sign(BitConverter.ToInt32(bytes, 0));
return (sign * BitConverter.ToInt32(bytes, 0)) % (maxValue - minValue) + minValue;
}
public long NextLong(long minValue, long maxValue)
{
if (minValue > maxValue)
throw new ArgumentOutOfRangeException(nameof(maxValue));
if (minValue == maxValue)
return minValue;
var bytes = new byte[sizeof(long)];
_rng.GetBytes(bytes);
var sign = Math.Sign(BitConverter.ToInt64(bytes, 0));
return (sign * BitConverter.ToInt64(bytes, 0)) % (maxValue - minValue) + minValue;
}
public override void NextBytes(byte[] buffer)
{
_rng.GetBytes(buffer);
}
protected override double Sample()
{
var bytes = new byte[sizeof(double)];
_rng.GetBytes(bytes);
return Math.Abs(BitConverter.ToDouble(bytes, 0) / double.MaxValue + 1);
}
public override double NextDouble()
{
var bytes = new byte[sizeof(double)];
_rng.GetBytes(bytes);
return BitConverter.ToDouble(bytes, 0);
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Threading.Tasks;
using Discord.Commands;
namespace NadekoBot.Common
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public sealed class NoPublicBotAttribute : PreconditionAttribute
{
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
{
#if GLOBAL_NADEKO
return Task.FromResult(PreconditionResult.FromError("Not available on the public bot"));
#else
return Task.FromResult(PreconditionResult.FromSuccess());
#endif
}
}
}

View File

@@ -0,0 +1,24 @@
using CommandLine;
namespace NadekoBot.Core.Common
{
public static class OptionsParser
{
public static T ParseFrom<T>(string[] args) where T : INadekoCommandOptions, new()
=> ParseFrom(new T(), args).Item1;
public static (T, bool) ParseFrom<T>(T options, string[] args) where T : INadekoCommandOptions
{
using (var p = new Parser(x =>
{
x.HelpWriter = null;
}))
{
var res = p.ParseArguments<T>(args);
options = res.MapResult(x => x, x => options);
options.NormalizeOptions();
return (options, res.Tag == ParserResultType.Parsed);
}
}
}
}

View File

@@ -0,0 +1,9 @@
namespace NadekoBot.Core.Common
{
public class OsuMapData
{
public string Title { get; set; }
public string Artist { get; set; }
public string Version { get; set; }
}
}

View File

@@ -0,0 +1,41 @@
using Newtonsoft.Json;
namespace NadekoBot.Core.Common
{
public class OsuUserBests
{
[JsonProperty("beatmap_id")] public string BeatmapId { get; set; }
[JsonProperty("score_id")] public string ScoreId { get; set; }
[JsonProperty("score")] public string Score { get; set; }
[JsonProperty("maxcombo")] public string Maxcombo { get; set; }
[JsonProperty("count50")] public double Count50 { get; set; }
[JsonProperty("count100")] public double Count100 { get; set; }
[JsonProperty("count300")] public double Count300 { get; set; }
[JsonProperty("countmiss")] public int Countmiss { get; set; }
[JsonProperty("countkatu")] public double Countkatu { get; set; }
[JsonProperty("countgeki")] public double Countgeki { get; set; }
[JsonProperty("perfect")] public string Perfect { get; set; }
[JsonProperty("enabled_mods")] public int EnabledMods { get; set; }
[JsonProperty("user_id")] public string UserId { get; set; }
[JsonProperty("date")] public string Date { get; set; }
[JsonProperty("rank")] public string Rank { get; set; }
[JsonProperty("pp")] public double Pp { get; set; }
[JsonProperty("replay_available")] public string ReplayAvailable { get; set; }
}
}

View File

@@ -0,0 +1,25 @@
using System;
namespace NadekoBot.Common
{
public static class PlatformHelper
{
private const int ProcessorCountRefreshIntervalMs = 30000;
private static volatile int _processorCount;
private static volatile int _lastProcessorCountRefreshTicks;
public static int ProcessorCount {
get {
var now = Environment.TickCount;
if (_processorCount == 0 || (now - _lastProcessorCountRefreshTicks) >= ProcessorCountRefreshIntervalMs)
{
_processorCount = Environment.ProcessorCount;
_lastProcessorCountRefreshTicks = now;
}
return _processorCount;
}
}
}
}

View File

@@ -0,0 +1,8 @@
namespace NadekoBot.Core.Common.Pokemon
{
public class PokemonNameId
{
public int Id { get; set; }
public string Name { get; set; }
}
}

View File

@@ -0,0 +1,40 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace NadekoBot.Core.Common.Pokemon
{
public class SearchPokemon
{
public class GenderRatioClass
{
public float M { get; set; }
public float F { get; set; }
}
public class BaseStatsClass
{
public int HP { get; set; }
public int ATK { get; set; }
public int DEF { get; set; }
public int SPA { get; set; }
public int SPD { get; set; }
public int SPE { get; set; }
public override string ToString() => $@"💚**HP:** {HP,-4} ⚔**ATK:** {ATK,-4} 🛡**DEF:** {DEF,-4}
✨**SPA:** {SPA,-4} 🎇**SPD:** {SPD,-4} 💨**SPE:** {SPE,-4}";
}
[JsonProperty("num")]
public int Id { get; set; }
public string Species { get; set; }
public string[] Types { get; set; }
public GenderRatioClass GenderRatio { get; set; }
public BaseStatsClass BaseStats { get; set; }
public Dictionary<string, string> Abilities { get; set; }
public float HeightM { get; set; }
public float WeightKg { get; set; }
public string Color { get; set; }
public string[] Evos { get; set; }
public string[] EggGroups { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
namespace NadekoBot.Core.Common.Pokemon
{
public class SearchPokemonAbility
{
public string Desc { get; set; }
public string ShortDesc { get; set; }
public string Name { get; set; }
public float Rating { get; set; }
}
}

View File

@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace NadekoBot.Core.Common
{
public class EventPubSub : IPubSub
{
private readonly Dictionary<string, Dictionary<Delegate, List<Func<object, ValueTask>>>> _actions
= new Dictionary<string, Dictionary<Delegate, List<Func<object, ValueTask>>>>();
private readonly object locker = new object();
public Task Sub<TData>(in TypedKey<TData> key, Func<TData, ValueTask> action)
{
Func<object, ValueTask> localAction = obj => action((TData) obj);
lock(locker)
{
Dictionary<Delegate, List<Func<object, ValueTask>>> keyActions;
if (!_actions.TryGetValue(key.Key, out keyActions))
{
keyActions = new Dictionary<Delegate, List<Func<object, ValueTask>>>();
_actions[key.Key] = keyActions;
}
List<Func<object, ValueTask>> sameActions;
if (!keyActions.TryGetValue(action, out sameActions))
{
sameActions = new List<Func<object, ValueTask>>();
keyActions[action] = sameActions;
}
sameActions.Add(localAction);
return Task.CompletedTask;
}
}
public Task Pub<TData>(in TypedKey<TData> key, TData data)
{
lock (locker)
{
if(_actions.TryGetValue(key.Key, out var actions))
{
// if this class ever gets used, this needs to be properly implemented
// 1. ignore all valuetasks which are completed
// 2. return task.whenall all other tasks
return Task.WhenAll(actions
.SelectMany(kvp => kvp.Value)
.Select(action => action(data).AsTask()));
}
return Task.CompletedTask;
}
}
public Task Unsub<TData>(in TypedKey<TData> key, Func<TData, ValueTask> action)
{
lock (locker)
{
// get subscriptions for this action
if (_actions.TryGetValue(key.Key, out var actions))
{
var hashCode = action.GetHashCode();
// get subscriptions which have the same action hash code
// note: having this as a list allows for multiple subscriptions of
// the same insance's/static method
if (actions.TryGetValue(action, out var sameActions))
{
// remove last subscription
sameActions.RemoveAt(sameActions.Count - 1);
// if the last subscription was the only subscription
// we can safely remove this action's dictionary entry
if (sameActions.Count == 0)
{
actions.Remove(action);
// if our dictionary has no more elements after
// removing the entry
// it's safe to remove it from the key's subscriptions
if (actions.Count == 0)
{
_actions.Remove(key.Key);
}
}
}
}
return Task.CompletedTask;
}
}
}
}

View File

@@ -0,0 +1,11 @@
using System;
using System.Threading.Tasks;
namespace NadekoBot.Core.Common
{
public interface IPubSub
{
public Task Pub<TData>(in TypedKey<TData> key, TData data);
public Task Sub<TData>(in TypedKey<TData> key, Func<TData, ValueTask> action);
}
}

View File

@@ -0,0 +1,8 @@
namespace NadekoBot.Core.Common
{
public interface ISeria
{
byte[] Serialize<T>(T data);
T Deserialize<T>(byte[] data);
}
}

View File

@@ -0,0 +1,28 @@
using System.Text.Json;
using NadekoBot.Core.Common.JsonConverters;
namespace NadekoBot.Core.Common
{
public class JsonSeria : ISeria
{
private JsonSerializerOptions serializerOptions = new JsonSerializerOptions()
{
Converters =
{
new Rgba32Converter(),
new CultureInfoConverter(),
}
};
public byte[] Serialize<T>(T data)
=> JsonSerializer.SerializeToUtf8Bytes(data, serializerOptions);
public T Deserialize<T>(byte[] data)
{
if (data is null)
return default;
return JsonSerializer.Deserialize<T>(data, serializerOptions);
}
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.Threading.Tasks;
using NadekoBot.Core.Services;
using NadekoBot.Extensions;
using Serilog;
using StackExchange.Redis;
namespace NadekoBot.Core.Common
{
public sealed class RedisPubSub : IPubSub
{
private readonly ConnectionMultiplexer _multi;
private readonly ISeria _serializer;
private readonly IBotCredentials _creds;
public RedisPubSub(ConnectionMultiplexer multi, ISeria serializer, IBotCredentials creds)
{
_multi = multi;
_serializer = serializer;
_creds = creds;
}
public Task Pub<TData>(in TypedKey<TData> key, TData data)
{
var serialized = _serializer.Serialize(data);
return _multi.GetSubscriber().PublishAsync($"{_creds.RedisKey()}:{key.Key}", serialized, CommandFlags.FireAndForget);
}
public Task Sub<TData>(in TypedKey<TData> key, Func<TData, ValueTask> action)
{
var eventName = key.Key;
return _multi.GetSubscriber().SubscribeAsync($"{_creds.RedisKey()}:{eventName}", async (ch, data) =>
{
try
{
var dataObj = _serializer.Deserialize<TData>(data);
await action(dataObj);
}
catch (Exception ex)
{
Log.Error($"Error handling the event {eventName}: {ex.Message}");
}
});
}
}
}

View File

@@ -0,0 +1,29 @@
namespace NadekoBot.Core.Common
{
public readonly struct TypedKey<TData>
{
public readonly string Key;
public TypedKey(in string key)
{
Key = key;
}
public static implicit operator TypedKey<TData>(in string input)
=> new TypedKey<TData>(input);
public static implicit operator string(in TypedKey<TData> input)
=> input.Key;
public static bool operator ==(in TypedKey<TData> left, in TypedKey<TData> right)
=> left.Key == right.Key;
public static bool operator !=(in TypedKey<TData> left, in TypedKey<TData> right)
=> !(left == right);
public override bool Equals(object obj)
=> obj is TypedKey<TData> o && o == this;
public override int GetHashCode() => Key?.GetHashCode() ?? 0;
public override string ToString() => Key;
}
}

View File

@@ -0,0 +1,38 @@
using System.Text.RegularExpressions;
using NadekoBot.Common.Yml;
using NadekoBot.Core.Common.Configs;
using YamlDotNet.Serialization;
namespace NadekoBot.Core.Common
{
public class YamlSeria : IConfigSeria
{
private readonly ISerializer _serializer;
private readonly IDeserializer _deserializer;
private static readonly Regex CodePointRegex
= new Regex(@"(\\U(?<code>[a-zA-Z0-9]{8})|\\u(?<code>[a-zA-Z0-9]{4})|\\x(?<code>[a-zA-Z0-9]{2}))",
RegexOptions.Compiled);
public YamlSeria()
{
_serializer = Yaml.Serializer;
_deserializer = Yaml.Deserializer;
}
public string Serialize<T>(T obj)
{
var escapedOutput = _serializer.Serialize(obj);
var output = CodePointRegex.Replace(escapedOutput, me =>
{
var str = me.Groups["code"].Value;
var newString = YamlHelper.UnescapeUnicodeCodePoint(str);
return newString;
});
return output;
}
public T Deserialize<T>(string data)
=> _deserializer.Deserialize<T>(data);
}
}

View File

@@ -0,0 +1,235 @@
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using NadekoBot.Extensions;
using NadekoBot.Modules.Administration.Services;
using NadekoBot.Modules.Music.Services;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using NadekoBot.Core.Common;
namespace NadekoBot.Common.Replacements
{
public class ReplacementBuilder
{
private static readonly Regex rngRegex = new Regex("%rng(?:(?<from>(?:-)?\\d+)-(?<to>(?:-)?\\d+))?%", RegexOptions.Compiled);
private ConcurrentDictionary<string, Func<string>> _reps = new ConcurrentDictionary<string, Func<string>>();
private ConcurrentDictionary<Regex, Func<Match, string>> _regex = new ConcurrentDictionary<Regex, Func<Match, string>>();
public ReplacementBuilder()
{
WithRngRegex();
}
public ReplacementBuilder WithDefault(IUser usr, IMessageChannel ch, SocketGuild g, DiscordSocketClient client)
{
return this.WithUser(usr)
.WithChannel(ch)
.WithServer(client, g)
.WithClient(client);
}
public ReplacementBuilder WithDefault(ICommandContext ctx) =>
WithDefault(ctx.User, ctx.Channel, ctx.Guild as SocketGuild, (DiscordSocketClient)ctx.Client);
public ReplacementBuilder WithMention(DiscordSocketClient client)
{
/*OBSOLETE*/
_reps.TryAdd("%mention%", () => $"<@{client.CurrentUser.Id}>");
/*NEW*/
_reps.TryAdd("%bot.mention%", () => client.CurrentUser.Mention);
return this;
}
public ReplacementBuilder WithClient(DiscordSocketClient client)
{
WithMention(client);
/*OBSOLETE*/
_reps.TryAdd("%shardid%", () => client.ShardId.ToString());
_reps.TryAdd("%time%", () => DateTime.Now.ToString("HH:mm " + TimeZoneInfo.Local.StandardName.GetInitials()));
/*NEW*/
_reps.TryAdd("%bot.status%", () => client.Status.ToString());
_reps.TryAdd("%bot.latency%", () => client.Latency.ToString());
_reps.TryAdd("%bot.name%", () => client.CurrentUser.Username);
_reps.TryAdd("%bot.fullname%", () => client.CurrentUser.ToString());
_reps.TryAdd("%bot.time%", () => DateTime.Now.ToString("HH:mm " + TimeZoneInfo.Local.StandardName.GetInitials()));
_reps.TryAdd("%bot.discrim%", () => client.CurrentUser.Discriminator);
_reps.TryAdd("%bot.id%", () => client.CurrentUser.Id.ToString());
_reps.TryAdd("%bot.avatar%", () => client.CurrentUser.RealAvatarUrl()?.ToString());
WithStats(client);
return this;
}
public ReplacementBuilder WithServer(DiscordSocketClient client, SocketGuild g)
{
/*OBSOLETE*/
_reps.TryAdd("%sid%", () => g == null ? "DM" : g.Id.ToString());
_reps.TryAdd("%server%", () => g == null ? "DM" : g.Name);
_reps.TryAdd("%members%", () => g != null && g is SocketGuild sg ? sg.MemberCount.ToString() : "?");
_reps.TryAdd("%server_time%", () =>
{
TimeZoneInfo to = TimeZoneInfo.Local;
if (g != null)
{
if (GuildTimezoneService.AllServices.TryGetValue(client.CurrentUser.Id, out var tz))
to = tz.GetTimeZoneOrDefault(g.Id) ?? TimeZoneInfo.Local;
}
return TimeZoneInfo.ConvertTime(DateTime.UtcNow,
TimeZoneInfo.Utc,
to).ToString("HH:mm ") + to.StandardName.GetInitials();
});
/*NEW*/
_reps.TryAdd("%server.id%", () => g == null ? "DM" : g.Id.ToString());
_reps.TryAdd("%server.name%", () => g == null ? "DM" : g.Name);
_reps.TryAdd("%server.members%", () => g != null && g is SocketGuild sg ? sg.MemberCount.ToString() : "?");
_reps.TryAdd("%server.time%", () =>
{
TimeZoneInfo to = TimeZoneInfo.Local;
if (g != null)
{
if (GuildTimezoneService.AllServices.TryGetValue(client.CurrentUser.Id, out var tz))
to = tz.GetTimeZoneOrDefault(g.Id) ?? TimeZoneInfo.Local;
}
return TimeZoneInfo.ConvertTime(DateTime.UtcNow,
TimeZoneInfo.Utc,
to).ToString("HH:mm ") + to.StandardName.GetInitials();
});
return this;
}
public ReplacementBuilder WithChannel(IMessageChannel ch)
{
/*OBSOLETE*/
_reps.TryAdd("%channel%", () => (ch as ITextChannel)?.Mention ?? "#" + ch.Name);
_reps.TryAdd("%chname%", () => ch.Name);
_reps.TryAdd("%cid%", () => ch?.Id.ToString());
/*NEW*/
_reps.TryAdd("%channel.mention%", () => (ch as ITextChannel)?.Mention ?? "#" + ch.Name);
_reps.TryAdd("%channel.name%", () => ch.Name);
_reps.TryAdd("%channel.id%", () => ch.Id.ToString());
_reps.TryAdd("%channel.created%", () => ch.CreatedAt.ToString("HH:mm dd.MM.yyyy"));
_reps.TryAdd("%channel.nsfw%", () => (ch as ITextChannel)?.IsNsfw.ToString() ?? "-");
_reps.TryAdd("%channel.topic%", () => (ch as ITextChannel)?.Topic ?? "-");
return this;
}
public ReplacementBuilder WithUser(IUser user)
{
// /*OBSOLETE*/
// _reps.TryAdd("%user%", () => user.Mention);
// _reps.TryAdd("%userfull%", () => user.ToString());
// _reps.TryAdd("%username%", () => user.Username);
// _reps.TryAdd("%userdiscrim%", () => user.Discriminator);
// _reps.TryAdd("%useravatar%", () => user.RealAvatarUrl()?.ToString());
// _reps.TryAdd("%id%", () => user.Id.ToString());
// _reps.TryAdd("%uid%", () => user.Id.ToString());
// /*NEW*/
// _reps.TryAdd("%user.mention%", () => user.Mention);
// _reps.TryAdd("%user.fullname%", () => user.ToString());
// _reps.TryAdd("%user.name%", () => user.Username);
// _reps.TryAdd("%user.discrim%", () => user.Discriminator);
// _reps.TryAdd("%user.avatar%", () => user.RealAvatarUrl()?.ToString());
// _reps.TryAdd("%user.id%", () => user.Id.ToString());
// _reps.TryAdd("%user.created_time%", () => user.CreatedAt.ToString("HH:mm"));
// _reps.TryAdd("%user.created_date%", () => user.CreatedAt.ToString("dd.MM.yyyy"));
// _reps.TryAdd("%user.joined_time%", () => (user as IGuildUser)?.JoinedAt?.ToString("HH:mm") ?? "-");
// _reps.TryAdd("%user.joined_date%", () => (user as IGuildUser)?.JoinedAt?.ToString("dd.MM.yyyy") ?? "-");
WithManyUsers(new[] {user});
return this;
}
public ReplacementBuilder WithManyUsers(IEnumerable<IUser> users)
{
/*OBSOLETE*/
_reps.TryAdd("%user%", () => string.Join(" ", users.Select(user => user.Mention)));
_reps.TryAdd("%userfull%", () => string.Join(" ", users.Select(user => user.ToString())));
_reps.TryAdd("%username%", () => string.Join(" ", users.Select(user => user.Username)));
_reps.TryAdd("%userdiscrim%", () => string.Join(" ", users.Select(user => user.Discriminator)));
_reps.TryAdd("%useravatar%", () => string.Join(" ", users.Select(user => user.RealAvatarUrl()?.ToString())));
_reps.TryAdd("%id%", () => string.Join(" ", users.Select(user => user.Id.ToString())));
_reps.TryAdd("%uid%", () => string.Join(" ", users.Select(user => user.Id.ToString())));
/*NEW*/
_reps.TryAdd("%user.mention%", () => string.Join(" ", users.Select(user => user.Mention)));
_reps.TryAdd("%user.fullname%", () => string.Join(" ", users.Select(user => user.ToString())));
_reps.TryAdd("%user.name%", () => string.Join(" ", users.Select(user => user.Username)));
_reps.TryAdd("%user.discrim%", () => string.Join(" ", users.Select(user => user.Discriminator)));
_reps.TryAdd("%user.avatar%", () => string.Join(" ", users.Select(user => user.RealAvatarUrl()?.ToString())));
_reps.TryAdd("%user.id%", () => string.Join(" ", users.Select(user => user.Id.ToString())));
_reps.TryAdd("%user.created_time%", () => string.Join(" ", users.Select(user => user.CreatedAt.ToString("HH:mm"))));
_reps.TryAdd("%user.created_date%", () => string.Join(" ", users.Select(user => user.CreatedAt.ToString("dd.MM.yyyy"))));
_reps.TryAdd("%user.joined_time%", () => string.Join(" ", users.Select(user => (user as IGuildUser)?.JoinedAt?.ToString("HH:mm") ?? "-")));
_reps.TryAdd("%user.joined_date%", () => string.Join(" ", users.Select(user => (user as IGuildUser)?.JoinedAt?.ToString("dd.MM.yyyy") ?? "-")));
return this;
}
private ReplacementBuilder WithStats(DiscordSocketClient c)
{
/*OBSOLETE*/
_reps.TryAdd("%servers%", () => c.Guilds.Count.ToString());
#if !GLOBAL_NADEKO
_reps.TryAdd("%users%", () => c.Guilds.Sum(s => s.Users.Count).ToString());
#endif
/*NEW*/
_reps.TryAdd("%shard.servercount%", () => c.Guilds.Count.ToString());
#if !GLOBAL_NADEKO
_reps.TryAdd("%shard.usercount%", () => c.Guilds.Sum(s => s.Users.Count).ToString());
#endif
_reps.TryAdd("%shard.id%", () => c.ShardId.ToString());
return this;
}
public ReplacementBuilder WithRngRegex()
{
var rng = new NadekoRandom();
_regex.TryAdd(rngRegex, (match) =>
{
if (!int.TryParse(match.Groups["from"].ToString(), out var from))
from = 0;
if (!int.TryParse(match.Groups["to"].ToString(), out var to))
to = 0;
if (from == 0 && to == 0)
return rng.Next(0, 11).ToString();
if (from >= to)
return string.Empty;
return rng.Next(from, to + 1).ToString();
});
return this;
}
public ReplacementBuilder WithOverride(string key, Func<string> output)
{
_reps.AddOrUpdate(key, output, delegate { return output; });
return this;
}
public Replacer Build()
{
return new Replacer(_reps.Select(x => (x.Key, x.Value)).ToArray(), _regex.Select(x => (x.Key, x.Value)).ToArray());
}
public ReplacementBuilder WithProviders(IEnumerable<IPlaceholderProvider> phProviders)
{
foreach (var provider in phProviders)
{
foreach (var ovr in provider.GetPlaceholders())
{
_reps.TryAdd(ovr.Name, ovr.Func);
}
}
return this;
}
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace NadekoBot.Common.Replacements
{
public class Replacer
{
private readonly IEnumerable<(string Key, Func<string> Text)> _replacements;
private readonly IEnumerable<(Regex Regex, Func<Match, string> Replacement)> _regex;
public Replacer(IEnumerable<(string, Func<string>)> replacements, IEnumerable<(Regex, Func<Match, string>)> regex)
{
_replacements = replacements;
_regex = regex;
}
public string Replace(string input)
{
if (string.IsNullOrWhiteSpace(input))
return input;
foreach (var (Key, Text) in _replacements)
{
if (input.Contains(Key))
input = input.Replace(Key, Text(), StringComparison.InvariantCulture);
}
foreach (var item in _regex)
{
input = item.Regex.Replace(input, (m) => item.Replacement(m));
}
return input;
}
public CREmbed Replace(CREmbed embedData)
{
embedData.PlainText = Replace(embedData.PlainText);
embedData.Description = Replace(embedData.Description);
embedData.Title = Replace(embedData.Title);
embedData.Thumbnail = Replace(embedData.Thumbnail);
embedData.Image = Replace(embedData.Image);
if (embedData.Author != null)
{
embedData.Author.Name = Replace(embedData.Author.Name);
embedData.Author.IconUrl = Replace(embedData.Author.IconUrl);
}
if (embedData.Fields != null)
foreach (var f in embedData.Fields)
{
f.Name = Replace(f.Name);
f.Value = Replace(f.Value);
}
if (embedData.Footer != null)
{
embedData.Footer.Text = Replace(embedData.Footer.Text);
embedData.Footer.IconUrl = Replace(embedData.Footer.IconUrl);
}
return embedData;
}
}
}

View File

@@ -0,0 +1,16 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
namespace NadekoBot.Common
{
public class RequireObjectPropertiesContractResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
contract.ItemRequired = Required.DisallowNull;
return contract;
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using Discord;
namespace NadekoBot.Common.ShardCom
{
public class ShardComMessage
{
public int ShardId { get; set; }
public ConnectionState ConnectionState { get; set; }
public int Guilds { get; set; }
public DateTime Time { get; set; }
public ShardComMessage Clone() =>
new ShardComMessage
{
ShardId = ShardId,
ConnectionState = ConnectionState,
Guilds = Guilds,
Time = Time,
};
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
using NadekoBot.Core.Services;
namespace NadekoBot.Common.ShardCom
{
public class ShardComServer
{
private readonly IDataCache _cache;
public ShardComServer(IDataCache cache)
{
_cache = cache;
}
public void Start()
{
var sub = _cache.Redis.GetSubscriber();
sub.SubscribeAsync("shardcoord_send", (ch, data) =>
{
var _ = OnDataReceived(JsonConvert.DeserializeObject<ShardComMessage>(data));
}, StackExchange.Redis.CommandFlags.FireAndForget);
}
public event Func<ShardComMessage, Task> OnDataReceived = delegate { return Task.CompletedTask; };
}
}

View File

@@ -0,0 +1,63 @@
using System;
namespace NadekoBot.Core.Common
{
public struct ShmartNumber : IEquatable<ShmartNumber>
{
public long Value { get; }
public string Input { get; }
public ShmartNumber(long val, string input = null)
{
Value = val;
Input = input;
}
public static implicit operator ShmartNumber(long num)
{
return new ShmartNumber(num);
}
public static implicit operator long(ShmartNumber num)
{
return num.Value;
}
public static implicit operator ShmartNumber(int num)
{
return new ShmartNumber(num);
}
public override string ToString()
{
return Value.ToString();
}
public override bool Equals(object obj)
{
return obj is ShmartNumber sn
? Equals(sn)
: false;
}
public bool Equals(ShmartNumber other)
{
return other.Value == Value;
}
public override int GetHashCode()
{
return Value.GetHashCode() ^ Input.GetHashCode(StringComparison.InvariantCulture);
}
public static bool operator ==(ShmartNumber left, ShmartNumber right)
{
return left.Equals(right);
}
public static bool operator !=(ShmartNumber left, ShmartNumber right)
{
return !(left == right);
}
}
}

View File

@@ -0,0 +1,91 @@
using Discord;
using Discord.WebSocket;
using System;
using System.Threading.Tasks;
namespace NadekoBot.Common
{
public sealed class ReactionEventWrapper : IDisposable
{
public IUserMessage Message { get; }
public event Action<SocketReaction> OnReactionAdded = delegate { };
public event Action<SocketReaction> OnReactionRemoved = delegate { };
public event Action OnReactionsCleared = delegate { };
public ReactionEventWrapper(DiscordSocketClient client, IUserMessage msg)
{
Message = msg ?? throw new ArgumentNullException(nameof(msg));
_client = client;
_client.ReactionAdded += Discord_ReactionAdded;
_client.ReactionRemoved += Discord_ReactionRemoved;
_client.ReactionsCleared += Discord_ReactionsCleared;
}
private Task Discord_ReactionsCleared(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel channel)
{
Task.Run(() =>
{
try
{
if (msg.Id == Message.Id)
OnReactionsCleared?.Invoke();
}
catch { }
});
return Task.CompletedTask;
}
private Task Discord_ReactionRemoved(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel channel, SocketReaction reaction)
{
Task.Run(() =>
{
try
{
if (msg.Id == Message.Id)
OnReactionRemoved?.Invoke(reaction);
}
catch { }
});
return Task.CompletedTask;
}
private Task Discord_ReactionAdded(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel channel, SocketReaction reaction)
{
Task.Run(() =>
{
try
{
if (msg.Id == Message.Id)
OnReactionAdded?.Invoke(reaction);
}
catch { }
});
return Task.CompletedTask;
}
public void UnsubAll()
{
_client.ReactionAdded -= Discord_ReactionAdded;
_client.ReactionRemoved -= Discord_ReactionRemoved;
_client.ReactionsCleared -= Discord_ReactionsCleared;
OnReactionAdded = null;
OnReactionRemoved = null;
OnReactionsCleared = null;
}
private bool disposing = false;
private readonly DiscordSocketClient _client;
public void Dispose()
{
if (disposing)
return;
disposing = true;
UnsubAll();
}
}
}

View File

@@ -0,0 +1,9 @@
namespace NadekoBot.Common.TypeReaders
{
public enum AddRemove
{
Add = int.MinValue,
Rem = int.MinValue + 1,
Rm = int.MinValue + 1,
}
}

View File

@@ -0,0 +1,87 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Discord.Commands;
using NadekoBot.Core.Services;
using NadekoBot.Modules.CustomReactions.Services;
using NadekoBot.Core.Common.TypeReaders;
using Discord.WebSocket;
using Microsoft.Extensions.DependencyInjection;
namespace NadekoBot.Common.TypeReaders
{
public class CommandTypeReader : NadekoTypeReader<CommandInfo>
{
public CommandTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
{
}
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{
var _cmds = services.GetService<CommandService>();
var _cmdHandler = services.GetService<CommandHandler>();
input = input.ToUpperInvariant();
var prefix = _cmdHandler.GetPrefix(context.Guild);
if (!input.StartsWith(prefix.ToUpperInvariant(), StringComparison.InvariantCulture))
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such command found."));
input = input.Substring(prefix.Length);
var cmd = _cmds.Commands.FirstOrDefault(c =>
c.Aliases.Select(a => a.ToUpperInvariant()).Contains(input));
if (cmd == null)
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such command found."));
return Task.FromResult(TypeReaderResult.FromSuccess(cmd));
}
}
public class CommandOrCrTypeReader : NadekoTypeReader<CommandOrCrInfo>
{
private readonly DiscordSocketClient _client;
private readonly CommandService _cmds;
public CommandOrCrTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
{
_client = client;
_cmds = cmds;
}
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{
input = input.ToUpperInvariant();
var _crs = services.GetService<CustomReactionsService>();
if (_crs.ReactionExists(context.Guild?.Id, input))
{
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input, CommandOrCrInfo.Type.Custom));
}
var cmd = await new CommandTypeReader(_client, _cmds).ReadAsync(context, input, services).ConfigureAwait(false);
if (cmd.IsSuccess)
{
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Name, CommandOrCrInfo.Type.Normal));
}
return TypeReaderResult.FromError(CommandError.ParseFailed, "No such command or cr found.");
}
}
public class CommandOrCrInfo
{
public enum Type
{
Normal,
Custom,
}
public string Name { get; set; }
public Type CmdType { get; set; }
public bool IsCustom => CmdType == Type.Custom;
public CommandOrCrInfo(string input, Type type)
{
this.Name = input;
this.CmdType = type;
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Threading.Tasks;
using Discord.Commands;
using NadekoBot.Modules.Administration.Services;
using NadekoBot.Core.Common.TypeReaders;
using Discord.WebSocket;
using Microsoft.Extensions.DependencyInjection;
namespace NadekoBot.Common.TypeReaders
{
public class GuildDateTimeTypeReader : NadekoTypeReader<GuildDateTime>
{
public GuildDateTimeTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
{
}
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{
var gdt = Parse(services, context.Guild.Id, input);
if(gdt == null)
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Input string is in an incorrect format."));
return Task.FromResult(TypeReaderResult.FromSuccess(gdt));
}
public static GuildDateTime Parse(IServiceProvider services, ulong guildId, string input)
{
var _gts = services.GetService<GuildTimezoneService>();
if (!DateTime.TryParse(input, out var dt))
return null;
var tz = _gts.GetTimeZoneOrUtc(guildId);
return new GuildDateTime(tz, dt);
}
}
public class GuildDateTime
{
public TimeZoneInfo Timezone { get; }
public DateTime CurrentGuildTime { get; }
public DateTime InputTime { get; }
public DateTime InputTimeUtc { get; }
private GuildDateTime() { }
public GuildDateTime(TimeZoneInfo guildTimezone, DateTime inputTime)
{
var now = DateTime.UtcNow;
Timezone = guildTimezone;
CurrentGuildTime = TimeZoneInfo.ConvertTime(now, TimeZoneInfo.Utc, Timezone);
InputTime = inputTime;
InputTimeUtc = TimeZoneInfo.ConvertTime(inputTime, Timezone, TimeZoneInfo.Utc);
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Discord.Commands;
using Discord.WebSocket;
using NadekoBot.Core.Common.TypeReaders;
using Discord;
namespace NadekoBot.Common.TypeReaders
{
public class GuildTypeReader : NadekoTypeReader<IGuild>
{
private readonly DiscordSocketClient _client;
public GuildTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
{
_client = client;
}
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider _)
{
input = input.Trim().ToUpperInvariant();
var guilds = _client.Guilds;
var guild = guilds.FirstOrDefault(g => g.Id.ToString().Trim().ToUpperInvariant() == input) ?? //by id
guilds.FirstOrDefault(g => g.Name.Trim().ToUpperInvariant() == input); //by name
if (guild != null)
return Task.FromResult(TypeReaderResult.FromSuccess(guild));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No guild by that name or Id found"));
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Threading.Tasks;
using Discord.Commands;
using Discord.WebSocket;
namespace NadekoBot.Core.Common.TypeReaders
{
public class KwumTypeReader : NadekoTypeReader<kwum>
{
public KwumTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
{
}
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{
if (kwum.TryParse(input, out var val))
return Task.FromResult(TypeReaderResult.FromSuccess(val));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Input is not a valid kwum"));
}
}
}

View File

@@ -0,0 +1,27 @@
namespace NadekoBot.Common.TypeReaders.Models
{
public class PermissionAction
{
public static PermissionAction Enable => new PermissionAction(true);
public static PermissionAction Disable => new PermissionAction(false);
public bool Value { get; }
public PermissionAction(bool value)
{
this.Value = value;
}
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
return this.Value == ((PermissionAction)obj).Value;
}
public override int GetHashCode() => Value.GetHashCode();
}
}

View File

@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace NadekoBot.Core.Common.TypeReaders.Models
{
public class StoopidTime
{
public string Input { get; set; }
public TimeSpan Time { get; set; }
private static readonly Regex _regex = new Regex(
@"^(?:(?<months>\d)mo)?(?:(?<weeks>\d{1,2})w)?(?:(?<days>\d{1,2})d)?(?:(?<hours>\d{1,4})h)?(?:(?<minutes>\d{1,5})m)?(?:(?<seconds>\d{1,6})s)?$",
RegexOptions.Compiled | RegexOptions.Multiline);
private StoopidTime() { }
public static StoopidTime FromInput(string input)
{
var m = _regex.Match(input);
if (m.Length == 0)
{
throw new ArgumentException("Invalid string input format.");
}
string output = "";
var namesAndValues = new Dictionary<string, int>();
foreach (var groupName in _regex.GetGroupNames())
{
if (groupName == "0") continue;
if (!int.TryParse(m.Groups[groupName].Value, out var value))
{
namesAndValues[groupName] = 0;
continue;
}
if (value < 1)
{
throw new ArgumentException($"Invalid {groupName} value.");
}
namesAndValues[groupName] = value;
output += m.Groups[groupName].Value + " " + groupName + " ";
}
var ts = new TimeSpan(30 * namesAndValues["months"] +
7 * namesAndValues["weeks"] +
namesAndValues["days"],
namesAndValues["hours"],
namesAndValues["minutes"],
namesAndValues["seconds"]);
if (ts > TimeSpan.FromDays(90))
{
throw new ArgumentException("Time is too long.");
}
return new StoopidTime()
{
Input = input,
Time = ts,
};
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Discord.Commands;
using NadekoBot.Extensions;
using NadekoBot.Core.Common.TypeReaders;
using Discord.WebSocket;
namespace NadekoBot.Common.TypeReaders
{
public class ModuleTypeReader : NadekoTypeReader<ModuleInfo>
{
private readonly CommandService _cmds;
public ModuleTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
{
_cmds = cmds;
}
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider _)
{
input = input.ToUpperInvariant();
var module = _cmds.Modules.GroupBy(m => m.GetTopLevelModule()).FirstOrDefault(m => m.Key.Name.ToUpperInvariant() == input)?.Key;
if (module == null)
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such module found."));
return Task.FromResult(TypeReaderResult.FromSuccess(module));
}
}
public class ModuleOrCrTypeReader : NadekoTypeReader<ModuleOrCrInfo>
{
private readonly CommandService _cmds;
public ModuleOrCrTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
{
_cmds = cmds;
}
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider _)
{
input = input.ToUpperInvariant();
var module = _cmds.Modules.GroupBy(m => m.GetTopLevelModule()).FirstOrDefault(m => m.Key.Name.ToUpperInvariant() == input)?.Key;
if (module == null && input != "ACTUALCUSTOMREACTIONS")
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such module found."));
return Task.FromResult(TypeReaderResult.FromSuccess(new ModuleOrCrInfo
{
Name = input,
}));
}
}
public class ModuleOrCrInfo
{
public string Name { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using Discord.Commands;
using Discord.WebSocket;
namespace NadekoBot.Core.Common.TypeReaders
{
public abstract class NadekoTypeReader<T> : TypeReader
{
private readonly DiscordSocketClient _client;
private readonly CommandService _cmds;
private NadekoTypeReader() { }
protected NadekoTypeReader(DiscordSocketClient client, CommandService cmds)
{
_client = client;
_cmds = cmds;
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Threading.Tasks;
using Discord.Commands;
using Discord.WebSocket;
using NadekoBot.Common.TypeReaders.Models;
using NadekoBot.Core.Common.TypeReaders;
namespace NadekoBot.Common.TypeReaders
{
/// <summary>
/// Used instead of bool for more flexible keywords for true/false only in the permission module
/// </summary>
public class PermissionActionTypeReader : NadekoTypeReader<PermissionAction>
{
public PermissionActionTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
{
}
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider _)
{
input = input.ToUpperInvariant();
switch (input)
{
case "1":
case "T":
case "TRUE":
case "ENABLE":
case "ENABLED":
case "ALLOW":
case "PERMIT":
case "UNBAN":
return Task.FromResult(TypeReaderResult.FromSuccess(PermissionAction.Enable));
case "0":
case "F":
case "FALSE":
case "DENY":
case "DISABLE":
case "DISABLED":
case "DISALLOW":
case "BAN":
return Task.FromResult(TypeReaderResult.FromSuccess(PermissionAction.Disable));
default:
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Did not receive a valid boolean value"));
}
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Threading.Tasks;
using Discord.Commands;
using Discord.WebSocket;
using SixLabors.ImageSharp;
namespace NadekoBot.Core.Common.TypeReaders
{
public class Rgba32TypeReader : NadekoTypeReader<Color>
{
public Rgba32TypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
{
}
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{
await Task.Yield();
input = input.Replace("#", "", StringComparison.InvariantCulture);
try
{
return TypeReaderResult.FromSuccess(Color.ParseHex(input));
}
catch
{
return TypeReaderResult.FromError(CommandError.ParseFailed, "Parameter is not a valid color hex.");
}
}
}
}

View File

@@ -0,0 +1,109 @@
using Discord.Commands;
using Discord.WebSocket;
using Microsoft.Extensions.DependencyInjection;
using NadekoBot.Core.Services;
using System;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using NadekoBot.Core.Modules.Gambling.Services;
namespace NadekoBot.Core.Common.TypeReaders
{
public class ShmartNumberTypeReader : NadekoTypeReader<ShmartNumber>
{
public ShmartNumberTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
{
}
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{
await Task.Yield();
if (string.IsNullOrWhiteSpace(input))
return TypeReaderResult.FromError(CommandError.ParseFailed, "Input is empty.");
var i = input.Trim().ToUpperInvariant();
i = i.Replace("K", "000");
//can't add m because it will conflict with max atm
if (TryHandlePercentage(services, context, i, out var num))
return TypeReaderResult.FromSuccess(new ShmartNumber(num, i));
try
{
var expr = new NCalc.Expression(i, NCalc.EvaluateOptions.IgnoreCase);
expr.EvaluateParameter += (str, ev) => EvaluateParam(str, ev, context, services);
var lon = (long)(decimal.Parse(expr.Evaluate().ToString()));
return TypeReaderResult.FromSuccess(new ShmartNumber(lon, input));
}
catch (Exception)
{
return TypeReaderResult.FromError(CommandError.ParseFailed, $"Invalid input: {input}");
}
}
private static void EvaluateParam(string name, NCalc.ParameterArgs args, ICommandContext ctx, IServiceProvider svc)
{
switch (name.ToUpperInvariant())
{
case "PI":
args.Result = Math.PI;
break;
case "E":
args.Result = Math.E;
break;
case "ALL":
case "ALLIN":
args.Result = Cur(svc, ctx);
break;
case "HALF":
args.Result = Cur(svc, ctx) / 2;
break;
case "MAX":
args.Result = Max(svc, ctx);
break;
default:
break;
}
}
private static readonly Regex percentRegex = new Regex(@"^((?<num>100|\d{1,2})%)$", RegexOptions.Compiled);
private static long Cur(IServiceProvider services, ICommandContext ctx)
{
var _db = services.GetService<DbService>();
long cur;
using (var uow = _db.GetDbContext())
{
cur = uow.DiscordUsers.GetUserCurrency(ctx.User.Id);
uow.SaveChanges();
}
return cur;
}
private static long Max(IServiceProvider services, ICommandContext ctx)
{
var settings = services.GetService<GamblingConfigService>().Data;
var max = settings.MaxBet;
return max == 0
? Cur(services, ctx)
: max;
}
private static bool TryHandlePercentage(IServiceProvider services, ICommandContext ctx, string input, out long num)
{
num = 0;
var m = percentRegex.Match(input);
if (m.Captures.Count != 0)
{
if (!long.TryParse(m.Groups["num"].ToString(), out var percent))
return false;
num = (long)(Cur(services, ctx) * (percent / 100.0f));
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,30 @@
using Discord.Commands;
using Discord.WebSocket;
using NadekoBot.Core.Common.TypeReaders.Models;
using System;
using System.Threading.Tasks;
namespace NadekoBot.Core.Common.TypeReaders
{
public class StoopidTimeTypeReader : NadekoTypeReader<StoopidTime>
{
public StoopidTimeTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
{
}
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{
if (string.IsNullOrWhiteSpace(input))
return Task.FromResult(TypeReaderResult.FromError(CommandError.Unsuccessful, "Input is empty."));
try
{
var time = StoopidTime.FromInput(input);
return Task.FromResult(TypeReaderResult.FromSuccess(time));
}
catch (Exception ex)
{
return Task.FromResult(TypeReaderResult.FromError(CommandError.Exception, ex.Message));
}
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
namespace NadekoBot.Common.Yml
{
public class CommentAttribute : Attribute
{
public string Comment { get; }
public CommentAttribute(string comment)
{
Comment = comment;
}
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using YamlDotNet.Core;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.TypeInspectors;
namespace NadekoBot.Common.Yml
{
public class CommentGatheringTypeInspector : TypeInspectorSkeleton
{
private readonly ITypeInspector innerTypeDescriptor;
public CommentGatheringTypeInspector(ITypeInspector innerTypeDescriptor)
{
this.innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException("innerTypeDescriptor");
}
public override IEnumerable<IPropertyDescriptor> GetProperties(Type type, object container)
{
return innerTypeDescriptor
.GetProperties(type, container)
.Select(d => new CommentsPropertyDescriptor(d));
}
private sealed class CommentsPropertyDescriptor : IPropertyDescriptor
{
private readonly IPropertyDescriptor baseDescriptor;
public CommentsPropertyDescriptor(IPropertyDescriptor baseDescriptor)
{
this.baseDescriptor = baseDescriptor;
Name = baseDescriptor.Name;
}
public string Name { get; set; }
public Type Type { get { return baseDescriptor.Type; } }
public Type TypeOverride {
get { return baseDescriptor.TypeOverride; }
set { baseDescriptor.TypeOverride = value; }
}
public int Order { get; set; }
public ScalarStyle ScalarStyle {
get { return baseDescriptor.ScalarStyle; }
set { baseDescriptor.ScalarStyle = value; }
}
public bool CanWrite { get { return baseDescriptor.CanWrite; } }
public void Write(object target, object value)
{
baseDescriptor.Write(target, value);
}
public T GetCustomAttribute<T>() where T : Attribute
{
return baseDescriptor.GetCustomAttribute<T>();
}
public IObjectDescriptor Read(object target)
{
var comment = baseDescriptor.GetCustomAttribute<CommentAttribute>();
return comment != null
? new CommentsObjectDescriptor(baseDescriptor.Read(target), comment.Comment)
: baseDescriptor.Read(target);
}
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using YamlDotNet.Core;
using YamlDotNet.Serialization;
namespace NadekoBot.Common.Yml
{
public sealed class CommentsObjectDescriptor : IObjectDescriptor
{
private readonly IObjectDescriptor innerDescriptor;
public CommentsObjectDescriptor(IObjectDescriptor innerDescriptor, string comment)
{
this.innerDescriptor = innerDescriptor;
this.Comment = comment;
}
public string Comment { get; private set; }
public object Value { get { return innerDescriptor.Value; } }
public Type Type { get { return innerDescriptor.Type; } }
public Type StaticType { get { return innerDescriptor.StaticType; } }
public ScalarStyle ScalarStyle { get { return innerDescriptor.ScalarStyle; } }
}
}

View File

@@ -0,0 +1,26 @@
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.ObjectGraphVisitors;
namespace NadekoBot.Common.Yml
{
public class CommentsObjectGraphVisitor : ChainedObjectGraphVisitor
{
public CommentsObjectGraphVisitor(IObjectGraphVisitor<IEmitter> nextVisitor)
: base(nextVisitor)
{
}
public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context)
{
var commentsDescriptor = value as CommentsObjectDescriptor;
if (commentsDescriptor != null && !string.IsNullOrWhiteSpace(commentsDescriptor.Comment))
{
context.Emit(new Comment(commentsDescriptor.Comment.Replace("\n", "\n# "), false));
}
return base.EnterMapping(key, value, context);
}
}
}

View File

@@ -0,0 +1,32 @@
using YamlDotNet.Core;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.EventEmitters;
namespace NadekoBot.Common.Yml
{
public class MultilineScalarFlowStyleEmitter : ChainedEventEmitter
{
public MultilineScalarFlowStyleEmitter(IEventEmitter nextEmitter)
: base(nextEmitter) { }
public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter)
{
if (typeof(string).IsAssignableFrom(eventInfo.Source.Type))
{
string value = eventInfo.Source.Value as string;
if (!string.IsNullOrEmpty(value))
{
bool isMultiLine = value.IndexOfAny(new char[] { '\r', '\n', '\x85', '\x2028', '\x2029' }) >= 0;
if (isMultiLine)
eventInfo = new ScalarEventInfo(eventInfo.Source)
{
Style = ScalarStyle.Literal,
};
}
}
nextEmitter.Emit(eventInfo, emitter);
}
}
}

View File

@@ -0,0 +1,52 @@
using System;
using System.Globalization;
using SixLabors.ImageSharp.PixelFormats;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace NadekoBot.Common.Yml
{
public class Rgba32Converter : IYamlTypeConverter
{
public bool Accepts(Type type)
{
return type == typeof(Rgba32);
}
public object ReadYaml(IParser parser, Type type)
{
var scalar = parser.Consume<Scalar>();
var result = Rgba32.ParseHex(scalar.Value);
return result;
}
public void WriteYaml(IEmitter emitter, object value, Type type)
{
var color = (Rgba32)value;
var val = (uint) (color.B << 0 | color.G << 8 | color.R << 16);
emitter.Emit(new Scalar(val.ToString("X6").ToLower()));
}
}
public class CultureInfoConverter : IYamlTypeConverter
{
public bool Accepts(Type type)
{
return type == typeof(CultureInfo);
}
public object ReadYaml(IParser parser, Type type)
{
var scalar = parser.Consume<Scalar>();
var result = new CultureInfo(scalar.Value);
return result;
}
public void WriteYaml(IEmitter emitter, object value, Type type)
{
var ci = (CultureInfo)value;
emitter.Emit(new Scalar(ci.Name));
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace NadekoBot.Common.Yml
{
public class UriConverter : IYamlTypeConverter
{
public bool Accepts(Type type)
{
return type == typeof(Uri);
}
public object ReadYaml(IParser parser, Type type)
{
var scalar = parser.Consume<Scalar>();
var result = new Uri(scalar.Value);
return result;
}
public void WriteYaml(IEmitter emitter, object value, Type type)
{
var uri = (Uri)value;
emitter.Emit(new Scalar(uri.ToString()));
}
}
}

View File

@@ -0,0 +1,25 @@
using YamlDotNet.Serialization;
namespace NadekoBot.Common.Yml
{
public class Yaml
{
public static ISerializer Serializer => new SerializerBuilder()
.WithTypeInspector(inner => new CommentGatheringTypeInspector(inner))
.WithEmissionPhaseObjectGraphVisitor(args => new CommentsObjectGraphVisitor(args.InnerVisitor))
.WithEventEmitter(args => new MultilineScalarFlowStyleEmitter(args))
.WithNamingConvention(YamlDotNet.Serialization.NamingConventions.CamelCaseNamingConvention.Instance)
.WithIndentedSequences()
.WithTypeConverter(new Rgba32Converter())
.WithTypeConverter(new CultureInfoConverter())
.WithTypeConverter(new UriConverter())
.Build();
public static IDeserializer Deserializer => new DeserializerBuilder()
.WithNamingConvention(YamlDotNet.Serialization.NamingConventions.CamelCaseNamingConvention.Instance)
.WithTypeConverter(new Rgba32Converter())
.WithTypeConverter(new CultureInfoConverter())
.WithTypeConverter(new UriConverter())
.Build();
}
}

View File

@@ -0,0 +1,58 @@
namespace NadekoBot.Common.Yml
{
public class YamlHelper
{
// https://github.com/aaubry/YamlDotNet/blob/0f4cc205e8b2dd8ef6589d96de32bf608a687c6f/YamlDotNet/Core/Scanner.cs#L1687
/// <summary>
/// This is modified code from yamldotnet's repo which handles parsing unicode code points
/// it is needed as yamldotnet doesn't support unescaped unicode characters
/// </summary>
/// <param name="point">Unicode code point</param>
/// <returns>Actual character</returns>
public static string UnescapeUnicodeCodePoint(string point)
{
var character = 0;
// Scan the character value.
foreach(var c in point)
{
if (!IsHex(c))
{
return point;
}
character = (character << 4) + AsHex(c);
}
// Check the value and write the character.
if (character >= 0xD800 && character <= 0xDFFF || character > 0x10FFFF)
{
return point;
}
return char.ConvertFromUtf32(character);
}
public static bool IsHex(char c)
{
return
(c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'F') ||
(c >= 'a' && c <= 'f');
}
public static int AsHex(char c)
{
if (c <= '9')
{
return c - '0';
}
if (c <= 'F')
{
return c - 'A' + 10;
}
return c - 'a' + 10;
}
}
}

View File

@@ -0,0 +1,759 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using NadekoBot.Core.Services.Database;
namespace NadekoBot.Migrations
{
[DbContext(typeof(NadekoContext))]
[Migration("20161011200458_first")]
partial class first
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
modelBuilder
.HasAnnotation("ProductVersion", "1.0.0-rtm-21431");
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<ulong>("ItemId");
b.Property<int>("Type");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("BlacklistItem");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BotConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("BufferSize");
b.Property<float>("CurrencyGenerationChance");
b.Property<int>("CurrencyGenerationCooldown");
b.Property<string>("CurrencyName");
b.Property<string>("CurrencyPluralName");
b.Property<string>("CurrencySign");
b.Property<string>("DMHelpString");
b.Property<bool>("ForwardMessages");
b.Property<bool>("ForwardToAllOwners");
b.Property<string>("HelpString");
b.Property<int>("MigrationVersion");
b.Property<string>("RemindMessageFormat");
b.Property<bool>("RotatingStatuses");
b.HasKey("Id");
b.ToTable("BotConfig");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("BaseDestroyed");
b.Property<string>("CallUser");
b.Property<int>("ClashWarId");
b.Property<int>("Stars");
b.Property<DateTime>("TimeAdded");
b.HasKey("Id");
b.HasIndex("ClashWarId");
b.ToTable("ClashCallers");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashWar", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<string>("EnemyClan");
b.Property<ulong>("GuildId");
b.Property<int>("Size");
b.Property<DateTime>("StartedAt");
b.Property<int>("WarState");
b.HasKey("Id");
b.ToTable("ClashOfClans");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("CommandName");
b.Property<int?>("GuildConfigId");
b.Property<int>("Seconds");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("CommandCooldown");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ConvertUnit", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("InternalTrigger");
b.Property<decimal>("Modifier");
b.Property<string>("UnitType");
b.HasKey("Id");
b.ToTable("ConversionUnits");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Currency", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Currency");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CustomReaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong?>("GuildId");
b.Property<bool>("IsRegex");
b.Property<bool>("OwnerOnly");
b.Property<string>("Response");
b.Property<string>("Trigger");
b.HasKey("Id");
b.ToTable("CustomReactions");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Donator", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Amount");
b.Property<string>("Name");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Donators");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Text");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("EightBallResponses");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<int?>("GuildConfigId1");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.HasIndex("GuildConfigId1");
b.ToTable("FilterChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<string>("Word");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FilteredWord");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<ulong>("GuildId");
b.Property<int>("Type");
b.Property<string>("Username");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FollowedStream");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("GCChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AutoAssignRoleId");
b.Property<bool>("AutoDeleteByeMessages");
b.Property<bool>("AutoDeleteGreetMessages");
b.Property<int>("AutoDeleteGreetMessagesTimer");
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
b.Property<ulong>("ByeMessageChannelId");
b.Property<string>("ChannelByeMessageText");
b.Property<string>("ChannelGreetMessageText");
b.Property<float>("DefaultMusicVolume");
b.Property<bool>("DeleteMessageOnCommand");
b.Property<string>("DmGreetMessageText");
b.Property<bool>("ExclusiveSelfAssignedRoles");
b.Property<bool>("FilterInvites");
b.Property<bool>("FilterWords");
b.Property<ulong>("GreetMessageChannelId");
b.Property<ulong>("GuildId");
b.Property<int?>("LogSettingId");
b.Property<string>("PermissionRole");
b.Property<int?>("RootPermissionId");
b.Property<bool>("SendChannelByeMessage");
b.Property<bool>("SendChannelGreetMessage");
b.Property<bool>("SendDmGreetMessage");
b.Property<bool>("VerbosePermissions");
b.Property<bool>("VoicePlusTextEnabled");
b.HasKey("Id");
b.HasIndex("GuildId")
.IsUnique();
b.HasIndex("LogSettingId");
b.HasIndex("RootPermissionId");
b.ToTable("GuildConfigs");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredLogChannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredVoicePresenceCHannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.LogSetting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("ChannelCreated");
b.Property<bool>("ChannelDestroyed");
b.Property<ulong>("ChannelId");
b.Property<bool>("ChannelUpdated");
b.Property<bool>("IsLogging");
b.Property<bool>("LogUserPresence");
b.Property<bool>("LogVoicePresence");
b.Property<bool>("MessageDeleted");
b.Property<bool>("MessageUpdated");
b.Property<bool>("UserBanned");
b.Property<bool>("UserJoined");
b.Property<bool>("UserLeft");
b.Property<ulong>("UserPresenceChannelId");
b.Property<bool>("UserUnbanned");
b.Property<bool>("UserUpdated");
b.Property<ulong>("VoicePresenceChannelId");
b.HasKey("Id");
b.ToTable("LogSettings");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("ModuleName");
b.Property<string>("Prefix");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("ModulePrefixes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.MusicPlaylist", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Author");
b.Property<ulong>("AuthorId");
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("MusicPlaylists");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("NextId");
b.Property<int>("PrimaryTarget");
b.Property<ulong>("PrimaryTargetId");
b.Property<int>("SecondaryTarget");
b.Property<string>("SecondaryTargetName");
b.Property<bool>("State");
b.HasKey("Id");
b.HasIndex("NextId")
.IsUnique();
b.ToTable("Permission");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Status");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("PlayingStatus");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("MusicPlaylistId");
b.Property<string>("Provider");
b.Property<int>("ProviderType");
b.Property<string>("Query");
b.Property<string>("Title");
b.Property<string>("Uri");
b.HasKey("Id");
b.HasIndex("MusicPlaylistId");
b.ToTable("PlaylistSong");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Quote", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AuthorId");
b.Property<string>("AuthorName")
.IsRequired();
b.Property<ulong>("GuildId");
b.Property<string>("Keyword")
.IsRequired();
b.Property<string>("Text")
.IsRequired();
b.HasKey("Id");
b.ToTable("Quotes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Icon");
b.Property<string>("Name");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("RaceAnimals");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Reminder", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<bool>("IsPrivate");
b.Property<string>("Message");
b.Property<ulong>("ServerId");
b.Property<ulong>("UserId");
b.Property<DateTime>("When");
b.HasKey("Id");
b.ToTable("Reminders");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Repeater", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<ulong>("GuildId");
b.Property<TimeSpan>("Interval");
b.Property<string>("Message");
b.HasKey("Id");
b.HasIndex("ChannelId")
.IsUnique();
b.ToTable("Repeaters");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.SelfAssignedRole", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("GuildId");
b.Property<ulong>("RoleId");
b.HasKey("Id");
b.HasIndex("GuildId", "RoleId")
.IsUnique();
b.ToTable("SelfAssignableRoles");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("Blacklist")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.ClashWar", "ClashWar")
.WithMany("Bases")
.HasForeignKey("ClashWarId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("CommandCooldowns")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("EightBallResponses")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterInvitesChannelIds")
.HasForeignKey("GuildConfigId");
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterWordsChannelIds")
.HasForeignKey("GuildConfigId1");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilteredWords")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FollowedStreams")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("GenerateCurrencyChannelIds")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany()
.HasForeignKey("LogSettingId");
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "RootPermission")
.WithMany()
.HasForeignKey("RootPermissionId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredChannels")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredVoicePresenceChannelIds")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("ModulePrefixes")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "Next")
.WithOne("Previous")
.HasForeignKey("NadekoBot.Core.Services.Database.Models.Permission", "NextId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RotatingStatusMessages")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.MusicPlaylist")
.WithMany("Songs")
.HasForeignKey("MusicPlaylistId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RaceAnimals")
.HasForeignKey("BotConfigId");
});
}
}
}

View File

@@ -0,0 +1,804 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class first : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "BotConfig",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
BufferSize = table.Column<ulong>(nullable: false),
CurrencyGenerationChance = table.Column<float>(nullable: false),
CurrencyGenerationCooldown = table.Column<int>(nullable: false),
CurrencyName = table.Column<string>(nullable: true),
CurrencyPluralName = table.Column<string>(nullable: true),
CurrencySign = table.Column<string>(nullable: true),
DMHelpString = table.Column<string>(nullable: true),
ForwardMessages = table.Column<bool>(nullable: false),
ForwardToAllOwners = table.Column<bool>(nullable: false),
HelpString = table.Column<string>(nullable: true),
MigrationVersion = table.Column<int>(nullable: false),
RemindMessageFormat = table.Column<string>(nullable: true),
RotatingStatuses = table.Column<bool>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_BotConfig", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ClashOfClans",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
ChannelId = table.Column<ulong>(nullable: false),
EnemyClan = table.Column<string>(nullable: true),
GuildId = table.Column<ulong>(nullable: false),
Size = table.Column<int>(nullable: false),
StartedAt = table.Column<DateTime>(nullable: false),
WarState = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClashOfClans", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ConversionUnits",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
InternalTrigger = table.Column<string>(nullable: true),
Modifier = table.Column<decimal>(nullable: false),
UnitType = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ConversionUnits", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Currency",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
Amount = table.Column<long>(nullable: false),
UserId = table.Column<ulong>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Currency", x => x.Id);
});
migrationBuilder.CreateTable(
name: "CustomReactions",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
GuildId = table.Column<ulong>(nullable: true),
IsRegex = table.Column<bool>(nullable: false),
OwnerOnly = table.Column<bool>(nullable: false),
Response = table.Column<string>(nullable: true),
Trigger = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CustomReactions", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Donators",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
Amount = table.Column<int>(nullable: false),
Name = table.Column<string>(nullable: true),
UserId = table.Column<ulong>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Donators", x => x.Id);
});
migrationBuilder.CreateTable(
name: "LogSettings",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
ChannelCreated = table.Column<bool>(nullable: false),
ChannelDestroyed = table.Column<bool>(nullable: false),
ChannelId = table.Column<ulong>(nullable: false),
ChannelUpdated = table.Column<bool>(nullable: false),
IsLogging = table.Column<bool>(nullable: false),
LogUserPresence = table.Column<bool>(nullable: false),
LogVoicePresence = table.Column<bool>(nullable: false),
MessageDeleted = table.Column<bool>(nullable: false),
MessageUpdated = table.Column<bool>(nullable: false),
UserBanned = table.Column<bool>(nullable: false),
UserJoined = table.Column<bool>(nullable: false),
UserLeft = table.Column<bool>(nullable: false),
UserPresenceChannelId = table.Column<ulong>(nullable: false),
UserUnbanned = table.Column<bool>(nullable: false),
UserUpdated = table.Column<bool>(nullable: false),
VoicePresenceChannelId = table.Column<ulong>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LogSettings", x => x.Id);
});
migrationBuilder.CreateTable(
name: "MusicPlaylists",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
Author = table.Column<string>(nullable: true),
AuthorId = table.Column<ulong>(nullable: false),
Name = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_MusicPlaylists", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Permission",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
NextId = table.Column<int>(nullable: true),
PrimaryTarget = table.Column<int>(nullable: false),
PrimaryTargetId = table.Column<ulong>(nullable: false),
SecondaryTarget = table.Column<int>(nullable: false),
SecondaryTargetName = table.Column<string>(nullable: true),
State = table.Column<bool>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Permission", x => x.Id);
table.ForeignKey(
name: "FK_Permission_Permission_NextId",
column: x => x.NextId,
principalTable: "Permission",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Quotes",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
AuthorId = table.Column<ulong>(nullable: false),
AuthorName = table.Column<string>(nullable: false),
GuildId = table.Column<ulong>(nullable: false),
Keyword = table.Column<string>(nullable: false),
Text = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Quotes", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Reminders",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
ChannelId = table.Column<ulong>(nullable: false),
IsPrivate = table.Column<bool>(nullable: false),
Message = table.Column<string>(nullable: true),
ServerId = table.Column<ulong>(nullable: false),
UserId = table.Column<ulong>(nullable: false),
When = table.Column<DateTime>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Reminders", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Repeaters",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
ChannelId = table.Column<ulong>(nullable: false),
GuildId = table.Column<ulong>(nullable: false),
Interval = table.Column<TimeSpan>(nullable: false),
Message = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Repeaters", x => x.Id);
});
migrationBuilder.CreateTable(
name: "SelfAssignableRoles",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
GuildId = table.Column<ulong>(nullable: false),
RoleId = table.Column<ulong>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SelfAssignableRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "BlacklistItem",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
BotConfigId = table.Column<int>(nullable: true),
ItemId = table.Column<ulong>(nullable: false),
Type = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_BlacklistItem", x => x.Id);
table.ForeignKey(
name: "FK_BlacklistItem_BotConfig_BotConfigId",
column: x => x.BotConfigId,
principalTable: "BotConfig",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "EightBallResponses",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
BotConfigId = table.Column<int>(nullable: true),
Text = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_EightBallResponses", x => x.Id);
table.ForeignKey(
name: "FK_EightBallResponses_BotConfig_BotConfigId",
column: x => x.BotConfigId,
principalTable: "BotConfig",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "ModulePrefixes",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
BotConfigId = table.Column<int>(nullable: true),
ModuleName = table.Column<string>(nullable: true),
Prefix = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ModulePrefixes", x => x.Id);
table.ForeignKey(
name: "FK_ModulePrefixes_BotConfig_BotConfigId",
column: x => x.BotConfigId,
principalTable: "BotConfig",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "PlayingStatus",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
BotConfigId = table.Column<int>(nullable: true),
Status = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PlayingStatus", x => x.Id);
table.ForeignKey(
name: "FK_PlayingStatus_BotConfig_BotConfigId",
column: x => x.BotConfigId,
principalTable: "BotConfig",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "RaceAnimals",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
BotConfigId = table.Column<int>(nullable: true),
Icon = table.Column<string>(nullable: true),
Name = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_RaceAnimals", x => x.Id);
table.ForeignKey(
name: "FK_RaceAnimals_BotConfig_BotConfigId",
column: x => x.BotConfigId,
principalTable: "BotConfig",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "ClashCallers",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
BaseDestroyed = table.Column<bool>(nullable: false),
CallUser = table.Column<string>(nullable: true),
ClashWarId = table.Column<int>(nullable: false),
Stars = table.Column<int>(nullable: false),
TimeAdded = table.Column<DateTime>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClashCallers", x => x.Id);
table.ForeignKey(
name: "FK_ClashCallers_ClashOfClans_ClashWarId",
column: x => x.ClashWarId,
principalTable: "ClashOfClans",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "IgnoredLogChannels",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
ChannelId = table.Column<ulong>(nullable: false),
LogSettingId = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_IgnoredLogChannels", x => x.Id);
table.ForeignKey(
name: "FK_IgnoredLogChannels_LogSettings_LogSettingId",
column: x => x.LogSettingId,
principalTable: "LogSettings",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "IgnoredVoicePresenceCHannels",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
ChannelId = table.Column<ulong>(nullable: false),
LogSettingId = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_IgnoredVoicePresenceCHannels", x => x.Id);
table.ForeignKey(
name: "FK_IgnoredVoicePresenceCHannels_LogSettings_LogSettingId",
column: x => x.LogSettingId,
principalTable: "LogSettings",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "PlaylistSong",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
MusicPlaylistId = table.Column<int>(nullable: true),
Provider = table.Column<string>(nullable: true),
ProviderType = table.Column<int>(nullable: false),
Query = table.Column<string>(nullable: true),
Title = table.Column<string>(nullable: true),
Uri = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PlaylistSong", x => x.Id);
table.ForeignKey(
name: "FK_PlaylistSong_MusicPlaylists_MusicPlaylistId",
column: x => x.MusicPlaylistId,
principalTable: "MusicPlaylists",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "GuildConfigs",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
AutoAssignRoleId = table.Column<ulong>(nullable: false),
AutoDeleteByeMessages = table.Column<bool>(nullable: false),
AutoDeleteGreetMessages = table.Column<bool>(nullable: false),
AutoDeleteGreetMessagesTimer = table.Column<int>(nullable: false),
AutoDeleteSelfAssignedRoleMessages = table.Column<bool>(nullable: false),
ByeMessageChannelId = table.Column<ulong>(nullable: false),
ChannelByeMessageText = table.Column<string>(nullable: true),
ChannelGreetMessageText = table.Column<string>(nullable: true),
DefaultMusicVolume = table.Column<float>(nullable: false),
DeleteMessageOnCommand = table.Column<bool>(nullable: false),
DmGreetMessageText = table.Column<string>(nullable: true),
ExclusiveSelfAssignedRoles = table.Column<bool>(nullable: false),
FilterInvites = table.Column<bool>(nullable: false),
FilterWords = table.Column<bool>(nullable: false),
GreetMessageChannelId = table.Column<ulong>(nullable: false),
GuildId = table.Column<ulong>(nullable: false),
LogSettingId = table.Column<int>(nullable: true),
PermissionRole = table.Column<string>(nullable: true),
RootPermissionId = table.Column<int>(nullable: true),
SendChannelByeMessage = table.Column<bool>(nullable: false),
SendChannelGreetMessage = table.Column<bool>(nullable: false),
SendDmGreetMessage = table.Column<bool>(nullable: false),
VerbosePermissions = table.Column<bool>(nullable: false),
VoicePlusTextEnabled = table.Column<bool>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_GuildConfigs", x => x.Id);
table.ForeignKey(
name: "FK_GuildConfigs_LogSettings_LogSettingId",
column: x => x.LogSettingId,
principalTable: "LogSettings",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_GuildConfigs_Permission_RootPermissionId",
column: x => x.RootPermissionId,
principalTable: "Permission",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "CommandCooldown",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
CommandName = table.Column<string>(nullable: true),
GuildConfigId = table.Column<int>(nullable: true),
Seconds = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CommandCooldown", x => x.Id);
table.ForeignKey(
name: "FK_CommandCooldown_GuildConfigs_GuildConfigId",
column: x => x.GuildConfigId,
principalTable: "GuildConfigs",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "FilterChannelId",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
ChannelId = table.Column<ulong>(nullable: false),
GuildConfigId = table.Column<int>(nullable: true),
GuildConfigId1 = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_FilterChannelId", x => x.Id);
table.ForeignKey(
name: "FK_FilterChannelId_GuildConfigs_GuildConfigId",
column: x => x.GuildConfigId,
principalTable: "GuildConfigs",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_FilterChannelId_GuildConfigs_GuildConfigId1",
column: x => x.GuildConfigId1,
principalTable: "GuildConfigs",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "FilteredWord",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
GuildConfigId = table.Column<int>(nullable: true),
Word = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_FilteredWord", x => x.Id);
table.ForeignKey(
name: "FK_FilteredWord_GuildConfigs_GuildConfigId",
column: x => x.GuildConfigId,
principalTable: "GuildConfigs",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "FollowedStream",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
ChannelId = table.Column<ulong>(nullable: false),
GuildConfigId = table.Column<int>(nullable: true),
GuildId = table.Column<ulong>(nullable: false),
Type = table.Column<int>(nullable: false),
Username = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_FollowedStream", x => x.Id);
table.ForeignKey(
name: "FK_FollowedStream_GuildConfigs_GuildConfigId",
column: x => x.GuildConfigId,
principalTable: "GuildConfigs",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "GCChannelId",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
ChannelId = table.Column<ulong>(nullable: false),
GuildConfigId = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_GCChannelId", x => x.Id);
table.ForeignKey(
name: "FK_GCChannelId_GuildConfigs_GuildConfigId",
column: x => x.GuildConfigId,
principalTable: "GuildConfigs",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_BlacklistItem_BotConfigId",
table: "BlacklistItem",
column: "BotConfigId");
migrationBuilder.CreateIndex(
name: "IX_ClashCallers_ClashWarId",
table: "ClashCallers",
column: "ClashWarId");
migrationBuilder.CreateIndex(
name: "IX_CommandCooldown_GuildConfigId",
table: "CommandCooldown",
column: "GuildConfigId");
migrationBuilder.CreateIndex(
name: "IX_Currency_UserId",
table: "Currency",
column: "UserId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Donators_UserId",
table: "Donators",
column: "UserId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_EightBallResponses_BotConfigId",
table: "EightBallResponses",
column: "BotConfigId");
migrationBuilder.CreateIndex(
name: "IX_FilterChannelId_GuildConfigId",
table: "FilterChannelId",
column: "GuildConfigId");
migrationBuilder.CreateIndex(
name: "IX_FilterChannelId_GuildConfigId1",
table: "FilterChannelId",
column: "GuildConfigId1");
migrationBuilder.CreateIndex(
name: "IX_FilteredWord_GuildConfigId",
table: "FilteredWord",
column: "GuildConfigId");
migrationBuilder.CreateIndex(
name: "IX_FollowedStream_GuildConfigId",
table: "FollowedStream",
column: "GuildConfigId");
migrationBuilder.CreateIndex(
name: "IX_GCChannelId_GuildConfigId",
table: "GCChannelId",
column: "GuildConfigId");
migrationBuilder.CreateIndex(
name: "IX_GuildConfigs_GuildId",
table: "GuildConfigs",
column: "GuildId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_GuildConfigs_LogSettingId",
table: "GuildConfigs",
column: "LogSettingId");
migrationBuilder.CreateIndex(
name: "IX_GuildConfigs_RootPermissionId",
table: "GuildConfigs",
column: "RootPermissionId");
migrationBuilder.CreateIndex(
name: "IX_IgnoredLogChannels_LogSettingId",
table: "IgnoredLogChannels",
column: "LogSettingId");
migrationBuilder.CreateIndex(
name: "IX_IgnoredVoicePresenceCHannels_LogSettingId",
table: "IgnoredVoicePresenceCHannels",
column: "LogSettingId");
migrationBuilder.CreateIndex(
name: "IX_ModulePrefixes_BotConfigId",
table: "ModulePrefixes",
column: "BotConfigId");
migrationBuilder.CreateIndex(
name: "IX_Permission_NextId",
table: "Permission",
column: "NextId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_PlayingStatus_BotConfigId",
table: "PlayingStatus",
column: "BotConfigId");
migrationBuilder.CreateIndex(
name: "IX_PlaylistSong_MusicPlaylistId",
table: "PlaylistSong",
column: "MusicPlaylistId");
migrationBuilder.CreateIndex(
name: "IX_RaceAnimals_BotConfigId",
table: "RaceAnimals",
column: "BotConfigId");
migrationBuilder.CreateIndex(
name: "IX_Repeaters_channelId",
table: "Repeaters",
column: "ChannelId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_SelfAssignableRoles_GuildId_RoleId",
table: "SelfAssignableRoles",
columns: new[] { "GuildId", "RoleId" },
unique: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "BlacklistItem");
migrationBuilder.DropTable(
name: "ClashCallers");
migrationBuilder.DropTable(
name: "CommandCooldown");
migrationBuilder.DropTable(
name: "ConversionUnits");
migrationBuilder.DropTable(
name: "Currency");
migrationBuilder.DropTable(
name: "CustomReactions");
migrationBuilder.DropTable(
name: "Donators");
migrationBuilder.DropTable(
name: "EightBallResponses");
migrationBuilder.DropTable(
name: "FilterChannelId");
migrationBuilder.DropTable(
name: "FilteredWord");
migrationBuilder.DropTable(
name: "FollowedStream");
migrationBuilder.DropTable(
name: "GCChannelId");
migrationBuilder.DropTable(
name: "IgnoredLogChannels");
migrationBuilder.DropTable(
name: "IgnoredVoicePresenceCHannels");
migrationBuilder.DropTable(
name: "ModulePrefixes");
migrationBuilder.DropTable(
name: "PlayingStatus");
migrationBuilder.DropTable(
name: "PlaylistSong");
migrationBuilder.DropTable(
name: "Quotes");
migrationBuilder.DropTable(
name: "RaceAnimals");
migrationBuilder.DropTable(
name: "Reminders");
migrationBuilder.DropTable(
name: "Repeaters");
migrationBuilder.DropTable(
name: "SelfAssignableRoles");
migrationBuilder.DropTable(
name: "ClashOfClans");
migrationBuilder.DropTable(
name: "GuildConfigs");
migrationBuilder.DropTable(
name: "MusicPlaylists");
migrationBuilder.DropTable(
name: "BotConfig");
migrationBuilder.DropTable(
name: "LogSettings");
migrationBuilder.DropTable(
name: "Permission");
}
}
}

View File

@@ -0,0 +1,775 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using NadekoBot.Core.Services.Database;
namespace NadekoBot.Migrations
{
[DbContext(typeof(NadekoContext))]
[Migration("20161015005020_CurrencyTransaction")]
partial class CurrencyTransaction
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
modelBuilder
.HasAnnotation("ProductVersion", "1.0.0-rtm-21431");
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<ulong>("ItemId");
b.Property<int>("Type");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("BlacklistItem");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BotConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("BufferSize");
b.Property<float>("CurrencyGenerationChance");
b.Property<int>("CurrencyGenerationCooldown");
b.Property<string>("CurrencyName");
b.Property<string>("CurrencyPluralName");
b.Property<string>("CurrencySign");
b.Property<string>("DMHelpString");
b.Property<bool>("ForwardMessages");
b.Property<bool>("ForwardToAllOwners");
b.Property<string>("HelpString");
b.Property<int>("MigrationVersion");
b.Property<string>("RemindMessageFormat");
b.Property<bool>("RotatingStatuses");
b.HasKey("Id");
b.ToTable("BotConfig");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("BaseDestroyed");
b.Property<string>("CallUser");
b.Property<int>("ClashWarId");
b.Property<int>("Stars");
b.Property<DateTime>("TimeAdded");
b.HasKey("Id");
b.HasIndex("ClashWarId");
b.ToTable("ClashCallers");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashWar", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<string>("EnemyClan");
b.Property<ulong>("GuildId");
b.Property<int>("Size");
b.Property<DateTime>("StartedAt");
b.Property<int>("WarState");
b.HasKey("Id");
b.ToTable("ClashOfClans");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("CommandName");
b.Property<int?>("GuildConfigId");
b.Property<int>("Seconds");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("CommandCooldown");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ConvertUnit", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("InternalTrigger");
b.Property<decimal>("Modifier");
b.Property<string>("UnitType");
b.HasKey("Id");
b.ToTable("ConversionUnits");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Currency", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Currency");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CurrencyTransaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<string>("Reason");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.ToTable("CurrencyTransactions");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CustomReaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong?>("GuildId");
b.Property<bool>("IsRegex");
b.Property<bool>("OwnerOnly");
b.Property<string>("Response");
b.Property<string>("Trigger");
b.HasKey("Id");
b.ToTable("CustomReactions");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Donator", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Amount");
b.Property<string>("Name");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Donators");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Text");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("EightBallResponses");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<int?>("GuildConfigId1");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.HasIndex("GuildConfigId1");
b.ToTable("FilterChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<string>("Word");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FilteredWord");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<ulong>("GuildId");
b.Property<int>("Type");
b.Property<string>("Username");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FollowedStream");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("GCChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AutoAssignRoleId");
b.Property<bool>("AutoDeleteByeMessages");
b.Property<bool>("AutoDeleteGreetMessages");
b.Property<int>("AutoDeleteGreetMessagesTimer");
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
b.Property<ulong>("ByeMessageChannelId");
b.Property<string>("ChannelByeMessageText");
b.Property<string>("ChannelGreetMessageText");
b.Property<float>("DefaultMusicVolume");
b.Property<bool>("DeleteMessageOnCommand");
b.Property<string>("DmGreetMessageText");
b.Property<bool>("ExclusiveSelfAssignedRoles");
b.Property<bool>("FilterInvites");
b.Property<bool>("FilterWords");
b.Property<ulong>("GreetMessageChannelId");
b.Property<ulong>("GuildId");
b.Property<int?>("LogSettingId");
b.Property<string>("PermissionRole");
b.Property<int?>("RootPermissionId");
b.Property<bool>("SendChannelByeMessage");
b.Property<bool>("SendChannelGreetMessage");
b.Property<bool>("SendDmGreetMessage");
b.Property<bool>("VerbosePermissions");
b.Property<bool>("VoicePlusTextEnabled");
b.HasKey("Id");
b.HasIndex("GuildId")
.IsUnique();
b.HasIndex("LogSettingId");
b.HasIndex("RootPermissionId");
b.ToTable("GuildConfigs");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredLogChannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredVoicePresenceCHannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.LogSetting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("ChannelCreated");
b.Property<bool>("ChannelDestroyed");
b.Property<ulong>("ChannelId");
b.Property<bool>("ChannelUpdated");
b.Property<bool>("IsLogging");
b.Property<bool>("LogUserPresence");
b.Property<bool>("LogVoicePresence");
b.Property<bool>("MessageDeleted");
b.Property<bool>("MessageUpdated");
b.Property<bool>("UserBanned");
b.Property<bool>("UserJoined");
b.Property<bool>("UserLeft");
b.Property<ulong>("UserPresenceChannelId");
b.Property<bool>("UserUnbanned");
b.Property<bool>("UserUpdated");
b.Property<ulong>("VoicePresenceChannelId");
b.HasKey("Id");
b.ToTable("LogSettings");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("ModuleName");
b.Property<string>("Prefix");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("ModulePrefixes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.MusicPlaylist", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Author");
b.Property<ulong>("AuthorId");
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("MusicPlaylists");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("NextId");
b.Property<int>("PrimaryTarget");
b.Property<ulong>("PrimaryTargetId");
b.Property<int>("SecondaryTarget");
b.Property<string>("SecondaryTargetName");
b.Property<bool>("State");
b.HasKey("Id");
b.HasIndex("NextId")
.IsUnique();
b.ToTable("Permission");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Status");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("PlayingStatus");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("MusicPlaylistId");
b.Property<string>("Provider");
b.Property<int>("ProviderType");
b.Property<string>("Query");
b.Property<string>("Title");
b.Property<string>("Uri");
b.HasKey("Id");
b.HasIndex("MusicPlaylistId");
b.ToTable("PlaylistSong");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Quote", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AuthorId");
b.Property<string>("AuthorName")
.IsRequired();
b.Property<ulong>("GuildId");
b.Property<string>("Keyword")
.IsRequired();
b.Property<string>("Text")
.IsRequired();
b.HasKey("Id");
b.ToTable("Quotes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Icon");
b.Property<string>("Name");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("RaceAnimals");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Reminder", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<bool>("IsPrivate");
b.Property<string>("Message");
b.Property<ulong>("ServerId");
b.Property<ulong>("UserId");
b.Property<DateTime>("When");
b.HasKey("Id");
b.ToTable("Reminders");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Repeater", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<ulong>("GuildId");
b.Property<TimeSpan>("Interval");
b.Property<string>("Message");
b.HasKey("Id");
b.HasIndex("ChannelId")
.IsUnique();
b.ToTable("Repeaters");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.SelfAssignedRole", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("GuildId");
b.Property<ulong>("RoleId");
b.HasKey("Id");
b.HasIndex("GuildId", "RoleId")
.IsUnique();
b.ToTable("SelfAssignableRoles");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("Blacklist")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.ClashWar", "ClashWar")
.WithMany("Bases")
.HasForeignKey("ClashWarId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("CommandCooldowns")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("EightBallResponses")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterInvitesChannelIds")
.HasForeignKey("GuildConfigId");
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterWordsChannelIds")
.HasForeignKey("GuildConfigId1");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilteredWords")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FollowedStreams")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("GenerateCurrencyChannelIds")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany()
.HasForeignKey("LogSettingId");
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "RootPermission")
.WithMany()
.HasForeignKey("RootPermissionId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredChannels")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredVoicePresenceChannelIds")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("ModulePrefixes")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "Next")
.WithOne("Previous")
.HasForeignKey("NadekoBot.Core.Services.Database.Models.Permission", "NextId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RotatingStatusMessages")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.MusicPlaylist")
.WithMany("Songs")
.HasForeignKey("MusicPlaylistId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RaceAnimals")
.HasForeignKey("BotConfigId");
});
}
}
}

View File

@@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class CurrencyTransaction : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "CurrencyTransactions",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
Amount = table.Column<long>(nullable: false),
Reason = table.Column<string>(nullable: true),
UserId = table.Column<ulong>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CurrencyTransactions", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "CurrencyTransactions");
}
}
}

View File

@@ -0,0 +1,777 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using NadekoBot.Core.Services.Database;
namespace NadekoBot.Migrations
{
[DbContext(typeof(NadekoContext))]
[Migration("20161015102407_coc")]
partial class coc
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
modelBuilder
.HasAnnotation("ProductVersion", "1.0.0-rtm-21431");
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<ulong>("ItemId");
b.Property<int>("Type");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("BlacklistItem");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BotConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("BufferSize");
b.Property<float>("CurrencyGenerationChance");
b.Property<int>("CurrencyGenerationCooldown");
b.Property<string>("CurrencyName");
b.Property<string>("CurrencyPluralName");
b.Property<string>("CurrencySign");
b.Property<string>("DMHelpString");
b.Property<bool>("ForwardMessages");
b.Property<bool>("ForwardToAllOwners");
b.Property<string>("HelpString");
b.Property<int>("MigrationVersion");
b.Property<string>("RemindMessageFormat");
b.Property<bool>("RotatingStatuses");
b.HasKey("Id");
b.ToTable("BotConfig");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("BaseDestroyed");
b.Property<string>("CallUser");
b.Property<int>("ClashWarId");
b.Property<int?>("SequenceNumber");
b.Property<int>("Stars");
b.Property<DateTime>("TimeAdded");
b.HasKey("Id");
b.HasIndex("ClashWarId");
b.ToTable("ClashCallers");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashWar", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<string>("EnemyClan");
b.Property<ulong>("GuildId");
b.Property<int>("Size");
b.Property<DateTime>("StartedAt");
b.Property<int>("WarState");
b.HasKey("Id");
b.ToTable("ClashOfClans");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("CommandName");
b.Property<int?>("GuildConfigId");
b.Property<int>("Seconds");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("CommandCooldown");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ConvertUnit", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("InternalTrigger");
b.Property<decimal>("Modifier");
b.Property<string>("UnitType");
b.HasKey("Id");
b.ToTable("ConversionUnits");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Currency", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Currency");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CurrencyTransaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<string>("Reason");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.ToTable("CurrencyTransactions");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CustomReaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong?>("GuildId");
b.Property<bool>("IsRegex");
b.Property<bool>("OwnerOnly");
b.Property<string>("Response");
b.Property<string>("Trigger");
b.HasKey("Id");
b.ToTable("CustomReactions");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Donator", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Amount");
b.Property<string>("Name");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Donators");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Text");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("EightBallResponses");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<int?>("GuildConfigId1");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.HasIndex("GuildConfigId1");
b.ToTable("FilterChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<string>("Word");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FilteredWord");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<ulong>("GuildId");
b.Property<int>("Type");
b.Property<string>("Username");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FollowedStream");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("GCChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AutoAssignRoleId");
b.Property<bool>("AutoDeleteByeMessages");
b.Property<bool>("AutoDeleteGreetMessages");
b.Property<int>("AutoDeleteGreetMessagesTimer");
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
b.Property<ulong>("ByeMessageChannelId");
b.Property<string>("ChannelByeMessageText");
b.Property<string>("ChannelGreetMessageText");
b.Property<float>("DefaultMusicVolume");
b.Property<bool>("DeleteMessageOnCommand");
b.Property<string>("DmGreetMessageText");
b.Property<bool>("ExclusiveSelfAssignedRoles");
b.Property<bool>("FilterInvites");
b.Property<bool>("FilterWords");
b.Property<ulong>("GreetMessageChannelId");
b.Property<ulong>("GuildId");
b.Property<int?>("LogSettingId");
b.Property<string>("PermissionRole");
b.Property<int?>("RootPermissionId");
b.Property<bool>("SendChannelByeMessage");
b.Property<bool>("SendChannelGreetMessage");
b.Property<bool>("SendDmGreetMessage");
b.Property<bool>("VerbosePermissions");
b.Property<bool>("VoicePlusTextEnabled");
b.HasKey("Id");
b.HasIndex("GuildId")
.IsUnique();
b.HasIndex("LogSettingId");
b.HasIndex("RootPermissionId");
b.ToTable("GuildConfigs");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredLogChannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredVoicePresenceCHannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.LogSetting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("ChannelCreated");
b.Property<bool>("ChannelDestroyed");
b.Property<ulong>("ChannelId");
b.Property<bool>("ChannelUpdated");
b.Property<bool>("IsLogging");
b.Property<bool>("LogUserPresence");
b.Property<bool>("LogVoicePresence");
b.Property<bool>("MessageDeleted");
b.Property<bool>("MessageUpdated");
b.Property<bool>("UserBanned");
b.Property<bool>("UserJoined");
b.Property<bool>("UserLeft");
b.Property<ulong>("UserPresenceChannelId");
b.Property<bool>("UserUnbanned");
b.Property<bool>("UserUpdated");
b.Property<ulong>("VoicePresenceChannelId");
b.HasKey("Id");
b.ToTable("LogSettings");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("ModuleName");
b.Property<string>("Prefix");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("ModulePrefixes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.MusicPlaylist", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Author");
b.Property<ulong>("AuthorId");
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("MusicPlaylists");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("NextId");
b.Property<int>("PrimaryTarget");
b.Property<ulong>("PrimaryTargetId");
b.Property<int>("SecondaryTarget");
b.Property<string>("SecondaryTargetName");
b.Property<bool>("State");
b.HasKey("Id");
b.HasIndex("NextId")
.IsUnique();
b.ToTable("Permission");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Status");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("PlayingStatus");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("MusicPlaylistId");
b.Property<string>("Provider");
b.Property<int>("ProviderType");
b.Property<string>("Query");
b.Property<string>("Title");
b.Property<string>("Uri");
b.HasKey("Id");
b.HasIndex("MusicPlaylistId");
b.ToTable("PlaylistSong");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Quote", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AuthorId");
b.Property<string>("AuthorName")
.IsRequired();
b.Property<ulong>("GuildId");
b.Property<string>("Keyword")
.IsRequired();
b.Property<string>("Text")
.IsRequired();
b.HasKey("Id");
b.ToTable("Quotes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Icon");
b.Property<string>("Name");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("RaceAnimals");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Reminder", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<bool>("IsPrivate");
b.Property<string>("Message");
b.Property<ulong>("ServerId");
b.Property<ulong>("UserId");
b.Property<DateTime>("When");
b.HasKey("Id");
b.ToTable("Reminders");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Repeater", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<ulong>("GuildId");
b.Property<TimeSpan>("Interval");
b.Property<string>("Message");
b.HasKey("Id");
b.HasIndex("ChannelId")
.IsUnique();
b.ToTable("Repeaters");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.SelfAssignedRole", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("GuildId");
b.Property<ulong>("RoleId");
b.HasKey("Id");
b.HasIndex("GuildId", "RoleId")
.IsUnique();
b.ToTable("SelfAssignableRoles");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("Blacklist")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.ClashWar", "ClashWar")
.WithMany("Bases")
.HasForeignKey("ClashWarId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("CommandCooldowns")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("EightBallResponses")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterInvitesChannelIds")
.HasForeignKey("GuildConfigId");
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterWordsChannelIds")
.HasForeignKey("GuildConfigId1");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilteredWords")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FollowedStreams")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("GenerateCurrencyChannelIds")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany()
.HasForeignKey("LogSettingId");
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "RootPermission")
.WithMany()
.HasForeignKey("RootPermissionId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredChannels")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredVoicePresenceChannelIds")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("ModulePrefixes")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "Next")
.WithOne("Previous")
.HasForeignKey("NadekoBot.Core.Services.Database.Models.Permission", "NextId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RotatingStatusMessages")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.MusicPlaylist")
.WithMany("Songs")
.HasForeignKey("MusicPlaylistId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RaceAnimals")
.HasForeignKey("BotConfigId");
});
}
}
}

View File

@@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class coc : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "SequenceNumber",
table: "ClashCallers",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "SequenceNumber",
table: "ClashCallers");
}
}
}

View File

@@ -0,0 +1,779 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using NadekoBot.Core.Services.Database;
namespace NadekoBot.Migrations
{
[DbContext(typeof(NadekoContext))]
[Migration("20161019055137_MuteRoleName")]
partial class MuteRoleName
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
modelBuilder
.HasAnnotation("ProductVersion", "1.0.0-rtm-21431");
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<ulong>("ItemId");
b.Property<int>("Type");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("BlacklistItem");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BotConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("BufferSize");
b.Property<float>("CurrencyGenerationChance");
b.Property<int>("CurrencyGenerationCooldown");
b.Property<string>("CurrencyName");
b.Property<string>("CurrencyPluralName");
b.Property<string>("CurrencySign");
b.Property<string>("DMHelpString");
b.Property<bool>("ForwardMessages");
b.Property<bool>("ForwardToAllOwners");
b.Property<string>("HelpString");
b.Property<int>("MigrationVersion");
b.Property<string>("RemindMessageFormat");
b.Property<bool>("RotatingStatuses");
b.HasKey("Id");
b.ToTable("BotConfig");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("BaseDestroyed");
b.Property<string>("CallUser");
b.Property<int>("ClashWarId");
b.Property<int?>("SequenceNumber");
b.Property<int>("Stars");
b.Property<DateTime>("TimeAdded");
b.HasKey("Id");
b.HasIndex("ClashWarId");
b.ToTable("ClashCallers");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashWar", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<string>("EnemyClan");
b.Property<ulong>("GuildId");
b.Property<int>("Size");
b.Property<DateTime>("StartedAt");
b.Property<int>("WarState");
b.HasKey("Id");
b.ToTable("ClashOfClans");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("CommandName");
b.Property<int?>("GuildConfigId");
b.Property<int>("Seconds");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("CommandCooldown");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ConvertUnit", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("InternalTrigger");
b.Property<decimal>("Modifier");
b.Property<string>("UnitType");
b.HasKey("Id");
b.ToTable("ConversionUnits");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Currency", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Currency");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CurrencyTransaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<string>("Reason");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.ToTable("CurrencyTransactions");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CustomReaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong?>("GuildId");
b.Property<bool>("IsRegex");
b.Property<bool>("OwnerOnly");
b.Property<string>("Response");
b.Property<string>("Trigger");
b.HasKey("Id");
b.ToTable("CustomReactions");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Donator", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Amount");
b.Property<string>("Name");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Donators");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Text");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("EightBallResponses");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<int?>("GuildConfigId1");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.HasIndex("GuildConfigId1");
b.ToTable("FilterChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<string>("Word");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FilteredWord");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<ulong>("GuildId");
b.Property<int>("Type");
b.Property<string>("Username");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FollowedStream");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("GCChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AutoAssignRoleId");
b.Property<bool>("AutoDeleteByeMessages");
b.Property<bool>("AutoDeleteGreetMessages");
b.Property<int>("AutoDeleteGreetMessagesTimer");
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
b.Property<ulong>("ByeMessageChannelId");
b.Property<string>("ChannelByeMessageText");
b.Property<string>("ChannelGreetMessageText");
b.Property<float>("DefaultMusicVolume");
b.Property<bool>("DeleteMessageOnCommand");
b.Property<string>("DmGreetMessageText");
b.Property<bool>("ExclusiveSelfAssignedRoles");
b.Property<bool>("FilterInvites");
b.Property<bool>("FilterWords");
b.Property<ulong>("GreetMessageChannelId");
b.Property<ulong>("GuildId");
b.Property<int?>("LogSettingId");
b.Property<string>("MuteRoleName");
b.Property<string>("PermissionRole");
b.Property<int?>("RootPermissionId");
b.Property<bool>("SendChannelByeMessage");
b.Property<bool>("SendChannelGreetMessage");
b.Property<bool>("SendDmGreetMessage");
b.Property<bool>("VerbosePermissions");
b.Property<bool>("VoicePlusTextEnabled");
b.HasKey("Id");
b.HasIndex("GuildId")
.IsUnique();
b.HasIndex("LogSettingId");
b.HasIndex("RootPermissionId");
b.ToTable("GuildConfigs");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredLogChannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredVoicePresenceCHannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.LogSetting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("ChannelCreated");
b.Property<bool>("ChannelDestroyed");
b.Property<ulong>("ChannelId");
b.Property<bool>("ChannelUpdated");
b.Property<bool>("IsLogging");
b.Property<bool>("LogUserPresence");
b.Property<bool>("LogVoicePresence");
b.Property<bool>("MessageDeleted");
b.Property<bool>("MessageUpdated");
b.Property<bool>("UserBanned");
b.Property<bool>("UserJoined");
b.Property<bool>("UserLeft");
b.Property<ulong>("UserPresenceChannelId");
b.Property<bool>("UserUnbanned");
b.Property<bool>("UserUpdated");
b.Property<ulong>("VoicePresenceChannelId");
b.HasKey("Id");
b.ToTable("LogSettings");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("ModuleName");
b.Property<string>("Prefix");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("ModulePrefixes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.MusicPlaylist", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Author");
b.Property<ulong>("AuthorId");
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("MusicPlaylists");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("NextId");
b.Property<int>("PrimaryTarget");
b.Property<ulong>("PrimaryTargetId");
b.Property<int>("SecondaryTarget");
b.Property<string>("SecondaryTargetName");
b.Property<bool>("State");
b.HasKey("Id");
b.HasIndex("NextId")
.IsUnique();
b.ToTable("Permission");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Status");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("PlayingStatus");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("MusicPlaylistId");
b.Property<string>("Provider");
b.Property<int>("ProviderType");
b.Property<string>("Query");
b.Property<string>("Title");
b.Property<string>("Uri");
b.HasKey("Id");
b.HasIndex("MusicPlaylistId");
b.ToTable("PlaylistSong");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Quote", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AuthorId");
b.Property<string>("AuthorName")
.IsRequired();
b.Property<ulong>("GuildId");
b.Property<string>("Keyword")
.IsRequired();
b.Property<string>("Text")
.IsRequired();
b.HasKey("Id");
b.ToTable("Quotes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Icon");
b.Property<string>("Name");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("RaceAnimals");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Reminder", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<bool>("IsPrivate");
b.Property<string>("Message");
b.Property<ulong>("ServerId");
b.Property<ulong>("UserId");
b.Property<DateTime>("When");
b.HasKey("Id");
b.ToTable("Reminders");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Repeater", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<ulong>("GuildId");
b.Property<TimeSpan>("Interval");
b.Property<string>("Message");
b.HasKey("Id");
b.HasIndex("ChannelId")
.IsUnique();
b.ToTable("Repeaters");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.SelfAssignedRole", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("GuildId");
b.Property<ulong>("RoleId");
b.HasKey("Id");
b.HasIndex("GuildId", "RoleId")
.IsUnique();
b.ToTable("SelfAssignableRoles");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("Blacklist")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.ClashWar", "ClashWar")
.WithMany("Bases")
.HasForeignKey("ClashWarId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("CommandCooldowns")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("EightBallResponses")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterInvitesChannelIds")
.HasForeignKey("GuildConfigId");
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterWordsChannelIds")
.HasForeignKey("GuildConfigId1");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilteredWords")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FollowedStreams")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("GenerateCurrencyChannelIds")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany()
.HasForeignKey("LogSettingId");
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "RootPermission")
.WithMany()
.HasForeignKey("RootPermissionId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredChannels")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredVoicePresenceChannelIds")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("ModulePrefixes")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "Next")
.WithOne("Previous")
.HasForeignKey("NadekoBot.Core.Services.Database.Models.Permission", "NextId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RotatingStatusMessages")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.MusicPlaylist")
.WithMany("Songs")
.HasForeignKey("MusicPlaylistId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RaceAnimals")
.HasForeignKey("BotConfigId");
});
}
}
}

View File

@@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class MuteRoleName : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "MuteRoleName",
table: "GuildConfigs",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MuteRoleName",
table: "GuildConfigs");
}
}
}

View File

@@ -0,0 +1,780 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using NadekoBot.Core.Services.Database;
namespace NadekoBot.Migrations
{
[DbContext(typeof(NadekoContext))]
[Migration("20161107213222_Cleverbot")]
partial class Cleverbot
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
modelBuilder
.HasAnnotation("ProductVersion", "1.0.0-rtm-21431");
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<ulong>("ItemId");
b.Property<int>("Type");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("BlacklistItem");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BotConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("BufferSize");
b.Property<float>("CurrencyGenerationChance");
b.Property<int>("CurrencyGenerationCooldown");
b.Property<string>("CurrencyName");
b.Property<string>("CurrencyPluralName");
b.Property<string>("CurrencySign");
b.Property<string>("DMHelpString");
b.Property<bool>("ForwardMessages");
b.Property<bool>("ForwardToAllOwners");
b.Property<string>("HelpString");
b.Property<int>("MigrationVersion");
b.Property<string>("RemindMessageFormat");
b.Property<bool>("RotatingStatuses");
b.HasKey("Id");
b.ToTable("BotConfig");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("BaseDestroyed");
b.Property<string>("CallUser");
b.Property<int>("ClashWarId");
b.Property<int?>("SequenceNumber");
b.Property<int>("Stars");
b.Property<DateTime>("TimeAdded");
b.HasKey("Id");
b.HasIndex("ClashWarId");
b.ToTable("ClashCallers");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashWar", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<string>("EnemyClan");
b.Property<ulong>("GuildId");
b.Property<int>("Size");
b.Property<DateTime>("StartedAt");
b.Property<int>("WarState");
b.HasKey("Id");
b.ToTable("ClashOfClans");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("CommandName");
b.Property<int?>("GuildConfigId");
b.Property<int>("Seconds");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("CommandCooldown");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ConvertUnit", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("InternalTrigger");
b.Property<decimal>("Modifier");
b.Property<string>("UnitType");
b.HasKey("Id");
b.ToTable("ConversionUnits");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Currency", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Currency");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CurrencyTransaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<string>("Reason");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.ToTable("CurrencyTransactions");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CustomReaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong?>("GuildId");
b.Property<bool>("IsRegex");
b.Property<bool>("OwnerOnly");
b.Property<string>("Response");
b.Property<string>("Trigger");
b.HasKey("Id");
b.ToTable("CustomReactions");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Donator", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Amount");
b.Property<string>("Name");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Donators");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Text");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("EightBallResponses");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<int?>("GuildConfigId1");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.HasIndex("GuildConfigId1");
b.ToTable("FilterChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<string>("Word");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FilteredWord");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<ulong>("GuildId");
b.Property<int>("Type");
b.Property<string>("Username");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FollowedStream");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("GCChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AutoAssignRoleId");
b.Property<bool>("AutoDeleteByeMessages");
b.Property<bool>("AutoDeleteGreetMessages");
b.Property<int>("AutoDeleteGreetMessagesTimer");
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
b.Property<ulong>("ByeMessageChannelId");
b.Property<string>("ChannelByeMessageText");
b.Property<string>("ChannelGreetMessageText");
b.Property<bool>("CleverbotEnabled");
b.Property<float>("DefaultMusicVolume");
b.Property<bool>("DeleteMessageOnCommand");
b.Property<string>("DmGreetMessageText");
b.Property<bool>("ExclusiveSelfAssignedRoles");
b.Property<bool>("FilterInvites");
b.Property<bool>("FilterWords");
b.Property<ulong>("GreetMessageChannelId");
b.Property<ulong>("GuildId");
b.Property<int?>("LogSettingId");
b.Property<string>("MuteRoleName");
b.Property<string>("PermissionRole");
b.Property<int?>("RootPermissionId");
b.Property<bool>("SendChannelByeMessage");
b.Property<bool>("SendChannelGreetMessage");
b.Property<bool>("SendDmGreetMessage");
b.Property<bool>("VerbosePermissions");
b.Property<bool>("VoicePlusTextEnabled");
b.HasKey("Id");
b.HasIndex("GuildId")
.IsUnique();
b.HasIndex("LogSettingId");
b.HasIndex("RootPermissionId");
b.ToTable("GuildConfigs");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredLogChannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredVoicePresenceCHannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.LogSetting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("ChannelCreated");
b.Property<bool>("ChannelDestroyed");
b.Property<ulong>("ChannelId");
b.Property<bool>("ChannelUpdated");
b.Property<bool>("IsLogging");
b.Property<bool>("LogUserPresence");
b.Property<bool>("LogVoicePresence");
b.Property<bool>("MessageDeleted");
b.Property<bool>("MessageUpdated");
b.Property<bool>("UserBanned");
b.Property<bool>("UserJoined");
b.Property<bool>("UserLeft");
b.Property<ulong>("UserPresenceChannelId");
b.Property<bool>("UserUnbanned");
b.Property<bool>("UserUpdated");
b.Property<ulong>("VoicePresenceChannelId");
b.HasKey("Id");
b.ToTable("LogSettings");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("ModuleName");
b.Property<string>("Prefix");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("ModulePrefixes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.MusicPlaylist", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Author");
b.Property<ulong>("AuthorId");
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("MusicPlaylists");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("NextId");
b.Property<int>("PrimaryTarget");
b.Property<ulong>("PrimaryTargetId");
b.Property<int>("SecondaryTarget");
b.Property<string>("SecondaryTargetName");
b.Property<bool>("State");
b.HasKey("Id");
b.HasIndex("NextId")
.IsUnique();
b.ToTable("Permission");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Status");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("PlayingStatus");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("MusicPlaylistId");
b.Property<string>("Provider");
b.Property<int>("ProviderType");
b.Property<string>("Query");
b.Property<string>("Title");
b.Property<string>("Uri");
b.HasKey("Id");
b.HasIndex("MusicPlaylistId");
b.ToTable("PlaylistSong");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Quote", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AuthorId");
b.Property<string>("AuthorName")
.IsRequired();
b.Property<ulong>("GuildId");
b.Property<string>("Keyword")
.IsRequired();
b.Property<string>("Text")
.IsRequired();
b.HasKey("Id");
b.ToTable("Quotes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Icon");
b.Property<string>("Name");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("RaceAnimals");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Reminder", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<bool>("IsPrivate");
b.Property<string>("Message");
b.Property<ulong>("ServerId");
b.Property<ulong>("UserId");
b.Property<DateTime>("When");
b.HasKey("Id");
b.ToTable("Reminders");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Repeater", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<ulong>("GuildId");
b.Property<TimeSpan>("Interval");
b.Property<string>("Message");
b.HasKey("Id");
b.HasIndex("ChannelId")
.IsUnique();
b.ToTable("Repeaters");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.SelfAssignedRole", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("GuildId");
b.Property<ulong>("RoleId");
b.HasKey("Id");
b.HasIndex("GuildId", "RoleId")
.IsUnique();
b.ToTable("SelfAssignableRoles");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("Blacklist")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.ClashWar", "ClashWar")
.WithMany("Bases")
.HasForeignKey("ClashWarId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("CommandCooldowns")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("EightBallResponses")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterInvitesChannelIds")
.HasForeignKey("GuildConfigId");
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterWordsChannelIds")
.HasForeignKey("GuildConfigId1");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilteredWords")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FollowedStreams")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("GenerateCurrencyChannelIds")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany()
.HasForeignKey("LogSettingId");
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "RootPermission")
.WithMany()
.HasForeignKey("RootPermissionId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredChannels")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredVoicePresenceChannelIds")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("ModulePrefixes")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "Next")
.WithOne("Previous")
.HasForeignKey("NadekoBot.Core.Services.Database.Models.Permission", "NextId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RotatingStatusMessages")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.MusicPlaylist")
.WithMany("Songs")
.HasForeignKey("MusicPlaylistId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RaceAnimals")
.HasForeignKey("BotConfigId");
});
}
}
}

View File

@@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class Cleverbot : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "CleverbotEnabled",
table: "GuildConfigs",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "CleverbotEnabled",
table: "GuildConfigs");
}
}
}

View File

@@ -0,0 +1,783 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using NadekoBot.Core.Services.Database;
namespace NadekoBot.Migrations
{
[DbContext(typeof(NadekoContext))]
[Migration("20161122100602_Greet and bye improved")]
partial class Greetandbyeimproved
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
modelBuilder
.HasAnnotation("ProductVersion", "1.1.0-rtm-22752");
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<ulong>("ItemId");
b.Property<int>("Type");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("BlacklistItem");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BotConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("BufferSize");
b.Property<float>("CurrencyGenerationChance");
b.Property<int>("CurrencyGenerationCooldown");
b.Property<string>("CurrencyName");
b.Property<string>("CurrencyPluralName");
b.Property<string>("CurrencySign");
b.Property<string>("DMHelpString");
b.Property<bool>("ForwardMessages");
b.Property<bool>("ForwardToAllOwners");
b.Property<string>("HelpString");
b.Property<int>("MigrationVersion");
b.Property<string>("RemindMessageFormat");
b.Property<bool>("RotatingStatuses");
b.HasKey("Id");
b.ToTable("BotConfig");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("BaseDestroyed");
b.Property<string>("CallUser");
b.Property<int>("ClashWarId");
b.Property<int?>("SequenceNumber");
b.Property<int>("Stars");
b.Property<DateTime>("TimeAdded");
b.HasKey("Id");
b.HasIndex("ClashWarId");
b.ToTable("ClashCallers");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashWar", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<string>("EnemyClan");
b.Property<ulong>("GuildId");
b.Property<int>("Size");
b.Property<DateTime>("StartedAt");
b.Property<int>("WarState");
b.HasKey("Id");
b.ToTable("ClashOfClans");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("CommandName");
b.Property<int?>("GuildConfigId");
b.Property<int>("Seconds");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("CommandCooldown");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ConvertUnit", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("InternalTrigger");
b.Property<decimal>("Modifier");
b.Property<string>("UnitType");
b.HasKey("Id");
b.ToTable("ConversionUnits");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Currency", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Currency");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CurrencyTransaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<string>("Reason");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.ToTable("CurrencyTransactions");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CustomReaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong?>("GuildId");
b.Property<bool>("IsRegex");
b.Property<bool>("OwnerOnly");
b.Property<string>("Response");
b.Property<string>("Trigger");
b.HasKey("Id");
b.ToTable("CustomReactions");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Donator", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Amount");
b.Property<string>("Name");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Donators");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Text");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("EightBallResponses");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<int?>("GuildConfigId1");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.HasIndex("GuildConfigId1");
b.ToTable("FilterChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<string>("Word");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FilteredWord");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<ulong>("GuildId");
b.Property<int>("Type");
b.Property<string>("Username");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FollowedStream");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("GCChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AutoAssignRoleId");
b.Property<bool>("AutoDeleteByeMessages");
b.Property<int>("AutoDeleteByeMessagesTimer");
b.Property<bool>("AutoDeleteGreetMessages");
b.Property<int>("AutoDeleteGreetMessagesTimer");
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
b.Property<ulong>("ByeMessageChannelId");
b.Property<string>("ChannelByeMessageText");
b.Property<string>("ChannelGreetMessageText");
b.Property<bool>("CleverbotEnabled");
b.Property<float>("DefaultMusicVolume");
b.Property<bool>("DeleteMessageOnCommand");
b.Property<string>("DmGreetMessageText");
b.Property<bool>("ExclusiveSelfAssignedRoles");
b.Property<bool>("FilterInvites");
b.Property<bool>("FilterWords");
b.Property<ulong>("GreetMessageChannelId");
b.Property<ulong>("GuildId");
b.Property<int?>("LogSettingId");
b.Property<string>("MuteRoleName");
b.Property<string>("PermissionRole");
b.Property<int?>("RootPermissionId");
b.Property<bool>("SendChannelByeMessage");
b.Property<bool>("SendChannelGreetMessage");
b.Property<bool>("SendDmGreetMessage");
b.Property<bool>("VerbosePermissions");
b.Property<bool>("VoicePlusTextEnabled");
b.HasKey("Id");
b.HasIndex("GuildId")
.IsUnique();
b.HasIndex("LogSettingId");
b.HasIndex("RootPermissionId");
b.ToTable("GuildConfigs");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredLogChannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredVoicePresenceCHannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.LogSetting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("ChannelCreated");
b.Property<bool>("ChannelDestroyed");
b.Property<ulong>("ChannelId");
b.Property<bool>("ChannelUpdated");
b.Property<bool>("IsLogging");
b.Property<bool>("LogUserPresence");
b.Property<bool>("LogVoicePresence");
b.Property<bool>("MessageDeleted");
b.Property<bool>("MessageUpdated");
b.Property<bool>("UserBanned");
b.Property<bool>("UserJoined");
b.Property<bool>("UserLeft");
b.Property<ulong>("UserPresenceChannelId");
b.Property<bool>("UserUnbanned");
b.Property<bool>("UserUpdated");
b.Property<ulong>("VoicePresenceChannelId");
b.HasKey("Id");
b.ToTable("LogSettings");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("ModuleName");
b.Property<string>("Prefix");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("ModulePrefixes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.MusicPlaylist", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Author");
b.Property<ulong>("AuthorId");
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("MusicPlaylists");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("NextId");
b.Property<int>("PrimaryTarget");
b.Property<ulong>("PrimaryTargetId");
b.Property<int>("SecondaryTarget");
b.Property<string>("SecondaryTargetName");
b.Property<bool>("State");
b.HasKey("Id");
b.HasIndex("NextId")
.IsUnique();
b.ToTable("Permission");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Status");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("PlayingStatus");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("MusicPlaylistId");
b.Property<string>("Provider");
b.Property<int>("ProviderType");
b.Property<string>("Query");
b.Property<string>("Title");
b.Property<string>("Uri");
b.HasKey("Id");
b.HasIndex("MusicPlaylistId");
b.ToTable("PlaylistSong");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Quote", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AuthorId");
b.Property<string>("AuthorName")
.IsRequired();
b.Property<ulong>("GuildId");
b.Property<string>("Keyword")
.IsRequired();
b.Property<string>("Text")
.IsRequired();
b.HasKey("Id");
b.ToTable("Quotes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Icon");
b.Property<string>("Name");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("RaceAnimals");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Reminder", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<bool>("IsPrivate");
b.Property<string>("Message");
b.Property<ulong>("ServerId");
b.Property<ulong>("UserId");
b.Property<DateTime>("When");
b.HasKey("Id");
b.ToTable("Reminders");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Repeater", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<ulong>("GuildId");
b.Property<TimeSpan>("Interval");
b.Property<string>("Message");
b.HasKey("Id");
b.HasIndex("ChannelId")
.IsUnique();
b.ToTable("Repeaters");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.SelfAssignedRole", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("GuildId");
b.Property<ulong>("RoleId");
b.HasKey("Id");
b.HasIndex("GuildId", "RoleId")
.IsUnique();
b.ToTable("SelfAssignableRoles");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("Blacklist")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.ClashWar", "ClashWar")
.WithMany("Bases")
.HasForeignKey("ClashWarId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("CommandCooldowns")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("EightBallResponses")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterInvitesChannelIds")
.HasForeignKey("GuildConfigId");
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterWordsChannelIds")
.HasForeignKey("GuildConfigId1");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilteredWords")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FollowedStreams")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("GenerateCurrencyChannelIds")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany()
.HasForeignKey("LogSettingId");
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "RootPermission")
.WithMany()
.HasForeignKey("RootPermissionId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredChannels")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredVoicePresenceChannelIds")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("ModulePrefixes")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "Next")
.WithOne("Previous")
.HasForeignKey("NadekoBot.Core.Services.Database.Models.Permission", "NextId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RotatingStatusMessages")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.MusicPlaylist")
.WithMany("Songs")
.HasForeignKey("MusicPlaylistId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RaceAnimals")
.HasForeignKey("BotConfigId");
});
}
}
}

View File

@@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class Greetandbyeimproved : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "AutoDeleteByeMessagesTimer",
table: "GuildConfigs",
nullable: false,
defaultValue: 0);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AutoDeleteByeMessagesTimer",
table: "GuildConfigs");
}
}
}

View File

@@ -0,0 +1,800 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using NadekoBot.Core.Services.Database;
namespace NadekoBot.Migrations
{
[DbContext(typeof(NadekoContext))]
[Migration("20161127233843_PokeGame")]
partial class PokeGame
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
modelBuilder
.HasAnnotation("ProductVersion", "1.1.0-rtm-22752");
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<ulong>("ItemId");
b.Property<int>("Type");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("BlacklistItem");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BotConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("BufferSize");
b.Property<float>("CurrencyGenerationChance");
b.Property<int>("CurrencyGenerationCooldown");
b.Property<string>("CurrencyName");
b.Property<string>("CurrencyPluralName");
b.Property<string>("CurrencySign");
b.Property<string>("DMHelpString");
b.Property<bool>("ForwardMessages");
b.Property<bool>("ForwardToAllOwners");
b.Property<string>("HelpString");
b.Property<int>("MigrationVersion");
b.Property<string>("RemindMessageFormat");
b.Property<bool>("RotatingStatuses");
b.HasKey("Id");
b.ToTable("BotConfig");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("BaseDestroyed");
b.Property<string>("CallUser");
b.Property<int>("ClashWarId");
b.Property<int?>("SequenceNumber");
b.Property<int>("Stars");
b.Property<DateTime>("TimeAdded");
b.HasKey("Id");
b.HasIndex("ClashWarId");
b.ToTable("ClashCallers");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashWar", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<string>("EnemyClan");
b.Property<ulong>("GuildId");
b.Property<int>("Size");
b.Property<DateTime>("StartedAt");
b.Property<int>("WarState");
b.HasKey("Id");
b.ToTable("ClashOfClans");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("CommandName");
b.Property<int?>("GuildConfigId");
b.Property<int>("Seconds");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("CommandCooldown");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ConvertUnit", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("InternalTrigger");
b.Property<decimal>("Modifier");
b.Property<string>("UnitType");
b.HasKey("Id");
b.ToTable("ConversionUnits");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Currency", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Currency");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CurrencyTransaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("Amount");
b.Property<string>("Reason");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.ToTable("CurrencyTransactions");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CustomReaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong?>("GuildId");
b.Property<bool>("IsRegex");
b.Property<bool>("OwnerOnly");
b.Property<string>("Response");
b.Property<string>("Trigger");
b.HasKey("Id");
b.ToTable("CustomReactions");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Donator", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Amount");
b.Property<string>("Name");
b.Property<ulong>("UserId");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Donators");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Text");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("EightBallResponses");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<int?>("GuildConfigId1");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.HasIndex("GuildConfigId1");
b.ToTable("FilterChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<string>("Word");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FilteredWord");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<ulong>("GuildId");
b.Property<int>("Type");
b.Property<string>("Username");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FollowedStream");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("GCChannelId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AutoAssignRoleId");
b.Property<bool>("AutoDeleteByeMessages");
b.Property<int>("AutoDeleteByeMessagesTimer");
b.Property<bool>("AutoDeleteGreetMessages");
b.Property<int>("AutoDeleteGreetMessagesTimer");
b.Property<bool>("AutoDeleteSelfAssignedRoleMessages");
b.Property<ulong>("ByeMessageChannelId");
b.Property<string>("ChannelByeMessageText");
b.Property<string>("ChannelGreetMessageText");
b.Property<bool>("CleverbotEnabled");
b.Property<float>("DefaultMusicVolume");
b.Property<bool>("DeleteMessageOnCommand");
b.Property<string>("DmGreetMessageText");
b.Property<bool>("ExclusiveSelfAssignedRoles");
b.Property<bool>("FilterInvites");
b.Property<bool>("FilterWords");
b.Property<ulong>("GreetMessageChannelId");
b.Property<ulong>("GuildId");
b.Property<int?>("LogSettingId");
b.Property<string>("MuteRoleName");
b.Property<string>("PermissionRole");
b.Property<int?>("RootPermissionId");
b.Property<bool>("SendChannelByeMessage");
b.Property<bool>("SendChannelGreetMessage");
b.Property<bool>("SendDmGreetMessage");
b.Property<bool>("VerbosePermissions");
b.Property<bool>("VoicePlusTextEnabled");
b.HasKey("Id");
b.HasIndex("GuildId")
.IsUnique();
b.HasIndex("LogSettingId");
b.HasIndex("RootPermissionId");
b.ToTable("GuildConfigs");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredLogChannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("LogSettingId");
b.HasKey("Id");
b.HasIndex("LogSettingId");
b.ToTable("IgnoredVoicePresenceCHannels");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.LogSetting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("ChannelCreated");
b.Property<bool>("ChannelDestroyed");
b.Property<ulong>("ChannelId");
b.Property<bool>("ChannelUpdated");
b.Property<bool>("IsLogging");
b.Property<bool>("LogUserPresence");
b.Property<bool>("LogVoicePresence");
b.Property<bool>("MessageDeleted");
b.Property<bool>("MessageUpdated");
b.Property<bool>("UserBanned");
b.Property<bool>("UserJoined");
b.Property<bool>("UserLeft");
b.Property<ulong>("UserPresenceChannelId");
b.Property<bool>("UserUnbanned");
b.Property<bool>("UserUpdated");
b.Property<ulong>("VoicePresenceChannelId");
b.HasKey("Id");
b.ToTable("LogSettings");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("ModuleName");
b.Property<string>("Prefix");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("ModulePrefixes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.MusicPlaylist", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Author");
b.Property<ulong>("AuthorId");
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("MusicPlaylists");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("NextId");
b.Property<int>("PrimaryTarget");
b.Property<ulong>("PrimaryTargetId");
b.Property<int>("SecondaryTarget");
b.Property<string>("SecondaryTargetName");
b.Property<bool>("State");
b.HasKey("Id");
b.HasIndex("NextId")
.IsUnique();
b.ToTable("Permission");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Status");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("PlayingStatus");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("MusicPlaylistId");
b.Property<string>("Provider");
b.Property<int>("ProviderType");
b.Property<string>("Query");
b.Property<string>("Title");
b.Property<string>("Uri");
b.HasKey("Id");
b.HasIndex("MusicPlaylistId");
b.ToTable("PlaylistSong");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Quote", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("AuthorId");
b.Property<string>("AuthorName")
.IsRequired();
b.Property<ulong>("GuildId");
b.Property<string>("Keyword")
.IsRequired();
b.Property<string>("Text")
.IsRequired();
b.HasKey("Id");
b.ToTable("Quotes");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("BotConfigId");
b.Property<string>("Icon");
b.Property<string>("Name");
b.HasKey("Id");
b.HasIndex("BotConfigId");
b.ToTable("RaceAnimals");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Reminder", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<bool>("IsPrivate");
b.Property<string>("Message");
b.Property<ulong>("ServerId");
b.Property<ulong>("UserId");
b.Property<DateTime>("When");
b.HasKey("Id");
b.ToTable("Reminders");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Repeater", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<ulong>("GuildId");
b.Property<TimeSpan>("Interval");
b.Property<string>("Message");
b.HasKey("Id");
b.HasIndex("ChannelId")
.IsUnique();
b.ToTable("Repeaters");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.SelfAssignedRole", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("GuildId");
b.Property<ulong>("RoleId");
b.HasKey("Id");
b.HasIndex("GuildId", "RoleId")
.IsUnique();
b.ToTable("SelfAssignableRoles");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.UserPokeTypes", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("UserId");
b.Property<string>("type");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("PokeGame");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.BlacklistItem", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("Blacklist")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ClashCaller", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.ClashWar", "ClashWar")
.WithMany("Bases")
.HasForeignKey("ClashWarId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.CommandCooldown", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("CommandCooldowns")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.EightBallResponse", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("EightBallResponses")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilterChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterInvitesChannelIds")
.HasForeignKey("GuildConfigId");
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilterWordsChannelIds")
.HasForeignKey("GuildConfigId1");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FilteredWord", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FilteredWords")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.FollowedStream", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("FollowedStreams")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GCChannelId", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.GuildConfig")
.WithMany("GenerateCurrencyChannelIds")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.GuildConfig", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany()
.HasForeignKey("LogSettingId");
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "RootPermission")
.WithMany()
.HasForeignKey("RootPermissionId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredLogChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredChannels")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.LogSetting", "LogSetting")
.WithMany("IgnoredVoicePresenceChannelIds")
.HasForeignKey("LogSettingId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.ModulePrefix", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("ModulePrefixes")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.Permission", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.Permission", "Next")
.WithOne("Previous")
.HasForeignKey("NadekoBot.Core.Services.Database.Models.Permission", "NextId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlayingStatus", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RotatingStatusMessages")
.HasForeignKey("BotConfigId");
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.PlaylistSong", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.MusicPlaylist")
.WithMany("Songs")
.HasForeignKey("MusicPlaylistId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.RaceAnimal", b =>
{
b.HasOne("NadekoBot.Core.Services.Database.Models.BotConfig")
.WithMany("RaceAnimals")
.HasForeignKey("BotConfigId");
});
}
}
}

View File

@@ -0,0 +1,36 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class PokeGame : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "PokeGame",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
UserId = table.Column<ulong>(nullable: false),
type = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PokeGame", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_PokeGame_UserId",
table: "PokeGame",
column: "UserId",
unique: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "PokeGame");
}
}
}

Some files were not shown because too many files have changed in this diff Show More