diff --git a/src/Nullinside.Api/Shared/Support/TwitchBotLoginErrors.cs b/src/Nullinside.Api.Common/Twitch/Support/TwitchBotLoginErrors.cs
similarity index 100%
rename from src/Nullinside.Api/Shared/Support/TwitchBotLoginErrors.cs
rename to src/Nullinside.Api.Common/Twitch/Support/TwitchBotLoginErrors.cs
diff --git a/src/Nullinside.Api.Common/Twitch/TwitchApiProxy.cs b/src/Nullinside.Api.Common/Twitch/TwitchApiProxy.cs
index e720d30..56a3ec4 100644
--- a/src/Nullinside.Api.Common/Twitch/TwitchApiProxy.cs
+++ b/src/Nullinside.Api.Common/Twitch/TwitchApiProxy.cs
@@ -14,6 +14,7 @@
using TwitchLib.Api.Helix.Models.Moderation.GetModerators;
using TwitchLib.Api.Helix.Models.Streams.GetStreams;
using TwitchLib.Api.Helix.Models.Users.GetUsers;
+using TwitchLib.Api.Interfaces;
using Stream = TwitchLib.Api.Helix.Models.Streams.GetStreams.Stream;
@@ -73,7 +74,7 @@ public TwitchApiProxy(string token, string refreshToken, DateTime tokenExpires)
///
public async Task CreateAccessToken(string code, CancellationToken token = new()) {
- TwitchAPI api = GetApi();
+ ITwitchAPI api = GetApi();
AuthCodeResponse? response = await api.Auth.GetAccessTokenFromCodeAsync(code, ClientSecret, ClientRedirect);
if (null == response) {
return null;
@@ -90,7 +91,7 @@ public TwitchApiProxy(string token, string refreshToken, DateTime tokenExpires)
///
public async Task RefreshAccessToken(CancellationToken token = new()) {
try {
- TwitchAPI api = GetApi();
+ ITwitchAPI api = GetApi();
RefreshResponse? response = await api.Auth.RefreshAuthTokenAsync(OAuth?.RefreshToken, ClientSecret, ClientId);
if (null == response) {
return null;
@@ -116,7 +117,7 @@ public TwitchApiProxy(string token, string refreshToken, DateTime tokenExpires)
///
public async Task<(string? id, string? username)> GetUser(CancellationToken token = new()) {
return await Retry.Execute(async () => {
- TwitchAPI api = GetApi();
+ ITwitchAPI api = GetApi();
GetUsersResponse? response = await api.Helix.Users.GetUsersAsync();
if (null == response) {
return (null, null);
@@ -130,7 +131,7 @@ public TwitchApiProxy(string token, string refreshToken, DateTime tokenExpires)
///
public async Task GetUserEmail(CancellationToken token = new()) {
return await Retry.Execute(async () => {
- TwitchAPI api = GetApi();
+ ITwitchAPI api = GetApi();
GetUsersResponse? response = await api.Helix.Users.GetUsersAsync();
if (null == response) {
return null;
@@ -175,7 +176,7 @@ public async Task> GetUserModChannels(string
public async Task> BanChannelUsers(string channelId, string botId,
IEnumerable<(string Id, string Username)> users, string reason, CancellationToken token = new()) {
return await Retry.Execute(async () => {
- TwitchAPI api = GetApi();
+ ITwitchAPI api = GetApi();
var bannedUsers = new List();
foreach ((string Id, string Username) user in users) {
@@ -209,7 +210,7 @@ public async Task> BanChannelUsers(string channelId, str
public async Task> GetChannelUsers(string channelId, string botId,
CancellationToken token = new()) {
return await Retry.Execute(async () => {
- TwitchAPI api = GetApi();
+ ITwitchAPI api = GetApi();
var chatters = new List();
string? cursor = null;
int total = 0;
@@ -231,7 +232,7 @@ public async Task> GetChannelUsers(string channelId, string
///
public async Task> GetChannelsLive(IEnumerable userIds) {
- TwitchAPI api = GetApi();
+ ITwitchAPI api = GetApi();
// We can only query 100 at a time, so throttle the search.
var liveUsers = new List();
@@ -256,7 +257,7 @@ public async Task> GetChannelsLive(IEnumerable userI
///
public async Task> GetChannelMods(string channelId, CancellationToken token = new()) {
return await Retry.Execute(async () => {
- TwitchAPI api = GetApi();
+ ITwitchAPI api = GetApi();
var results = new List();
GetModeratorsResponse? response = null;
@@ -283,7 +284,7 @@ public async Task> GetChannelsLive(IEnumerable userI
///
public async Task AddChannelMod(string channelId, string userId, CancellationToken token = new()) {
return await Retry.Execute(async () => {
- TwitchAPI api = GetApi();
+ ITwitchAPI api = GetApi();
await api.Helix.Moderation.AddChannelModeratorAsync(channelId, userId);
return true;
}, Retries, token);
@@ -293,7 +294,7 @@ public async Task> GetChannelsLive(IEnumerable userI
/// Gets a new instance of the .
///
/// A new instance of the .
- private TwitchAPI GetApi() {
+ protected ITwitchAPI GetApi() {
var api = new TwitchAPI {
Settings = {
ClientId = ClientId,
diff --git a/src/Nullinside.Api/Controllers/TwitchBotController.cs b/src/Nullinside.Api/Controllers/TwitchBotController.cs
deleted file mode 100644
index 38b0a62..0000000
--- a/src/Nullinside.Api/Controllers/TwitchBotController.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using log4net;
-
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-
-using Nullinside.Api.Common.Twitch;
-using Nullinside.Api.Model;
-using Nullinside.Api.Model.Shared;
-using Nullinside.Api.Shared.Support;
-
-namespace Nullinside.Api.Controllers;
-
-///
-/// Handles user authentication and authorization.
-///
-[ApiController]
-[Route("[controller]")]
-public class TwitchBotController : ControllerBase {
- ///
- /// The application's configuration file.
- ///
- private readonly IConfiguration _configuration;
-
- ///
- /// The nullinside database.
- ///
- private readonly INullinsideContext _dbContext;
-
- ///
- /// The logger.
- ///
- private readonly ILog _logger = LogManager.GetLogger(typeof(TwitchBotController));
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The application's configuration file.
- /// The nullinside database.
- public TwitchBotController(IConfiguration configuration, INullinsideContext dbContext) {
- _configuration = configuration;
- _dbContext = dbContext;
- }
-
- ///
- /// **NOT CALLED BY SITE OR USERS** This endpoint is called by twitch as part of their oauth workflow. It
- /// redirects users back to the nullinside website.
- ///
- /// The credentials provided by twitch.
- /// The twitch api.
- /// The cancellation token.
- ///
- /// A redirect to the nullinside website.
- /// Errors:
- /// 2 = Internal error generating token.
- /// 3 = Code was invalid
- /// 4 = Twitch account has no email
- ///
- [AllowAnonymous]
- [HttpGet]
- [Route("login")]
- public async Task TwitchLogin([FromQuery] string code, [FromServices] ITwitchApiProxy api,
- CancellationToken token) {
- string? siteUrl = _configuration.GetValue("Api:SiteUrl");
- if (null == await api.CreateAccessToken(code, token)) {
- return Redirect($"{siteUrl}/twitch-bot/config?error={TwitchBotLoginErrors.TwitchErrorWithToken}");
- }
-
- string? email = await api.GetUserEmail(token);
- if (string.IsNullOrWhiteSpace(email)) {
- return Redirect($"{siteUrl}/twitch-bot/config?error={TwitchBotLoginErrors.TwitchAccountHasNoEmail}");
- }
-
- (string? id, string? username) user = await api.GetUser(token);
- if (string.IsNullOrWhiteSpace(user.username) || string.IsNullOrWhiteSpace(user.id)) {
- return Redirect($"{siteUrl}/twitch-bot/config?error={TwitchBotLoginErrors.InternalError}");
- }
-
- string? bearerToken = await UserHelpers.GetTokenAndSaveToDatabase(_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}");
- }
-
- return Redirect($"{siteUrl}/twitch-bot/config?token={bearerToken}");
- }
-}
\ No newline at end of file
diff --git a/src/Nullinside.Api/Controllers/UserController.cs b/src/Nullinside.Api/Controllers/UserController.cs
index 50e2780..7d30944 100644
--- a/src/Nullinside.Api/Controllers/UserController.cs
+++ b/src/Nullinside.Api/Controllers/UserController.cs
@@ -96,7 +96,7 @@ public async Task Login([FromForm] GoogleOpenIdToken creds, Cance
[HttpGet]
[Route("twitch-login")]
public async Task TwitchLogin([FromQuery] string code, [FromServices] ITwitchApiProxy api,
- CancellationToken token) {
+ CancellationToken token = new()) {
string? siteUrl = _configuration.GetValue("Api:SiteUrl");
if (null == await api.CreateAccessToken(code, token)) {
return Redirect($"{siteUrl}/user/login?error=3");