Merge remote-tracking branch 'upstream/dev' into dev

This commit is contained in:
fkndean 2016-12-03 08:57:00 -05:00
commit 657ee9668e
18 changed files with 265 additions and 176 deletions

View File

@ -52,7 +52,7 @@ namespace NadekoBot.Modules.Administration
bool shouldDelete; bool shouldDelete;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
shouldDelete = uow.GuildConfigs.For(channel.Guild.Id).DeleteMessageOnCommand; shouldDelete = uow.GuildConfigs.For(channel.Guild.Id, set => set).DeleteMessageOnCommand;
} }
if (shouldDelete) if (shouldDelete)
@ -128,15 +128,15 @@ namespace NadekoBot.Modules.Administration
public async Task Delmsgoncmd(IUserMessage umsg) public async Task Delmsgoncmd(IUserMessage umsg)
{ {
var channel = (ITextChannel)umsg.Channel; var channel = (ITextChannel)umsg.Channel;
GuildConfig conf; bool enabled;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
conf = uow.GuildConfigs.For(channel.Guild.Id); var conf = uow.GuildConfigs.For(channel.Guild.Id, set => set);
conf.DeleteMessageOnCommand = !conf.DeleteMessageOnCommand; enabled = conf.DeleteMessageOnCommand = !conf.DeleteMessageOnCommand;
uow.GuildConfigs.Update(conf);
await uow.CompleteAsync(); await uow.CompleteAsync();
} }
if (conf.DeleteMessageOnCommand) if (enabled)
await channel.SendMessageAsync("✅ **Now automatically deleting successful command invokations.**").ConfigureAwait(false); await channel.SendMessageAsync("✅ **Now automatically deleting successful command invokations.**").ConfigureAwait(false);
else else
await channel.SendMessageAsync("❗**Stopped automatic deletion of successful command invokations.**").ConfigureAwait(false); await channel.SendMessageAsync("❗**Stopped automatic deletion of successful command invokations.**").ConfigureAwait(false);
@ -399,7 +399,7 @@ namespace NadekoBot.Modules.Administration
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var config = uow.GuildConfigs.For(channel.Guild.Id); var config = uow.GuildConfigs.For(channel.Guild.Id, set => set);
config.MuteRoleName = name; config.MuteRoleName = name;
GuildMuteRoles.AddOrUpdate(channel.Guild.Id, name, (id, old) => name); GuildMuteRoles.AddOrUpdate(channel.Guild.Id, name, (id, old) => name);
await uow.CompleteAsync().ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false);

View File

@ -30,7 +30,7 @@ namespace NadekoBot.Modules.Administration
GuildConfig conf; GuildConfig conf;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
conf = uow.GuildConfigs.For(user.Guild.Id); conf = uow.GuildConfigs.For(user.Guild.Id, set => set);
} }
if (conf.AutoAssignRoleId == 0) if (conf.AutoAssignRoleId == 0)
@ -57,13 +57,12 @@ namespace NadekoBot.Modules.Administration
GuildConfig conf; GuildConfig conf;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
conf = uow.GuildConfigs.For(channel.Guild.Id); conf = uow.GuildConfigs.For(channel.Guild.Id, set => set);
if (role == null) if (role == null)
conf.AutoAssignRoleId = 0; conf.AutoAssignRoleId = 0;
else else
conf.AutoAssignRoleId = role.Id; conf.AutoAssignRoleId = role.Id;
uow.GuildConfigs.Update(conf);
await uow.CompleteAsync().ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false);
} }

View File

@ -1,6 +1,7 @@
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using Discord.WebSocket; using Discord.WebSocket;
using Microsoft.EntityFrameworkCore;
using NadekoBot.Attributes; using NadekoBot.Attributes;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using NadekoBot.Services; using NadekoBot.Services;
@ -698,7 +699,9 @@ namespace NadekoBot.Modules.Administration
bool enabled; bool enabled;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var logSetting = uow.GuildConfigs.For(channel.Guild.Id).LogSetting; var logSetting = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.LogSetting)
.ThenInclude(ls => ls.IgnoredVoicePresenceChannelIds))
.LogSetting;
GuildLogSettings.AddOrUpdate(channel.Guild.Id, (id) => logSetting, (id, old) => logSetting); GuildLogSettings.AddOrUpdate(channel.Guild.Id, (id) => logSetting, (id, old) => logSetting);
enabled = logSetting.LogVoicePresence = !logSetting.LogVoicePresence; enabled = logSetting.LogVoicePresence = !logSetting.LogVoicePresence;
if (enabled) if (enabled)

View File

@ -109,7 +109,7 @@ namespace NadekoBot.Modules.Administration
var byeMsg = (string)reader["ByeText"]; var byeMsg = (string)reader["ByeText"];
var grdel = false; var grdel = false;
var byedel = grdel; var byedel = grdel;
var gc = uow.GuildConfigs.For(gid); var gc = uow.GuildConfigs.For(gid, set => set);
if (greetDM) if (greetDM)
gc.SendDmGreetMessage = greet; gc.SendDmGreetMessage = greet;

View File

