Split Geekbot.net into src/Bot, src/Core, and src/Web
This commit is contained in:
parent
7b6dd2d2f9
commit
fc0af492ad
197 changed files with 542 additions and 498 deletions
7
src/Web/ApiError.cs
Normal file
7
src/Web/ApiError.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Geekbot.Web
|
||||
{
|
||||
public class ApiError
|
||||
{
|
||||
public string Message { get; set; }
|
||||
}
|
||||
}
|
57
src/Web/Controllers/Callback/CallbackController.cs
Normal file
57
src/Web/Controllers/Callback/CallbackController.cs
Normal file
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.Core.GlobalSettings;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Geekbot.Web.Controllers.Callback
|
||||
{
|
||||
public class CallbackController : Controller
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
|
||||
public CallbackController(DiscordSocketClient client, IGlobalSettings globalSettings)
|
||||
{
|
||||
_client = client;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
[Route("/callback")]
|
||||
public async Task<IActionResult> DoCallback([FromQuery] string code)
|
||||
{
|
||||
var token = "";
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
client.BaseAddress = new Uri("https://discordapp.com");
|
||||
var appInfo = await _client.GetApplicationInfoAsync();
|
||||
var accessToken = _globalSettings.GetKey("OAuthToken");
|
||||
var callbackUrl = _globalSettings.GetKey("OAuthCallbackUrl");
|
||||
|
||||
var form = new Dictionary<string, string>
|
||||
{
|
||||
{"client_id", appInfo.Id.ToString()},
|
||||
{"client_secret", accessToken},
|
||||
{"grant_type", "authorization_code"},
|
||||
{"code", code},
|
||||
{"scope", "identify email guilds"},
|
||||
{"redirect_uri", callbackUrl}
|
||||
};
|
||||
|
||||
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
|
||||
var result = await client.PostAsync("/api/oauth2/token", new FormUrlEncodedContent(form));
|
||||
result.EnsureSuccessStatusCode();
|
||||
|
||||
var stringResponse = await result.Content.ReadAsStringAsync();
|
||||
var responseData = JsonConvert.DeserializeObject<CallbackTokenResponseDto>(stringResponse);
|
||||
token = responseData.access_token;
|
||||
}
|
||||
|
||||
return new RedirectResult($"https://geekbot.pizzaandcoffee.rocks/login?token={token}", false);
|
||||
}
|
||||
}
|
||||
}
|
11
src/Web/Controllers/Callback/CallbackTokenResponseDto.cs
Normal file
11
src/Web/Controllers/Callback/CallbackTokenResponseDto.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Geekbot.Web.Controllers.Callback
|
||||
{
|
||||
public class CallbackTokenResponseDto
|
||||
{
|
||||
public string access_token { get; set; }
|
||||
public string token_type { get; set; }
|
||||
public int expires_in { get; set; }
|
||||
public string refresh_token { get; set; }
|
||||
public string scope { get; set; }
|
||||
}
|
||||
}
|
41
src/Web/Controllers/Commands/CommandController.cs
Normal file
41
src/Web/Controllers/Commands/CommandController.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using System.Linq;
|
||||
using Discord.Commands;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Geekbot.Web.Controllers.Commands
|
||||
{
|
||||
[EnableCors("AllowSpecificOrigin")]
|
||||
public class CommandController : Controller
|
||||
{
|
||||
private readonly CommandService _commands;
|
||||
|
||||
public CommandController(CommandService commands)
|
||||
{
|
||||
_commands = commands;
|
||||
}
|
||||
|
||||
[Route("/v1/commands")]
|
||||
public IActionResult GetCommands()
|
||||
{
|
||||
var commandList = (from cmd in _commands.Commands
|
||||
let cmdParamsObj = cmd.Parameters.Select(cmdParam => new CommandParamDto
|
||||
{
|
||||
Summary = cmdParam.Summary,
|
||||
Default = cmdParam.DefaultValue?.ToString(),
|
||||
Type = cmdParam.Type?.ToString()
|
||||
})
|
||||
.ToList()
|
||||
let param = string.Join(", !", cmd.Aliases)
|
||||
select new CommandDto
|
||||
{
|
||||
Name = cmd.Name,
|
||||
Summary = cmd.Summary,
|
||||
IsAdminCommand = param.Contains("admin") || param.Contains("owner"),
|
||||
Aliases = cmd.Aliases.ToList(),
|
||||
Params = cmdParamsObj
|
||||
}).ToList();
|
||||
return Ok(commandList.FindAll(e => !e.Aliases[0].StartsWith("owner")));
|
||||
}
|
||||
}
|
||||
}
|
13
src/Web/Controllers/Commands/CommandDto.cs
Normal file
13
src/Web/Controllers/Commands/CommandDto.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Geekbot.Web.Controllers.Commands
|
||||
{
|
||||
public class CommandDto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Summary { get; set; }
|
||||
public bool IsAdminCommand { get; set; }
|
||||
public List<string> Aliases { get; set; }
|
||||
public List<CommandParamDto> Params { get; set; }
|
||||
}
|
||||
}
|
9
src/Web/Controllers/Commands/CommandParamDto.cs
Normal file
9
src/Web/Controllers/Commands/CommandParamDto.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Geekbot.Web.Controllers.Commands
|
||||
{
|
||||
public class CommandParamDto
|
||||
{
|
||||
public string Summary { get; set; }
|
||||
public string Default { get; set; }
|
||||
public string Type { get; set; }
|
||||
}
|
||||
}
|
56
src/Web/Controllers/Highscores/HighscoreController.cs
Normal file
56
src/Web/Controllers/Highscores/HighscoreController.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
using System.Collections.Generic;
|
||||
using Geekbot.Core.Highscores;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Geekbot.Web.Controllers.Highscores
|
||||
{
|
||||
[EnableCors("AllowSpecificOrigin")]
|
||||
public class HighscoreController : Controller
|
||||
{
|
||||
private readonly IHighscoreManager _highscoreManager;
|
||||
|
||||
public HighscoreController(IHighscoreManager highscoreManager)
|
||||
{
|
||||
_highscoreManager = highscoreManager;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("/v1/highscore")]
|
||||
public IActionResult GetHighscores([FromBody] HighscoreControllerPostBodyDto body)
|
||||
{
|
||||
if (!ModelState.IsValid || body == null)
|
||||
{
|
||||
var error = new SerializableError(ModelState);
|
||||
return BadRequest(error);
|
||||
}
|
||||
|
||||
Dictionary<HighscoreUserDto, int> list;
|
||||
try
|
||||
{
|
||||
list = _highscoreManager.GetHighscoresWithUserData(body.Type, body.GuildId, body.Amount);
|
||||
}
|
||||
catch (HighscoreListEmptyException)
|
||||
{
|
||||
return NotFound(new ApiError
|
||||
{
|
||||
Message = $"No {body.Type} found on this server"
|
||||
});
|
||||
}
|
||||
|
||||
var response = new List<HighscoreControllerReponseBody>();
|
||||
var counter = 1;
|
||||
foreach (var item in list)
|
||||
{
|
||||
response.Add(new HighscoreControllerReponseBody
|
||||
{
|
||||
count = item.Value,
|
||||
rank = counter,
|
||||
user = item.Key
|
||||
});
|
||||
counter++;
|
||||
}
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using Geekbot.Core.Highscores;
|
||||
|
||||
namespace Geekbot.Web.Controllers.Highscores
|
||||
{
|
||||
public class HighscoreControllerPostBodyDto
|
||||
{
|
||||
[Required]
|
||||
public ulong GuildId { get; set; }
|
||||
|
||||
public HighscoreTypes Type { get; } = HighscoreTypes.messages;
|
||||
|
||||
[Range(1, 150)]
|
||||
public int Amount { get; } = 50;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using Geekbot.Core.Highscores;
|
||||
|
||||
namespace Geekbot.Web.Controllers.Highscores
|
||||
{
|
||||
public class HighscoreControllerReponseBody
|
||||
{
|
||||
public int rank { get; set; }
|
||||
public HighscoreUserDto user { get; set; }
|
||||
public int count { get; set; }
|
||||
}
|
||||
}
|
9
src/Web/Controllers/Status/ApiStatusDto.cs
Normal file
9
src/Web/Controllers/Status/ApiStatusDto.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Geekbot.Web.Controllers.Status
|
||||
{
|
||||
public class ApiStatusDto
|
||||
{
|
||||
public string GeekbotVersion { get; set; }
|
||||
public string ApiVersion { get; set; }
|
||||
public string Status { get; set; }
|
||||
}
|
||||
}
|
23
src/Web/Controllers/Status/StatusController.cs
Normal file
23
src/Web/Controllers/Status/StatusController.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using System.Globalization;
|
||||
using Geekbot.Core;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Geekbot.Web.Controllers.Status
|
||||
{
|
||||
[EnableCors("AllowSpecificOrigin")]
|
||||
public class StatusController : Controller
|
||||
{
|
||||
[Route("/")]
|
||||
public IActionResult GetCommands()
|
||||
{
|
||||
var responseBody = new ApiStatusDto
|
||||
{
|
||||
GeekbotVersion = Constants.BotVersion(),
|
||||
ApiVersion = Constants.ApiVersion.ToString(CultureInfo.InvariantCulture),
|
||||
Status = "Online"
|
||||
};
|
||||
return Ok(responseBody);
|
||||
}
|
||||
}
|
||||
}
|
28
src/Web/Logging/AspLogProvider.cs
Normal file
28
src/Web/Logging/AspLogProvider.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using System.Collections.Concurrent;
|
||||
using Geekbot.Core.Logger;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Geekbot.Web.Logging
|
||||
{
|
||||
public class AspLogProvider : ILoggerProvider
|
||||
{
|
||||
private readonly IGeekbotLogger _geekbotLogger;
|
||||
|
||||
private readonly ConcurrentDictionary<string, AspLogger> _loggers = new ConcurrentDictionary<string, AspLogger>();
|
||||
|
||||
public AspLogProvider(IGeekbotLogger geekbotLogger)
|
||||
{
|
||||
_geekbotLogger = geekbotLogger;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_loggers.Clear();
|
||||
}
|
||||
|
||||
public ILogger CreateLogger(string categoryName)
|
||||
{
|
||||
return _loggers.GetOrAdd(categoryName, name => new AspLogger(categoryName, _geekbotLogger));
|
||||
}
|
||||
}
|
||||
}
|
71
src/Web/Logging/AspLogger.cs
Normal file
71
src/Web/Logging/AspLogger.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using Geekbot.Core.Logger;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Geekbot.Web.Logging
|
||||
{
|
||||
public class AspLogger : ILogger
|
||||
{
|
||||
private readonly string _categoryName;
|
||||
private readonly IGeekbotLogger _geekbotLogger;
|
||||
|
||||
public AspLogger(string categoryName, IGeekbotLogger geekbotLogger)
|
||||
{
|
||||
geekbotLogger.Trace(LogSource.Api, $"Adding {categoryName}");
|
||||
_categoryName = categoryName;
|
||||
_geekbotLogger = geekbotLogger;
|
||||
}
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
{
|
||||
switch (logLevel)
|
||||
{
|
||||
case LogLevel.Trace:
|
||||
_geekbotLogger.Trace(LogSource.Api, $"{eventId.Id} - {_categoryName} - {state}");
|
||||
break;
|
||||
case LogLevel.Debug:
|
||||
_geekbotLogger.Debug(LogSource.Api, $"{eventId.Id} - {_categoryName} - {state}");
|
||||
break;
|
||||
case LogLevel.Information:
|
||||
_geekbotLogger.Information(LogSource.Api, $"{eventId.Id} - {_categoryName} - {state}");
|
||||
break;
|
||||
case LogLevel.Warning:
|
||||
_geekbotLogger.Warning(LogSource.Api, $"{eventId.Id} - {_categoryName} - {state}", exception);
|
||||
break;
|
||||
case LogLevel.Error:
|
||||
case LogLevel.Critical:
|
||||
_geekbotLogger.Error(LogSource.Api, $"{eventId.Id} - {_categoryName} - {state}", exception);
|
||||
break;
|
||||
case LogLevel.None:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(logLevel));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
return !_geekbotLogger.LogAsJson() && _geekbotLogger.GetNLogger().IsEnabled(ToGeekbotLogLevel(logLevel));
|
||||
}
|
||||
|
||||
public IDisposable BeginScope<TState>(TState state)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private static NLog.LogLevel ToGeekbotLogLevel(LogLevel level)
|
||||
{
|
||||
return level switch
|
||||
{
|
||||
LogLevel.Trace => NLog.LogLevel.Trace,
|
||||
LogLevel.Debug => NLog.LogLevel.Debug,
|
||||
LogLevel.Information => NLog.LogLevel.Info,
|
||||
LogLevel.Warning => NLog.LogLevel.Warn,
|
||||
LogLevel.Error => NLog.LogLevel.Error,
|
||||
LogLevel.Critical => NLog.LogLevel.Fatal,
|
||||
LogLevel.None => NLog.LogLevel.Off,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(level))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
26
src/Web/Web.csproj
Normal file
26
src/Web/Web.csproj
Normal file
|
@ -0,0 +1,26 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<VersionSuffix>$(VersionSuffix)</VersionSuffix>
|
||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</Version>
|
||||
<Version Condition=" '$(VersionSuffix)' == '' ">0.0.0-DEV</Version>
|
||||
<RootNamespace>Geekbot.Web</RootNamespace>
|
||||
<AssemblyName>Geekbot.Web</AssemblyName>
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Cors" Version="2.2.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Core\Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
58
src/Web/WebApiStartup.cs
Normal file
58
src/Web/WebApiStartup.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
using System.Net;
|
||||
using System.Reflection;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.GlobalSettings;
|
||||
using Geekbot.Core.Highscores;
|
||||
using Geekbot.Core.Logger;
|
||||
using Geekbot.Web.Logging;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Geekbot.Web
|
||||
{
|
||||
public static class WebApiStartup
|
||||
{
|
||||
public static void StartWebApi(IGeekbotLogger logger, RunParameters runParameters, CommandService commandService,
|
||||
DatabaseContext databaseContext, DiscordSocketClient client, IGlobalSettings globalSettings, IHighscoreManager highscoreManager)
|
||||
{
|
||||
WebHost.CreateDefaultBuilder()
|
||||
.UseKestrel(options =>
|
||||
{
|
||||
options.Listen(IPAddress.Any, int.Parse(runParameters.ApiPort));
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddMvc();
|
||||
services.AddSingleton(commandService);
|
||||
services.AddSingleton(databaseContext);
|
||||
services.AddSingleton(client);
|
||||
services.AddSingleton(globalSettings);
|
||||
services.AddSingleton(highscoreManager);
|
||||
services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowSpecificOrigin",
|
||||
builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
|
||||
});
|
||||
})
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseMvc();
|
||||
app.UseCors(builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().Build());
|
||||
})
|
||||
.ConfigureLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.SetMinimumLevel(LogLevel.Debug);
|
||||
logging.AddProvider(new AspLogProvider(logger));
|
||||
})
|
||||
.UseSetting(WebHostDefaults.ApplicationKey, typeof(WebApiStartup).GetTypeInfo().Assembly.FullName)
|
||||
.Build().Run();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue