diff --git a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/AChatRuleUnitTestBase.cs b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/AChatRuleUnitTestBase.cs new file mode 100644 index 0000000..34a7250 --- /dev/null +++ b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/AChatRuleUnitTestBase.cs @@ -0,0 +1,60 @@ +using Moq; +using Nullinside.Api.Common.Twitch; +using Nullinside.Api.Model.Ddl; +using Nullinside.Api.TwitchBot.ChatRules; + +namespace Nullinside.Api.TwitchBot.Tests.ChatRules; + +/// +/// A generic set of sets that all chat rules should be put through. +/// +/// +public abstract class AChatRuleUnitTestBase : UnitTestBase where T : AChatRule, new() +{ + /// + /// Tests that the message filter is capable of passing at all. + /// + /// A friendly string with no issues. + [Test] + [TestCase("Hello I love candy and sprinkles")] + public async Task TestItDoesntAlwaysFail(string goodString) + { + var rule = new T(); + var botProxy = new Mock(); + + // Process the message and assert that we pass the message. + var chat = new TwitchChatMessage(true, goodString, "123", "456"); + var result = await rule.Handle("123", botProxy.Object, chat, _db); + Assert.That(result, Is.True); + + // Process the message and assert that we pass the message. + chat = new TwitchChatMessage(false, goodString, "123", "456"); + result = await rule.Handle("123", botProxy.Object, chat, _db); + Assert.That(result, Is.True); + } + + /// + /// Tests that the rules are only running when they should be. + /// + [Test] + public void TestShouldRun() + { + var rule = new T(); + + // Rule is turned on and so is scanning. + var shouldRun = rule.ShouldRun(new TwitchUserConfig { Enabled = true, BanKnownBots = true }); + Assert.That(shouldRun, Is.True); + + // Scanning is turned off + shouldRun = rule.ShouldRun(new TwitchUserConfig { Enabled = false, BanKnownBots = true }); + Assert.That(shouldRun, Is.False); + + // Rule is turned off. + shouldRun = rule.ShouldRun(new TwitchUserConfig { Enabled = true, BanKnownBots = false }); + Assert.That(shouldRun, Is.False); + + // Everything is off. + shouldRun = rule.ShouldRun(new TwitchUserConfig { Enabled = false, BanKnownBots = false }); + Assert.That(shouldRun, Is.False); + } +} \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/BestCheapViewersTests.cs b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/BestCheapViewersTests.cs index 48cec94..db889c9 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/BestCheapViewersTests.cs +++ b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/BestCheapViewersTests.cs @@ -1,7 +1,18 @@ +using Moq; +using Nullinside.Api.Common.Twitch; +using Nullinside.Api.TwitchBot.ChatRules; + namespace Nullinside.Api.TwitchBot.Tests.ChatRules; -public class BestCheapViewersTests +/// +/// Tests the class. +/// +public class BestCheapViewersTests : AChatRuleUnitTestBase { + /// + /// Tests strings that have been typed in chats. + /// + /// The string that should fail. [Test] [TestCase("Best viewers on ***")] [TestCase("Best viewers on ***")] @@ -18,9 +29,14 @@ public class BestCheapViewersTests [TestCase("C̀heap Viewers on ***")] [TestCase("Cheaͧp v̫iewers on ***")] [TestCase("Cheaͧp v̫iewers on *** ")] - public void TestKnownStrings(string badString) + public async Task TestKnownStrings(string badString) { - // Need to put interfaces in front of the classes before we can do this. - Assert.Pass(); + var rule = new BestCheapViewers(); + var botProxy = new Mock(); + var chat = new TwitchChatMessage(true, badString, "123", "456"); + + // Process the message and assert that we fail the message. + var result = await rule.Handle("123", botProxy.Object, chat, _db); + Assert.That(result, Is.False); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/DiscordTests.cs b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/DiscordTests.cs index 5174193..790c4ea 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/DiscordTests.cs +++ b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/DiscordTests.cs @@ -1,16 +1,55 @@ -namespace Nullinside.Api.TwitchBot.Tests.ChatRules; +using Moq; +using Nullinside.Api.Common.Twitch; +using Nullinside.Api.TwitchBot.ChatRules; -public class DiscordTests +namespace Nullinside.Api.TwitchBot.Tests.ChatRules; + +/// +/// Tests the class. +/// +public class DiscordTests : AChatRuleUnitTestBase { + /// + /// Tests the strings typed in chats. + /// + /// The string that should fail. [Test] - [TestCase("Hello mate you stream pretty cool that's why I follow I would love to be a fan of yours if you don't mind kindly add me on Discord: 👉👉lacaster5")] - [TestCase("Hello, I just recently found your channel and can already tell that your content is great, and I would love to stick with you long term. If you're open to it, I'd be willing to connect with you on Discord. My username is teecash1000")] - [TestCase("Hey there 👋 You stream pretty cool that’s why I followed you. I will like to make you a friend and be a fan, if you don’t mind Kindly chat me on Discord, my Discord username is tuckzay")] - [TestCase("Hi! Just wanted to say that I absolutely love your gameplay and content.l'd love to connect better with you on Discord if that's possible. Looking forward to more awesome streams from you! My username is 👉👉👉 edisonpires")] - [TestCase("What's up Friend, great stream! I'm having a blast watching you stream. Let's move the conversation to Discord, where we can discuss more about streaming in more detail and get to know each other better. See you there! My discord username is 👉john_6029")] - public void TestKnownStrings(string badString) + [TestCase( + "Hello mate you stream pretty cool that's why I follow I would love to be a fan of yours if you don't mind kindly add me on Discord: 👉👉lacaster5")] + [TestCase( + "Hello, I just recently found your channel and can already tell that your content is great, and I would love to stick with you long term. If you're open to it, I'd be willing to connect with you on Discord. My username is teecash1000")] + [TestCase( + "Hey there 👋 You stream pretty cool that’s why I followed you. I will like to make you a friend and be a fan, if you don’t mind Kindly chat me on Discord, my Discord username is tuckzay")] + [TestCase( + "Hi! Just wanted to say that I absolutely love your gameplay and content.l'd love to connect better with you on Discord if that's possible. Looking forward to more awesome streams from you! My username is 👉👉👉 edisonpires")] + [TestCase( + "What's up Friend, great stream! I'm having a blast watching you stream. Let's move the conversation to Discord, where we can discuss more about streaming in more detail and get to know each other better. See you there! My discord username is 👉john_6029")] + public async Task TestKnownStrings(string badString) { - // Need to put interfaces in front of the classes before we can do this. - Assert.Pass(); + var rule = new Discord(); + var botProxy = new Mock(); + var chat = new TwitchChatMessage(true, badString, "123", "456"); + + // Process the message and assert that we fail the message. + var result = await rule.Handle("123", botProxy.Object, chat, _db); + Assert.That(result, Is.False); + } + + /// + /// Ensure that the rule doesn't fail just because it contains the word discord. + /// + /// The message. + [Test] + [TestCase("I've heard of the application discord before and it sounds great")] + [TestCase("I was talking on my discord the other day")] + public async Task EnsureNoFalsePositives(string message) + { + var rule = new Discord(); + var botProxy = new Mock(); + var chat = new TwitchChatMessage(true, message, "123", "456"); + + // Process the message and assert that we do not fail the message. + var result = await rule.Handle("123", botProxy.Object, chat, _db); + Assert.That(result, Is.True); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/StreamViewersTests.cs b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/StreamViewersTests.cs index a7c11b3..895c492 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/StreamViewersTests.cs +++ b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/StreamViewersTests.cs @@ -1,15 +1,31 @@ +using Moq; +using Nullinside.Api.Common.Twitch; using Nullinside.Api.TwitchBot.ChatRules; namespace Nullinside.Api.TwitchBot.Tests.ChatRules; -public class StreamViewersTests +/// +/// Tests the class. +/// +public class StreamViewersTests : AChatRuleUnitTestBase { + /// + /// Tests the strings typed in chats. + /// + /// The string that should fail. [Test] - [TestCase("@jellynyeko dо уоu alrеady triеd strеamviewers оrg? Real viewеrs, fire works! Тhеy arе now giving оut а frее рackagе for streamers оО")] - [TestCase("@kygaming98 dо уоu аlready tried streаmviewers оrg? Real viewers, firе works! Thеy arе now giving оut а freе package fоr streamers oО")] - public void TestKnownStrings(string badString) + [TestCase( + "@jellynyeko dо уоu alrеady triеd strеamviewers оrg? Real viewеrs, fire works! Тhеy arе now giving оut а frее рackagе for streamers оО")] + [TestCase( + "@kygaming98 dо уоu аlready tried streаmviewers оrg? Real viewers, firе works! Thеy arе now giving оut а freе package fоr streamers oО")] + public async Task TestKnownStrings(string badString) { - // Need to put interfaces in front of the classes before we can do this. - Assert.Pass(); + var rule = new StreamViewers(); + var botProxy = new Mock(); + var chat = new TwitchChatMessage(true, badString, "123", "456"); + + // Process the message and assert that we fail the message. + var result = await rule.Handle("123", botProxy.Object, chat, _db); + Assert.That(result, Is.False); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot.Tests/Nullinside.Api.TwitchBot.Tests.csproj b/src/Nullinside.Api.TwitchBot.Tests/Nullinside.Api.TwitchBot.Tests.csproj index bf32ead..f7c7c03 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/Nullinside.Api.TwitchBot.Tests.csproj +++ b/src/Nullinside.Api.TwitchBot.Tests/Nullinside.Api.TwitchBot.Tests.csproj @@ -11,16 +11,18 @@ - all - runtime; build; native; contentfiles; analyzers; buildtransitive + all + runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + + - all - runtime; build; native; contentfiles; analyzers; buildtransitive + all + runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -28,7 +30,7 @@ - + diff --git a/src/Nullinside.Api.TwitchBot.Tests/UnitTestBase.cs b/src/Nullinside.Api.TwitchBot.Tests/UnitTestBase.cs new file mode 100644 index 0000000..71c1d75 --- /dev/null +++ b/src/Nullinside.Api.TwitchBot.Tests/UnitTestBase.cs @@ -0,0 +1,35 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Nullinside.Api.Model; + +namespace Nullinside.Api.TwitchBot.Tests; + +/// +/// A base class for all unit tests. +/// +public abstract class UnitTestBase +{ + /// + /// A fake database. + /// + protected INullinsideContext _db; + + [SetUp] + public virtual void Setup() + { + // Create an in-memory database to fake the SQL queries. Note that we generate a random GUID for the name + // here. If you use the same name more than once you'll get collisions between tests. + var contextOptions = new DbContextOptionsBuilder() + .UseInMemoryDatabase(Guid.NewGuid().ToString()) + .ConfigureWarnings(b => b.Ignore(InMemoryEventId.TransactionIgnoredWarning)) + .Options; + _db = new NullinsideContext(contextOptions); + } + + [TearDown] + public virtual async Task TearDown() + { + // Dispose since it has one. + await _db.DisposeAsync(); + } +} \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/AChatRule.cs b/src/Nullinside.Api.TwitchBot/ChatRules/AChatRule.cs index 534a151..e7186db 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/AChatRule.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/AChatRule.cs @@ -16,7 +16,7 @@ public abstract class AChatRule : IChatRule { public abstract bool ShouldRun(TwitchUserConfig config); /// - public abstract Task Handle(string channelId, ITwitchApiProxy botProxy, ChatMessage message, + public abstract Task Handle(string channelId, ITwitchApiProxy botProxy, TwitchChatMessage message, INullinsideContext db, CancellationToken stoppingToken = new()); /// diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/BestCheapViewers.cs b/src/Nullinside.Api.TwitchBot/ChatRules/BestCheapViewers.cs index a6e10f4..4695f4b 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/BestCheapViewers.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/BestCheapViewers.cs @@ -26,7 +26,7 @@ public override bool ShouldRun(TwitchUserConfig config) { } /// - public override async Task Handle(string channelId, ITwitchApiProxy botProxy, ChatMessage message, + public override async Task Handle(string channelId, ITwitchApiProxy botProxy, TwitchChatMessage message, INullinsideContext db, CancellationToken stoppingToken = new()) { if (!message.IsFirstMessage) { return true; diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/Discord.cs b/src/Nullinside.Api.TwitchBot/ChatRules/Discord.cs index 5904020..fe590ba 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/Discord.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/Discord.cs @@ -22,7 +22,7 @@ public override bool ShouldRun(TwitchUserConfig config) { } /// - public override async Task Handle(string channelId, ITwitchApiProxy botProxy, ChatMessage message, + public override async Task Handle(string channelId, ITwitchApiProxy botProxy, TwitchChatMessage message, INullinsideContext db, CancellationToken stoppingToken = new()) { if (!message.IsFirstMessage) { return true; diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/Dogehype.cs b/src/Nullinside.Api.TwitchBot/ChatRules/Dogehype.cs index 2cb813f..e0e9904 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/Dogehype.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/Dogehype.cs @@ -16,7 +16,7 @@ public override bool ShouldRun(TwitchUserConfig config) { } /// - public override async Task Handle(string channelId, ITwitchApiProxy botProxy, ChatMessage message, + public override async Task Handle(string channelId, ITwitchApiProxy botProxy, TwitchChatMessage message, INullinsideContext db, CancellationToken stoppingToken = new()) { // The number of spaces per message may chance, so normalize that and lowercase it for comparison. string normalized = string.Concat(message.Message.Split(" ").Where(s => !string.IsNullOrWhiteSpace(s))) diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/HostHub.cs b/src/Nullinside.Api.TwitchBot/ChatRules/HostHub.cs index 2ebb1a2..dff2cac 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/HostHub.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/HostHub.cs @@ -16,7 +16,7 @@ public override bool ShouldRun(TwitchUserConfig config) { } /// - public override async Task Handle(string channelId, ITwitchApiProxy botProxy, ChatMessage message, + public override async Task Handle(string channelId, ITwitchApiProxy botProxy, TwitchChatMessage message, INullinsideContext db, CancellationToken stoppingToken = new()) { // The number of spaces per message may change, so normalize that and lowercase it for comparison. string normalized = string.Concat(message.Message.Split(" ").Where(s => !string.IsNullOrWhiteSpace(s))) diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/IChatRule.cs b/src/Nullinside.Api.TwitchBot/ChatRules/IChatRule.cs index 013dfb5..7832784 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/IChatRule.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/IChatRule.cs @@ -27,6 +27,6 @@ public interface IChatRule { /// The database. /// The cancellation token. /// An asynchronous task. - public Task Handle(string channelId, ITwitchApiProxy botProxy, ChatMessage message, INullinsideContext db, + public Task Handle(string channelId, ITwitchApiProxy botProxy, TwitchChatMessage message, INullinsideContext db, CancellationToken stoppingToken = new()); } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/IfYouWantViewers.cs b/src/Nullinside.Api.TwitchBot/ChatRules/IfYouWantViewers.cs index 6bd8c26..262684f 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/IfYouWantViewers.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/IfYouWantViewers.cs @@ -23,7 +23,7 @@ public override bool ShouldRun(TwitchUserConfig config) { } /// - public override async Task Handle(string channelId, ITwitchApiProxy botProxy, ChatMessage message, + public override async Task Handle(string channelId, ITwitchApiProxy botProxy, TwitchChatMessage message, INullinsideContext db, CancellationToken stoppingToken = new()) { if (!message.IsFirstMessage) { return true; diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/Naked.cs b/src/Nullinside.Api.TwitchBot/ChatRules/Naked.cs index add6111..63d40b4 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/Naked.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/Naked.cs @@ -19,7 +19,7 @@ public override bool ShouldRun(TwitchUserConfig config) { } /// - public override async Task Handle(string channelId, ITwitchApiProxy botProxy, ChatMessage message, + public override async Task Handle(string channelId, ITwitchApiProxy botProxy, TwitchChatMessage message, INullinsideContext db, CancellationToken stoppingToken = new()) { if (message.IsFirstMessage && (message.Message.TrimStart().StartsWith(_spam, StringComparison.InvariantCultureIgnoreCase) || diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/StreamRise.cs b/src/Nullinside.Api.TwitchBot/ChatRules/StreamRise.cs index 5a8e111..17ee45d 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/StreamRise.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/StreamRise.cs @@ -22,7 +22,7 @@ public override bool ShouldRun(TwitchUserConfig config) { } /// - public override async Task Handle(string channelId, ITwitchApiProxy botProxy, ChatMessage message, + public override async Task Handle(string channelId, ITwitchApiProxy botProxy, TwitchChatMessage message, INullinsideContext db, CancellationToken stoppingToken = new()) { if (message.IsFirstMessage && _spam.Equals(message.Message, StringComparison.InvariantCultureIgnoreCase)) { await BanAndLog(channelId, botProxy, new[] { (message.UserId, message.Username) }, diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/StreamViewers.cs b/src/Nullinside.Api.TwitchBot/ChatRules/StreamViewers.cs index 4bc0522..1ccb640 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/StreamViewers.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/StreamViewers.cs @@ -21,7 +21,7 @@ public override bool ShouldRun(TwitchUserConfig config) { } /// - public override async Task Handle(string channelId, ITwitchApiProxy botProxy, ChatMessage message, + public override async Task Handle(string channelId, ITwitchApiProxy botProxy, TwitchChatMessage message, INullinsideContext db, CancellationToken stoppingToken = new()) { if (!message.IsFirstMessage) { return true; diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/TwitchChatMessage.cs b/src/Nullinside.Api.TwitchBot/ChatRules/TwitchChatMessage.cs new file mode 100644 index 0000000..8adb12c --- /dev/null +++ b/src/Nullinside.Api.TwitchBot/ChatRules/TwitchChatMessage.cs @@ -0,0 +1,69 @@ +using System.Diagnostics.CodeAnalysis; + +using TwitchLib.Client.Models; + +namespace Nullinside.Api.TwitchBot.ChatRules; + +/// +/// This wrapper exists for unit testing purposes. It's nice passing the around only because +/// it promotes discoverability with what chat messages can possess. However, we can't construct a +/// easily in the unit tests and thus we need a wrapper that we can mess with that may or may +/// not have a source. +/// +[ExcludeFromCodeCoverage] +public class TwitchChatMessage { + /// + /// Initializes a new instance of the class. + /// + /// True if this is the first time the user has ever written in this channel. + /// The message in chat. + /// The user id of the sender. + /// The username of the sender. + public TwitchChatMessage(bool isFirstMessage, string message, string userId, string username) { + IsFirstMessage = isFirstMessage; + Message = message; + UserId = userId; + Username = username; + } + + /// + /// Initializes a new instance of the class. + /// + /// The chat message from twitch. + public TwitchChatMessage(ChatMessage message) { +#if DEBUG + Raw = message; +#endif + IsFirstMessage = message.IsFirstMessage; + Message = message.Message; + UserId = message.UserId; + Username = message.Username; + } + + /// + /// True if this is the first time the user has ever written in this channel. + /// + public bool IsFirstMessage { get; set; } + + /// + /// The message in chat. + /// + public string Message { get; set; } + + /// + /// The twitch user id of the chat sender. + /// + public string UserId { get; set; } + + /// + /// The twitch username of the chat sender. + /// + public string Username { get; set; } + +#if DEBUG + /// + /// FOR DEBUGGING PURPOSES ONLY! + /// + public ChatMessage? Raw { get; } +#endif +} \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/TwitchChatMessageMonitorConsumer.cs b/src/Nullinside.Api.TwitchBot/ChatRules/TwitchChatMessageMonitorConsumer.cs index 0991215..239d002 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/TwitchChatMessageMonitorConsumer.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/TwitchChatMessageMonitorConsumer.cs @@ -154,7 +154,7 @@ private async void MainLoop() { foreach (IChatRule rule in rules) { try { if (rule.ShouldRun(user.TwitchConfig)) { - if (!await rule.Handle(user.TwitchId, botProxy, message, _db)) { + if (!await rule.Handle(user.TwitchId, botProxy, new TwitchChatMessage(message), _db)) { break; } } diff --git a/src/Nullinside.Api.TwitchBot/Controllers/LoginController.cs b/src/Nullinside.Api.TwitchBot/Controllers/LoginController.cs index f14a0f6..e2b39ff 100644 --- a/src/Nullinside.Api.TwitchBot/Controllers/LoginController.cs +++ b/src/Nullinside.Api.TwitchBot/Controllers/LoginController.cs @@ -4,9 +4,9 @@ using Microsoft.AspNetCore.Mvc; using Nullinside.Api.Common.Twitch; +using Nullinside.Api.Common.Twitch.Support; using Nullinside.Api.Model; using Nullinside.Api.Model.Shared; -using Nullinside.Api.Shared.Support; namespace Nullinside.Api.TwitchBot.Controllers; @@ -73,7 +73,7 @@ public async Task TwitchLogin([FromQuery] string code, [FromServi return Redirect($"{siteUrl}/twitch-bot/config?error={TwitchBotLoginErrors.InternalError}"); } - string? bearerToken = await UserHelpers.GetTokenAndSaveToDatabase(_dbContext, email, token, api.OAuth?.AccessToken, + string? bearerToken = await UserHelpers.GenerateTokenAndSaveToDatabase(_dbContext, email, token, api.OAuth?.AccessToken, api.OAuth?.RefreshToken, api.OAuth?.ExpiresUtc, user.username, user.id); if (string.IsNullOrWhiteSpace(bearerToken)) { return Redirect($"{siteUrl}/twitch-bot/config?error={TwitchBotLoginErrors.InternalError}"); diff --git a/src/nullinside-api b/src/nullinside-api index 4e0605a..1826a07 160000 --- a/src/nullinside-api +++ b/src/nullinside-api @@ -1 +1 @@ -Subproject commit 4e0605a58523339345865d5655697090dc2e18b5 +Subproject commit 1826a079105d62430487e71e0b8c34e8ee923746