@ -27,7 +27,7 @@ namespace NadekoBot.Modules.Administration
bool newval; bool newval;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var config = uow.GuildConfigs.For(channel.Guild.Id); var config = uow.GuildConfigs.For(channel.Guild.Id, set => set);
newval = config.AutoDeleteSelfAssignedRoleMessages = !config.AutoDeleteSelfAssignedRoleMessages; newval = config.AutoDeleteSelfAssignedRoleMessages = !config.AutoDeleteSelfAssignedRoleMessages;
await uow.CompleteAsync().ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false);
} }
@ -132,7 +132,7 @@ namespace NadekoBot.Modules.Administration
bool areExclusive; bool areExclusive;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var config = uow.GuildConfigs.For(channel.Guild.Id); var config = uow.GuildConfigs.For(channel.Guild.Id, set => set);
areExclusive = config.ExclusiveSelfAssignedRoles = !config.ExclusiveSelfAssignedRoles; areExclusive = config.ExclusiveSelfAssignedRoles = !config.ExclusiveSelfAssignedRoles;
await uow.CompleteAsync(); await uow.CompleteAsync();
@ -153,7 +153,7 @@ namespace NadekoBot.Modules.Administration
IEnumerable<SelfAssignedRole> roles; IEnumerable<SelfAssignedRole> roles;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
conf = uow.GuildConfigs.For(channel.Guild.Id); conf = uow.GuildConfigs.For(channel.Guild.Id, set => set);
roles = uow.SelfAssignedRoles.GetFromGuild(channel.Guild.Id); roles = uow.SelfAssignedRoles.GetFromGuild(channel.Guild.Id);
} }
SelfAssignedRole roleModel; SelfAssignedRole roleModel;
@ -207,11 +207,11 @@ namespace NadekoBot.Modules.Administration
var channel = (ITextChannel)umsg.Channel; var channel = (ITextChannel)umsg.Channel;
var guildUser = (IGuildUser)umsg.Author; var guildUser = (IGuildUser)umsg.Author;
GuildConfig conf; bool autoDeleteSelfAssignedRoleMessages;
IEnumerable<SelfAssignedRole> roles; IEnumerable<SelfAssignedRole> roles;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
conf = uow.GuildConfigs.For(channel.Guild.Id); autoDeleteSelfAssignedRoleMessages = uow.GuildConfigs.For(channel.Guild.Id, set => set).AutoDeleteSelfAssignedRoleMessages;
roles = uow.SelfAssignedRoles.GetFromGuild(channel.Guild.Id); roles = uow.SelfAssignedRoles.GetFromGuild(channel.Guild.Id);
} }
SelfAssignedRole roleModel; SelfAssignedRole roleModel;
@ -236,7 +236,7 @@ namespace NadekoBot.Modules.Administration
} }
var msg = await channel.SendMessageAsync($"🆗 You no longer have **{role.Name}** role.").ConfigureAwait(false); var msg = await channel.SendMessageAsync($"🆗 You no longer have **{role.Name}** role.").ConfigureAwait(false);
if (conf.AutoDeleteSelfAssignedRoleMessages) if (autoDeleteSelfAssignedRoleMessages)
{ {
var t = Task.Run(async () => var t = Task.Run(async () =>
{ {

View File

@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Administration
GuildConfig conf; GuildConfig conf;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
conf = uow.GuildConfigs.For(user.Guild.Id); conf = uow.GuildConfigs.For(user.Guild.Id, set => set);
} }
if (!conf.SendChannelByeMessage) return; if (!conf.SendChannelByeMessage) return;
@ -76,7 +76,7 @@ namespace NadekoBot.Modules.Administration
GuildConfig conf; GuildConfig conf;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
conf = uow.GuildConfigs.For(user.Guild.Id); conf = uow.GuildConfigs.For(user.Guild.Id, set => set);
} }
if (conf.SendChannelGreetMessage) if (conf.SendChannelGreetMessage)
@ -147,9 +147,9 @@ namespace NadekoBot.Modules.Administration
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var conf = uow.GuildConfigs.For(id); var conf = uow.GuildConfigs.For(id, set => set);
conf.AutoDeleteGreetMessagesTimer = timer; conf.AutoDeleteGreetMessagesTimer = timer;
uow.GuildConfigs.Update(conf);
await uow.CompleteAsync().ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false);
} }
} }
@ -174,10 +174,10 @@ namespace NadekoBot.Modules.Administration
bool enabled; bool enabled;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var conf = uow.GuildConfigs.For(guildId); var conf = uow.GuildConfigs.For(guildId, set => set);
enabled = conf.SendChannelGreetMessage = value ?? !conf.SendChannelGreetMessage; enabled = conf.SendChannelGreetMessage = value ?? !conf.SendChannelGreetMessage;
conf.GreetMessageChannelId = channelId; conf.GreetMessageChannelId = channelId;
uow.GuildConfigs.Update(conf);
await uow.CompleteAsync().ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false);
} }
return enabled; return enabled;
@ -192,12 +192,12 @@ namespace NadekoBot.Modules.Administration
if (string.IsNullOrWhiteSpace(text)) if (string.IsNullOrWhiteSpace(text))
{ {
GuildConfig config; string channelGreetMessageText;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
config = uow.GuildConfigs.For(channel.Guild.Id); channelGreetMessageText = uow.GuildConfigs.For(channel.Guild.Id, set => set).ChannelGreetMessageText;
} }
await channel.SendMessageAsync(" Current **greet** message: `" + config.ChannelGreetMessageText?.SanitizeMentions() + "`"); await channel.SendMessageAsync(" Current **greet** message: `" + channelGreetMessageText?.SanitizeMentions() + "`");
return; return;
} }
@ -218,11 +218,10 @@ namespace NadekoBot.Modules.Administration
bool greetMsgEnabled; bool greetMsgEnabled;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var conf = uow.GuildConfigs.For(guildId); var conf = uow.GuildConfigs.For(guildId, set => set);
conf.ChannelGreetMessageText = message; conf.ChannelGreetMessageText = message;
greetMsgEnabled = conf.SendChannelGreetMessage; greetMsgEnabled = conf.SendChannelGreetMessage;
uow.GuildConfigs.Update(conf);
uow.Complete(); uow.Complete();
} }
return greetMsgEnabled; return greetMsgEnabled;
@ -248,9 +247,9 @@ namespace NadekoBot.Modules.Administration
bool enabled; bool enabled;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var conf = uow.GuildConfigs.For(guildId); var conf = uow.GuildConfigs.For(guildId, set => set);
enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage; enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage;
uow.GuildConfigs.Update(conf);
await uow.CompleteAsync().ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false);
} }
return enabled; return enabled;
@ -295,7 +294,6 @@ namespace NadekoBot.Modules.Administration
conf.DmGreetMessageText = message; conf.DmGreetMessageText = message;
greetMsgEnabled = conf.SendDmGreetMessage; greetMsgEnabled = conf.SendDmGreetMessage;
uow.GuildConfigs.Update(conf);
uow.Complete(); uow.Complete();
} }
return greetMsgEnabled; return greetMsgEnabled;
@ -321,10 +319,10 @@ namespace NadekoBot.Modules.Administration
bool enabled; bool enabled;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var conf = uow.GuildConfigs.For(guildId); var conf = uow.GuildConfigs.For(guildId, set => set);
enabled = conf.SendChannelByeMessage = value ?? !conf.SendChannelByeMessage; enabled = conf.SendChannelByeMessage = value ?? !conf.SendChannelByeMessage;
conf.ByeMessageChannelId = channelId; conf.ByeMessageChannelId = channelId;
uow.GuildConfigs.Update(conf);
await uow.CompleteAsync(); await uow.CompleteAsync();
} }
return enabled; return enabled;
@ -339,12 +337,12 @@ namespace NadekoBot.Modules.Administration
if (string.IsNullOrWhiteSpace(text)) if (string.IsNullOrWhiteSpace(text))
{ {
GuildConfig config; string byeMessageText;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
config = uow.GuildConfigs.For(channel.Guild.Id); byeMessageText = uow.GuildConfigs.For(channel.Guild.Id, set => set).ChannelByeMessageText;
} }
await channel.SendMessageAsync(" Current **bye** message: `" + config.ChannelByeMessageText?.SanitizeMentions() + "`"); await channel.SendMessageAsync(" Current **bye** message: `" + byeMessageText?.SanitizeMentions() + "`");
return; return;
} }
@ -365,11 +363,10 @@ namespace NadekoBot.Modules.Administration
bool byeMsgEnabled; bool byeMsgEnabled;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var conf = uow.GuildConfigs.For(guildId); var conf = uow.GuildConfigs.For(guildId, set => set);
conf.ChannelByeMessageText = message; conf.ChannelByeMessageText = message;
byeMsgEnabled = conf.SendChannelByeMessage; byeMsgEnabled = conf.SendChannelByeMessage;
uow.GuildConfigs.Update(conf);
uow.Complete(); uow.Complete();
} }
return byeMsgEnabled; return byeMsgEnabled;
@ -397,9 +394,9 @@ namespace NadekoBot.Modules.Administration
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var conf = uow.GuildConfigs.For(id); var conf = uow.GuildConfigs.For(id, set => set);
conf.AutoDeleteByeMessagesTimer = timer; conf.AutoDeleteByeMessagesTimer = timer;
uow.GuildConfigs.Update(conf);
await uow.CompleteAsync().ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false);
} }
} }

View File

@ -58,7 +58,7 @@ namespace NadekoBot.Modules.Administration
catch { } catch { }
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
uow.GuildConfigs.For(guild.Id).VoicePlusTextEnabled = false; uow.GuildConfigs.For(guild.Id, set => set).VoicePlusTextEnabled = false;
voicePlusTextCache.TryRemove(guild.Id); voicePlusTextCache.TryRemove(guild.Id);
await uow.CompleteAsync().ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false);
} }
@ -134,7 +134,7 @@ namespace NadekoBot.Modules.Administration
bool isEnabled; bool isEnabled;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var conf = uow.GuildConfigs.For(guild.Id); var conf = uow.GuildConfigs.For(guild.Id, set => set);
isEnabled = conf.VoicePlusTextEnabled = !conf.VoicePlusTextEnabled; isEnabled = conf.VoicePlusTextEnabled = !conf.VoicePlusTextEnabled;
await uow.CompleteAsync().ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false);
} }

View File

@ -1,6 +1,7 @@
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using Discord.WebSocket; using Discord.WebSocket;
using Microsoft.EntityFrameworkCore;
using NadekoBot.Attributes; using NadekoBot.Attributes;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using NadekoBot.Services; using NadekoBot.Services;
@ -166,7 +167,7 @@ namespace NadekoBot.Modules.Games
bool enabled; bool enabled;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var guildConfig = uow.GuildConfigs.For(channel.Id); var guildConfig = uow.GuildConfigs.For(channel.Id, set => set.Include(gc => gc.GenerateCurrencyChannelIds));
var toAdd = new GCChannelId() { ChannelId = channel.Id }; var toAdd = new GCChannelId() { ChannelId = channel.Id };
if (!guildConfig.GenerateCurrencyChannelIds.Contains(toAdd)) if (!guildConfig.GenerateCurrencyChannelIds.Contains(toAdd))

View File

@ -220,7 +220,7 @@ namespace NadekoBot.Modules.Music
} }
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
uow.GuildConfigs.For(channel.Guild.Id).DefaultMusicVolume = val / 100.0f; uow.GuildConfigs.For(channel.Guild.Id, set => set).DefaultMusicVolume = val / 100.0f;
uow.Complete(); uow.Complete();
} }
await channel.SendMessageAsync($"🎵 `Default volume set to {val}%`").ConfigureAwait(false); await channel.SendMessageAsync($"🎵 `Default volume set to {val}%`").ConfigureAwait(false);
@ -747,7 +747,7 @@ namespace NadekoBot.Modules.Music
float vol = 1;// SpecificConfigurations.Default.Of(server.Id).DefaultMusicVolume; float vol = 1;// SpecificConfigurations.Default.Of(server.Id).DefaultMusicVolume;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
vol = uow.GuildConfigs.For(textCh.Guild.Id).DefaultMusicVolume; vol = uow.GuildConfigs.For(textCh.Guild.Id, set => set).DefaultMusicVolume;
} }
var mp = new MusicPlayer(voiceCh, vol); var mp = new MusicPlayer(voiceCh, vol);

View File

@ -1,5 +1,6 @@
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using Microsoft.EntityFrameworkCore;
using NadekoBot.Attributes; using NadekoBot.Attributes;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using NadekoBot.Services; using NadekoBot.Services;
@ -46,7 +47,7 @@ namespace NadekoBot.Modules.Permissions
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var config = uow.GuildConfigs.For(channel.Guild.Id); var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.CommandCooldowns));
var localSet = commandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CommandCooldown>()); var localSet = commandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CommandCooldown>());
config.CommandCooldowns.RemoveWhere(cc => cc.CommandName == command.Text.ToLowerInvariant()); config.CommandCooldowns.RemoveWhere(cc => cc.CommandName == command.Text.ToLowerInvariant());

View File

@ -1,5 +1,6 @@
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using Microsoft.EntityFrameworkCore;
using NadekoBot.Attributes; using NadekoBot.Attributes;
using NadekoBot.Services; using NadekoBot.Services;
using System.Collections.Concurrent; using System.Collections.Concurrent;
@ -68,7 +69,7 @@ namespace NadekoBot.Modules.Permissions
bool enabled; bool enabled;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var config = uow.GuildConfigs.For(channel.Guild.Id); var config = uow.GuildConfigs.For(channel.Guild.Id, set => set);
enabled = config.FilterInvites = !config.FilterInvites; enabled = config.FilterInvites = !config.FilterInvites;
await uow.CompleteAsync().ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false);
} }
@ -94,7 +95,7 @@ namespace NadekoBot.Modules.Permissions
int removed; int removed;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var config = uow.GuildConfigs.For(channel.Guild.Id); var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FilterInvitesChannelIds));
removed = config.FilterInvitesChannelIds.RemoveWhere(fc => fc.ChannelId == channel.Id); removed = config.FilterInvitesChannelIds.RemoveWhere(fc => fc.ChannelId == channel.Id);
if (removed == 0) if (removed == 0)
{ {
@ -127,7 +128,7 @@ namespace NadekoBot.Modules.Permissions
bool enabled; bool enabled;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var config = uow.GuildConfigs.For(channel.Guild.Id); var config = uow.GuildConfigs.For(channel.Guild.Id, set => set);
enabled = config.FilterWords = !config.FilterWords; enabled = config.FilterWords = !config.FilterWords;
await uow.CompleteAsync().ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false);
} }
@ -153,7 +154,7 @@ namespace NadekoBot.Modules.Permissions
int removed; int removed;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var config = uow.GuildConfigs.For(channel.Guild.Id); var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FilterWordsChannelIds));
removed = config.FilterWordsChannelIds.RemoveWhere(fc => fc.ChannelId == channel.Id); removed = config.FilterWordsChannelIds.RemoveWhere(fc => fc.ChannelId == channel.Id);
if (removed == 0) if (removed == 0)
{ {
@ -191,7 +192,7 @@ namespace NadekoBot.Modules.Permissions
int removed; int removed;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var config = uow.GuildConfigs.For(channel.Guild.Id); var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FilteredWords));
removed = config.FilteredWords.RemoveWhere(fw => fw.Word == word); removed = config.FilteredWords.RemoveWhere(fw => fw.Word == word);

View File

@ -51,7 +51,7 @@ namespace NadekoBot.Modules.Permissions
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var config = uow.GuildConfigs.For(channel.Guild.Id); var config = uow.GuildConfigs.For(channel.Guild.Id, set => set);
config.VerbosePermissions = action.Value; config.VerbosePermissions = action.Value;
Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache() Cache.AddOrUpdate(channel.Guild.Id, new PermissionCache()
{ {
@ -72,7 +72,7 @@ namespace NadekoBot.Modules.Permissions
var channel = (ITextChannel)msg.Channel; var channel = (ITextChannel)msg.Channel;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var config = uow.GuildConfigs.For(channel.Guild.Id); var config = uow.GuildConfigs.For(channel.Guild.Id, set => set);
if (role == null) if (role == null)
{ {
await channel.SendMessageAsync($" Current permission role is **{config.PermissionRole}**.").ConfigureAwait(false); await channel.SendMessageAsync($" Current permission role is **{config.PermissionRole}**.").ConfigureAwait(false);

View File

@ -12,6 +12,11 @@ using NadekoBot.Services.Database.Models;
using System.Net.Http; using System.Net.Http;
using Discord.WebSocket; using Discord.WebSocket;
using NadekoBot.Attributes; using NadekoBot.Attributes;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using NLog;
using NadekoBot.Services.Database;
using NadekoBot.Extensions;
namespace NadekoBot.Modules.Searches namespace NadekoBot.Modules.Searches
{ {
@ -19,87 +24,112 @@ namespace NadekoBot.Modules.Searches
{ {
public class StreamStatus public class StreamStatus
{ {
public StreamStatus(string link, bool isLive, string views)
{
Link = link;
IsLive = isLive;
Views = views;
}
public bool IsLive { get; set; } public bool IsLive { get; set; }
public string Link { get; set; } public string ApiLink { get; set; }
public string Views { get; set; } public string Views { get; set; }
} }
public class HitboxResponse {
public bool Success { get; set; } = true;
[JsonProperty("media_is_live")]
public string MediaIsLive { get; set; }
public bool IsLive => MediaIsLive == "1";
[JsonProperty("media_views")]
public string Views { get; set; }
}
public class TwitchResponse
{
public string Error { get; set; } = null;
public bool IsLive => Stream != null;
public StreamInfo Stream { get; set; }
public class StreamInfo
{
public int Viewers { get; set; }
}
}
public class BeamResponse
{
public string Error { get; set; } = null;
[JsonProperty("online")]
public bool IsLive { get; set; }
public int ViewersCurrent { get; set; }
}
public class StreamNotFoundException : Exception
{
public StreamNotFoundException(string message) : base("Stream '" + message + "' not found.")
{
}
}
[Group] [Group]
public class StreamNotificationCommands public class StreamNotificationCommands
{ {
private Timer checkTimer { get; } private Timer checkTimer { get; }
private ConcurrentDictionary<string, StreamStatus> oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>(); private ConcurrentDictionary<string, StreamStatus> oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
private ConcurrentDictionary<string, StreamStatus> cachedStatuses = new ConcurrentDictionary<string, StreamStatus>(); private ConcurrentDictionary<string, StreamStatus> cachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
private Logger _log { get; }
private bool FirstPass { get; set; } = true; private bool FirstPass { get; set; } = true;
public StreamNotificationCommands() public StreamNotificationCommands()
{ {
_log = NLog.LogManager.GetCurrentClassLogger();
checkTimer = new Timer(async (state) => checkTimer = new Timer(async (state) =>
{ {
oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>(cachedStatuses); oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>(cachedStatuses);
cachedStatuses = new ConcurrentDictionary<string, StreamStatus>(); cachedStatuses.Clear();
try IEnumerable<FollowedStream> streams;
using (var uow = DbHandler.UnitOfWork())
{ {
IEnumerable<FollowedStream> streams; streams = uow.GuildConfigs.GetAllFollowedStreams();
using (var uow = DbHandler.UnitOfWork())
{
streams = uow.GuildConfigs.GetAllFollowedStreams();
}
foreach (var stream in streams)
{
StreamStatus data;
try
{
data = await GetStreamStatus(stream).ConfigureAwait(false);
if (data == null)
return;
}
catch
{
continue;
}
StreamStatus oldData;
oldCachedStatuses.TryGetValue(data.Link, out oldData);
if (oldData == null || data.IsLive != oldData.IsLive)
{
if (FirstPass)
continue;
var server = NadekoBot.Client.GetGuild(stream.GuildId);
var channel = server?.GetTextChannel(stream.ChannelId);
if (channel == null)
continue;
var msg = $"`{stream.Username}`'s stream is now " +
$"**{(data.IsLive ? "ONLINE" : "OFFLINE")}** with " +
$"**{data.Views}** viewers.";
if (data.IsLive)
if (stream.Type == FollowedStream.FollowedStreamType.Hitbox)
msg += $"\n`Here is the Link:`【 http://www.hitbox.tv/{stream.Username}/ 】";
else if (stream.Type == FollowedStream.FollowedStreamType.Twitch)
msg += $"\n`Here is the Link:`【 http://www.twitch.tv/{stream.Username}/ 】";
else if (stream.Type == FollowedStream.FollowedStreamType.Beam)
msg += $"\n`Here is the Link:`【 http://www.beam.pro/{stream.Username}/ 】";
try { await channel.SendMessageAsync(msg).ConfigureAwait(false); } catch { }
}
}
FirstPass = false;
} }
catch { }
await Task.WhenAll(streams.Select(async fs =>
{
try
{
var newStatus = await GetStreamStatus(fs).ConfigureAwait(false);
if (FirstPass)
{
return;
}
StreamStatus oldStatus;
if (oldCachedStatuses.TryGetValue(newStatus.ApiLink, out oldStatus) &&
oldStatus.IsLive != newStatus.IsLive)
{
var msg = $"`{fs.Username}`'s stream is now " +
$"**{(newStatus.IsLive ? "ONLINE" : "OFFLINE")}** with " +
$"**{newStatus.Views}** viewers.";
var server = NadekoBot.Client.GetGuild(fs.GuildId);
var channel = server?.GetTextChannel(fs.ChannelId);
if (channel == null)
return;
if (newStatus.IsLive)
msg += "\n" + fs.GetLink();
try { await channel.SendMessageAsync(msg).ConfigureAwait(false); } catch { }
}
}
catch (Exception ex)
{
}
}));
FirstPass = false;
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(60)); }, null, TimeSpan.Zero, TimeSpan.FromSeconds(60));
} }
private async Task<StreamStatus> GetStreamStatus(FollowedStream stream, bool checkCache = true) private async Task<StreamStatus> GetStreamStatus(FollowedStream stream, bool checkCache = true)
{ {
bool isLive;
string response; string response;
JObject data;
StreamStatus result; StreamStatus result;
switch (stream.Type) switch (stream.Type)
{ {
@ -111,10 +141,16 @@ namespace NadekoBot.Modules.Searches
{ {
response = await http.GetStringAsync(hitboxUrl).ConfigureAwait(false); response = await http.GetStringAsync(hitboxUrl).ConfigureAwait(false);
} }
data = JObject.Parse(response); var hbData = JsonConvert.DeserializeObject<HitboxResponse>(response);
isLive = data["media_is_live"].ToString() == "1"; if (!hbData.Success)
result = new StreamStatus(hitboxUrl, isLive, data["media_views"].ToString()); throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
cachedStatuses.TryAdd(hitboxUrl, result); result = new StreamStatus()
{
IsLive = hbData.IsLive,
ApiLink = hitboxUrl,
Views = hbData.Views
};
cachedStatuses.AddOrUpdate(hitboxUrl, result, (key, old) => result);
return result; return result;
case FollowedStream.FollowedStreamType.Twitch: case FollowedStream.FollowedStreamType.Twitch:
var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username)}?client_id=67w6z9i09xv2uoojdm9l0wsyph4hxo6"; var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username)}?client_id=67w6z9i09xv2uoojdm9l0wsyph4hxo6";
@ -124,10 +160,18 @@ namespace NadekoBot.Modules.Searches
{ {
response = await http.GetStringAsync(twitchUrl).ConfigureAwait(false); response = await http.GetStringAsync(twitchUrl).ConfigureAwait(false);
} }
data = JObject.Parse(response); var twData = JsonConvert.DeserializeObject<TwitchResponse>(response);
isLive = !string.IsNullOrWhiteSpace(data["stream"].ToString()); if (twData.Error != null)
result = new StreamStatus(twitchUrl, isLive, isLive ? data["stream"]["viewers"].ToString() : "0"); {
cachedStatuses.TryAdd(twitchUrl, result); throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
}
result = new StreamStatus()
{
IsLive = twData.IsLive,
ApiLink = twitchUrl,
Views = twData.Stream?.Viewers.ToString() ?? "0"
};
cachedStatuses.AddOrUpdate(twitchUrl, result, (key, old) => result);
return result; return result;
case FollowedStream.FollowedStreamType.Beam: case FollowedStream.FollowedStreamType.Beam:
var beamUrl = $"https://beam.pro/api/v1/channels/{stream.Username}"; var beamUrl = $"https://beam.pro/api/v1/channels/{stream.Username}";
@ -137,10 +181,17 @@ namespace NadekoBot.Modules.Searches
{ {
response = await http.GetStringAsync(beamUrl).ConfigureAwait(false); response = await http.GetStringAsync(beamUrl).ConfigureAwait(false);
} }
data = JObject.Parse(response);
isLive = data["online"].ToObject<bool>() == true; var bmData = JsonConvert.DeserializeObject<BeamResponse>(response);
result = new StreamStatus(beamUrl, isLive, data["viewersCurrent"].ToString()); if (bmData.Error != null)
cachedStatuses.TryAdd(beamUrl, result); throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
result = new StreamStatus()
{
IsLive = bmData.IsLive,
ApiLink = beamUrl,
Views = bmData.ViewersCurrent.ToString()
};
cachedStatuses.AddOrUpdate(beamUrl, result, (key, old) => result);
return result; return result;
default: default:
break; break;
@ -178,7 +229,10 @@ namespace NadekoBot.Modules.Searches
IEnumerable<FollowedStream> streams; IEnumerable<FollowedStream> streams;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
streams = uow.GuildConfigs.For(channel.Guild.Id).FollowedStreams; streams = uow.GuildConfigs
.For(channel.Guild.Id,
set => set.Include(gc => gc.FollowedStreams))
.FollowedStreams;
} }
if (!streams.Any()) if (!streams.Any())
@ -198,30 +252,33 @@ namespace NadekoBot.Modules.Searches
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
[RequirePermission(GuildPermission.ManageMessages)] [RequirePermission(GuildPermission.ManageMessages)]
public async Task RemoveStream(IUserMessage msg, [Remainder] string username) public async Task RemoveStream(IUserMessage msg, FollowedStream.FollowedStreamType type, [Remainder] string username)
{ {
var channel = (ITextChannel)msg.Channel; var channel = (ITextChannel)msg.Channel;
username = username.ToLowerInvariant().Trim(); username = username.ToLowerInvariant().Trim();
FollowedStream toRemove; var fs = new FollowedStream()
{
ChannelId = channel.Id,
Username = username,
Type = type
};
bool removed;
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var config = uow.GuildConfigs.For(channel.Guild.Id); var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FollowedStreams));
var streams = config.FollowedStreams; removed = config.FollowedStreams.Remove(fs);
toRemove = streams.Where(fs => fs.ChannelId == channel.Id && fs.Username.ToLowerInvariant() == username).FirstOrDefault(); if (removed)
if (toRemove != null) await uow.CompleteAsync().ConfigureAwait(false);
{
config.FollowedStreams = new HashSet<FollowedStream>(streams.Except(new[] { toRemove }));
await uow.CompleteAsync();
}
} }
if (toRemove == null) if (!removed)
{ {
await channel.SendMessageAsync(":anger: No such stream.").ConfigureAwait(false); await channel.SendMessageAsync(":anger: No such stream.").ConfigureAwait(false);
return; return;
} }
await channel.SendMessageAsync($":ok: Removed `{toRemove.Username}`'s stream ({toRemove.Type}) from notifications.").ConfigureAwait(false); await channel.SendMessageAsync($":ok: Removed `{username}`'s stream ({type}) from notifications.").ConfigureAwait(false);
} }
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
@ -238,7 +295,7 @@ namespace NadekoBot.Modules.Searches
var streamStatus = (await GetStreamStatus(new FollowedStream var streamStatus = (await GetStreamStatus(new FollowedStream
{ {
Username = stream, Username = stream,
Type = platform Type = platform,
})); }));
if (streamStatus.IsLive) if (streamStatus.IsLive)
{ {
@ -265,16 +322,7 @@ namespace NadekoBot.Modules.Searches
Username = username, Username = username,
Type = type, Type = type,
}; };
bool exists;
using (var uow = DbHandler.UnitOfWork())
{
exists = uow.GuildConfigs.For(channel.Guild.Id).FollowedStreams.Where(fs => fs.ChannelId == channel.Id && fs.Username.ToLowerInvariant().Trim() == username).Any();
}
if (exists)
{
await channel.SendMessageAsync($":anger: I am already following `{username}` ({type}) stream on this channel.").ConfigureAwait(false);
return;
}
StreamStatus data; StreamStatus data;
try try
{ {
@ -285,22 +333,35 @@ namespace NadekoBot.Modules.Searches
await channel.SendMessageAsync(":anger: Stream probably doesn't exist.").ConfigureAwait(false); await channel.SendMessageAsync(":anger: Stream probably doesn't exist.").ConfigureAwait(false);
return; return;
} }
var msg = $"Stream is currently **{(data.IsLive ? "ONLINE" : "OFFLINE")}** with **{data.Views}** viewers";
if (data.IsLive)
if (type == FollowedStream.FollowedStreamType.Hitbox)
msg += $"\n`Here is the Link:`【 http://www.hitbox.tv/{stream.Username}/ 】";
else if (type == FollowedStream.FollowedStreamType.Twitch)
msg += $"\n`Here is the Link:`【 http://www.twitch.tv/{stream.Username}/ 】";
else if (type == FollowedStream.FollowedStreamType.Beam)
msg += $"\n`Here is the Link:`【 https://beam.pro/{stream.Username}/ 】";
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
uow.GuildConfigs.For(channel.Guild.Id).FollowedStreams.Add(stream); uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FollowedStreams))
await uow.CompleteAsync(); .FollowedStreams
.Add(stream);
await uow.CompleteAsync().ConfigureAwait(false);
} }
var msg = $"Stream is currently **{(data.IsLive ? "ONLINE" : "OFFLINE")}** with **{data.Views}** viewers";
if (data.IsLive)
msg += stream.GetLink();
msg = $":ok: I will notify this channel when status changes.\n{msg}"; msg = $":ok: I will notify this channel when status changes.\n{msg}";
await channel.SendMessageAsync(msg).ConfigureAwait(false); await channel.SendMessageAsync(msg).ConfigureAwait(false);
} }
} }
} }
public static class FollowedStreamExtensions
{
public static string GetLink(this FollowedStream fs)
{
//todo C#7
if (fs.Type == FollowedStream.FollowedStreamType.Hitbox)
return $"\n`Here is the Link:`【 http://www.hitbox.tv/{fs.Username}/ 】";
else if (fs.Type == FollowedStream.FollowedStreamType.Twitch)
return $"\n`Here is the Link:`【 http://www.twitch.tv/{fs.Username}/ 】";
else if (fs.Type == FollowedStream.FollowedStreamType.Beam)
return $"\n`Here is the Link:`【 https://beam.pro/{fs.Username}/ 】";
return "???";
}
}
} }

View File

@ -5280,7 +5280,7 @@ namespace NadekoBot.Resources {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Removes notifications of a certain streamer on this channel.. /// Looks up a localized string similar to Removes notifications of a certain streamer from a certain platform on this channel..
/// </summary> /// </summary>
public static string removestream_desc { public static string removestream_desc {
get { get {
@ -5289,7 +5289,7 @@ namespace NadekoBot.Resources {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to `{0}rms SomeGuy`. /// Looks up a localized string similar to `{0}rms Twitch SomeGuy` or `{0}rms Beam SomeOtherGuy`.
/// </summary> /// </summary>
public static string removestream_usage { public static string removestream_usage {
get { get {

View File

@ -1759,10 +1759,10 @@
<value>removestream rms</value> <value>removestream rms</value>
</data> </data>
<data name="removestream_desc" xml:space="preserve"> <data name="removestream_desc" xml:space="preserve">
<value>Removes notifications of a certain streamer on this channel.</value> <value>Removes notifications of a certain streamer from a certain platform on this channel.</value>
</data> </data>
<data name="removestream_usage" xml:space="preserve"> <data name="removestream_usage" xml:space="preserve">
<value>`{0}rms SomeGuy`</value> <value>`{0}rms Twitch SomeGuy` or `{0}rms Beam SomeOtherGuy`</value>
</data> </data>
<data name="liststreams_cmd" xml:space="preserve"> <data name="liststreams_cmd" xml:space="preserve">
<value>liststreams ls</value> <value>liststreams ls</value>

View File

@ -11,5 +11,17 @@
{ {
Twitch, Hitbox, Beam Twitch, Hitbox, Beam
} }
public override int GetHashCode() =>
ChannelId.GetHashCode() ^ Username.GetHashCode();
public override bool Equals(object obj)
{
var fs = obj as FollowedStream;
if (fs == null)
return false;
return fs.ChannelId == ChannelId && fs.Username.ToLowerInvariant().Trim() == Username.ToLowerInvariant().Trim();
}
} }
} }

View File

@ -1,11 +1,14 @@
using NadekoBot.Services.Database.Models; using Microsoft.EntityFrameworkCore;
using NadekoBot.Services.Database.Models;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace NadekoBot.Services.Database.Repositories namespace NadekoBot.Services.Database.Repositories
{ {
public interface IGuildConfigRepository : IRepository<GuildConfig> public interface IGuildConfigRepository : IRepository<GuildConfig>
{ {
GuildConfig For(ulong guildId); GuildConfig For(ulong guildId, Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes = null);
GuildConfig PermissionsFor(ulong guildId); GuildConfig PermissionsFor(ulong guildId);
IEnumerable<GuildConfig> PermissionsForAll(); IEnumerable<GuildConfig> PermissionsForAll();
GuildConfig SetNewRootPermission(ulong guildId, Permission p); GuildConfig SetNewRootPermission(ulong guildId, Permission p);

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NadekoBot.Modules.Permissions; using NadekoBot.Modules.Permissions;
using System;
namespace NadekoBot.Services.Database.Repositories.Impl namespace NadekoBot.Services.Database.Repositories.Impl
{ {
@ -33,20 +34,30 @@ namespace NadekoBot.Services.Database.Repositories.Impl
/// </summary> /// </summary>
/// <param name="guildId"></param> /// <param name="guildId"></param>
/// <returns></returns> /// <returns></returns>
public GuildConfig For(ulong guildId) public GuildConfig For(ulong guildId, Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes = null)
{ {
var config = _set GuildConfig config;
.Include(gc => gc.FollowedStreams)
.Include(gc => gc.LogSetting) if (includes == null)
.ThenInclude(ls => ls.IgnoredChannels) {
.Include(gc => gc.LogSetting) config = _set
.ThenInclude(ls => ls.IgnoredVoicePresenceChannelIds) .Include(gc => gc.FollowedStreams)
.Include(gc => gc.FilterInvitesChannelIds) .Include(gc => gc.LogSetting)
.Include(gc => gc.FilterWordsChannelIds) .ThenInclude(ls => ls.IgnoredChannels)
.Include(gc => gc.FilteredWords) .Include(gc => gc.LogSetting)
.Include(gc => gc.GenerateCurrencyChannelIds) .ThenInclude(ls => ls.IgnoredVoicePresenceChannelIds)
.Include(gc => gc.CommandCooldowns) .Include(gc => gc.FilterInvitesChannelIds)
.FirstOrDefault(c => c.GuildId == guildId); .Include(gc => gc.FilterWordsChannelIds)
.Include(gc => gc.FilteredWords)
.Include(gc => gc.GenerateCurrencyChannelIds)
.Include(gc => gc.CommandCooldowns)
.FirstOrDefault(c => c.GuildId == guildId);
}
else
{
var set = includes(_set);
config = set.FirstOrDefault(c => c.GuildId == guildId);
}
if (config == null) if (config == null)
{ {