Updated repository manager for the new backend

This commit is contained in:
2025-04-01 18:47:13 +03:00
parent a6ed4078ca
commit 62ba5ec63d
8 changed files with 62 additions and 170 deletions

View File

@@ -1,29 +1,39 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordBotCore.Interfaces.PluginManagement; using DiscordBotCore.Interfaces.PluginManagement;
using DiscordBotCore.Others; using DiscordBotCore.Others;
using DiscordBotCore.Plugin; using DiscordBotCore.Plugin;
using Microsoft.AspNetCore.Http.Extensions;
namespace DiscordBotCore.Online.Helpers; namespace DiscordBotCore.Online.Helpers;
public class PluginRepository : IPluginRepository public class PluginRepository : IPluginRepository
{ {
private readonly IPluginRepositoryConfiguration _pluginRepositoryConfiguration; private readonly IPluginRepositoryConfiguration _pluginRepositoryConfiguration;
public HttpClient _httpClient; private readonly HttpClient _httpClient;
public PluginRepository(IPluginRepositoryConfiguration pluginRepositoryConfiguration) public PluginRepository(IPluginRepositoryConfiguration pluginRepositoryConfiguration)
{ {
_pluginRepositoryConfiguration = pluginRepositoryConfiguration; _pluginRepositoryConfiguration = pluginRepositoryConfiguration;
_httpClient = new HttpClient(); _httpClient = new HttpClient();
_httpClient.BaseAddress = new System.Uri(_pluginRepositoryConfiguration.BaseUrl); _httpClient.BaseAddress = new Uri(_pluginRepositoryConfiguration.BaseUrl);
} }
public async Task<List<OnlinePlugin>> GetAllPlugins() public async Task<List<OnlinePlugin>> GetAllPlugins()
{ {
HttpResponseMessage response = int operatingSystem = OS.GetOperatingSystemInt();
await _httpClient.GetAsync(_pluginRepositoryConfiguration.PluginRepositoryLocation + "get-all-plugins"); bool includeNotApproved = false;
string url = CreateUrlWithQueryParams(_pluginRepositoryConfiguration.PluginRepositoryLocation,
"get-all-plugins", new Dictionary<string, string>
{
{ "operatingSystem", operatingSystem.ToString() },
{ "includeNotApproved", includeNotApproved.ToString() }
});
HttpResponseMessage response = await _httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
@@ -39,9 +49,13 @@ public class PluginRepository : IPluginRepository
public async Task<OnlinePlugin?> GetPluginById(int pluginId) public async Task<OnlinePlugin?> GetPluginById(int pluginId)
{ {
HttpResponseMessage response = string url = CreateUrlWithQueryParams(_pluginRepositoryConfiguration.PluginRepositoryLocation,
await _httpClient.GetAsync(_pluginRepositoryConfiguration.PluginRepositoryLocation + "get-plugin", new Dictionary<string, string>
$"get-plugin/{pluginId}"); {
{ "pluginId", pluginId.ToString() },
{ "includeNotApproved", "false" }
});
HttpResponseMessage response = await _httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
@@ -57,9 +71,14 @@ public class PluginRepository : IPluginRepository
public async Task<OnlinePlugin?> GetPluginByName(string pluginName) public async Task<OnlinePlugin?> GetPluginByName(string pluginName)
{ {
HttpResponseMessage response = string url = CreateUrlWithQueryParams(_pluginRepositoryConfiguration.PluginRepositoryLocation,
await _httpClient.GetAsync(_pluginRepositoryConfiguration.PluginRepositoryLocation + "get-plugin-by-name", new Dictionary<string, string>
$"get-plugin-by-name/{pluginName}"); {
{ "pluginName", pluginName },
{ "operatingSystem", OS.GetOperatingSystemInt().ToString() },
{ "includeNotApproved", "false" }
});
HttpResponseMessage response = await _httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
@@ -75,7 +94,13 @@ public class PluginRepository : IPluginRepository
public async Task<List<OnlineDependencyInfo>> GetDependenciesForPlugin(int pluginId) public async Task<List<OnlineDependencyInfo>> GetDependenciesForPlugin(int pluginId)
{ {
HttpResponseMessage response = await _httpClient.GetAsync(_pluginRepositoryConfiguration.DependenciesRepositoryLocation + $"get-dependencies-for-plugin/{pluginId}"); string url = CreateUrlWithQueryParams(_pluginRepositoryConfiguration.DependenciesRepositoryLocation,
"get-dependencies-for-plugin", new Dictionary<string, string>
{
{ "pluginId", pluginId.ToString() }
});
HttpResponseMessage response = await _httpClient.GetAsync(url);
if(!response.IsSuccessStatusCode) if(!response.IsSuccessStatusCode)
{ {
Application.Log("Failed to get dependencies for plugin from the repository", LogType.Warning); Application.Log("Failed to get dependencies for plugin from the repository", LogType.Warning);
@@ -87,4 +112,18 @@ public class PluginRepository : IPluginRepository
return dependencies; return dependencies;
} }
private string CreateUrlWithQueryParams(string baseUrl, string endpoint, Dictionary<string, string> queryParams)
{
QueryBuilder queryBuilder = new QueryBuilder();
foreach (var(key,value) in queryParams)
{
queryBuilder.Add(key, value);
}
string queryString = queryBuilder.ToQueryString().ToString();
string url = baseUrl + endpoint + queryString;
return url;
}
} }

View File

@@ -5,7 +5,9 @@ namespace DiscordBotCore.Online.Helpers;
public class PluginRepositoryConfiguration : IPluginRepositoryConfiguration public class PluginRepositoryConfiguration : IPluginRepositoryConfiguration
{ {
public static PluginRepositoryConfiguration Default => new ("http://localhost:5097/api/v1/", "plugins-repository/", "dependencies-repository/"); public static PluginRepositoryConfiguration Default => new ("http://localhost:8080/api/v1/",
"plugin/",
"dependency/");
public string BaseUrl { get; } public string BaseUrl { get; }
public string PluginRepositoryLocation { get; } public string PluginRepositoryLocation { get; }

View File

@@ -43,7 +43,7 @@ public sealed class PluginManager : IPluginManager
if (!onlinePlugins.Any()) if (!onlinePlugins.Any())
{ {
Application.Log("Failed to get all plugins from the repository", LogType.Warning); Application.Log("Could not get any plugins from the repository", LogType.Warning);
return []; return [];
} }

View File

@@ -1,45 +0,0 @@
using DiscordBotCore;
using DiscordBotCore.API.Endpoints.PluginManagement;
using DiscordBotCore.Online;
using DiscordBotCore.Plugin;
using Moq;
namespace SethCoreTests;
public class PluginInstallEndpointTests
{
private readonly Mock<IPluginManager> _mockPluginManager;
private readonly PluginInstallEndpoint _endpoint;
public PluginInstallEndpointTests()
{
_mockPluginManager = new Mock<IPluginManager>();
_endpoint = new PluginInstallEndpoint(_mockPluginManager.Object);
}
[Fact]
public async Task HandleRequest_SuccessfulPluginInstallation_ReturnsOk()
{
var pluginName = "TestPlugin";
var pluginInfo = new OnlinePlugin(1, pluginName, "Description", "1.0", "Author", "http://link", 1);
_mockPluginManager.Setup(pm => pm.GetPluginDataByName(pluginName)).ReturnsAsync(pluginInfo);
_mockPluginManager.Setup(pm => pm.InstallPluginNoProgress(pluginInfo)).Returns(Task.CompletedTask);
var jsonRequest = $"{{\"pluginName\":\"{pluginName}\"}}";
var response = await _endpoint.HandleRequest(jsonRequest);
Assert.True(response.Success);
}
[Fact]
public async Task HandleRequest_PluginNotFound_ReturnsFail()
{
var pluginName = "NonExistentPlugin";
_mockPluginManager.Setup(pm => pm.GetPluginDataByName(pluginName)).ReturnsAsync((OnlinePlugin?)null);
var jsonRequest = $"{{\"pluginName\":\"{pluginName}\"}}";
var response = await _endpoint.HandleRequest(jsonRequest);
Assert.False(response.Success);
}
}

View File

@@ -1,69 +0,0 @@
using System.Net;
using DiscordBotCore.Interfaces.PluginManagement;
using DiscordBotCore.Online.Helpers;
using Moq;
using Moq.Protected;
namespace SethCoreTests;
public class PluginRepositoryTests
{
private readonly Mock<IPluginRepositoryConfiguration> _mockConfig;
private readonly Mock<HttpMessageHandler> _mockHttpMessageHandler;
private readonly PluginRepository _pluginRepository;
public PluginRepositoryTests()
{
_mockConfig = new Mock<IPluginRepositoryConfiguration>();
_mockConfig.SetupGet(c => c.BaseUrl).Returns("http://localhost/");
_mockConfig.SetupGet(c => c.PluginRepositoryLocation).Returns("api/plugins/");
_mockConfig.SetupGet(c => c.DependenciesRepositoryLocation).Returns("api/dependencies/");
_mockHttpMessageHandler = new Mock<HttpMessageHandler>();
var httpClient = new HttpClient(_mockHttpMessageHandler.Object)
{
BaseAddress = new System.Uri(_mockConfig.Object.BaseUrl)
};
_pluginRepository = new PluginRepository(_mockConfig.Object)
{
_httpClient = httpClient
};
}
[Fact]
public async Task GetAllPlugins_ReturnsListOfPlugins()
{
var pluginsJson = "[{\"PluginId\":1,\"PluginName\":\"TestPlugin\",\"PluginDescription\":\"Description\",\"LatestVersion\":\"1.0\",\"PluginAuthor\":\"Author\",\"PluginLink\":\"http://link\",\"OperatingSystem\":1}]";
_mockHttpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(pluginsJson)
});
var result = await _pluginRepository.GetAllPlugins();
Assert.Single(result);
Assert.Equal("TestPlugin", result[0].PluginName);
}
[Fact]
public async Task GetPluginById_ReturnsPlugin()
{
var pluginJson = "{\"PluginId\":1,\"PluginName\":\"TestPlugin\",\"PluginDescription\":\"Description\",\"LatestVersion\":\"1.0\",\"PluginAuthor\":\"Author\",\"PluginLink\":\"http://link\",\"OperatingSystem\":1}";
_mockHttpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(pluginJson)
});
var result = await _pluginRepository.GetPluginById(1);
Assert.NotNull(result);
Assert.Equal("TestPlugin", result.PluginName);
}
}

View File

@@ -1,28 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit" Version="2.5.3"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
</ItemGroup>
<ItemGroup>
<Using Include="Xunit"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DiscordBotCore\DiscordBotCore.csproj" />
</ItemGroup>
</Project>

View File

@@ -25,10 +25,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CppCompatibilityModule", "M
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordBotWebUI", "DiscordBotWebUI\DiscordBotWebUI.csproj", "{8683B195-B729-48BB-805A-D44CA98A0BF6}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordBotWebUI", "DiscordBotWebUI\DiscordBotWebUI.csproj", "{8683B195-B729-48BB-805A-D44CA98A0BF6}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SethTests", "SethTests", "{9D2F471B-89EE-4F17-B1EA-869069A9A3B8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SethCoreTests", "SethCoreTests\SethCoreTests.csproj", "{AB4BD8D1-7384-4669-9D75-3BBECFA0A96E}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -67,10 +63,6 @@ Global
{8683B195-B729-48BB-805A-D44CA98A0BF6}.Debug|Any CPU.Build.0 = Debug|Any CPU {8683B195-B729-48BB-805A-D44CA98A0BF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8683B195-B729-48BB-805A-D44CA98A0BF6}.Release|Any CPU.ActiveCfg = Release|Any CPU {8683B195-B729-48BB-805A-D44CA98A0BF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8683B195-B729-48BB-805A-D44CA98A0BF6}.Release|Any CPU.Build.0 = Release|Any CPU {8683B195-B729-48BB-805A-D44CA98A0BF6}.Release|Any CPU.Build.0 = Release|Any CPU
{AB4BD8D1-7384-4669-9D75-3BBECFA0A96E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AB4BD8D1-7384-4669-9D75-3BBECFA0A96E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB4BD8D1-7384-4669-9D75-3BBECFA0A96E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB4BD8D1-7384-4669-9D75-3BBECFA0A96E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -81,7 +73,6 @@ Global
{FCE9743F-7EB4-4639-A080-FCDDFCC7D689} = {5CF9AD7B-6BF0-4035-835F-722F989C01E1} {FCE9743F-7EB4-4639-A080-FCDDFCC7D689} = {5CF9AD7B-6BF0-4035-835F-722F989C01E1}
{F3C61A47-F758-4145-B496-E3ECCF979D89} = {5CF9AD7B-6BF0-4035-835F-722F989C01E1} {F3C61A47-F758-4145-B496-E3ECCF979D89} = {5CF9AD7B-6BF0-4035-835F-722F989C01E1}
{C67908F9-4A55-4DD8-B993-C26C648226F1} = {EA4FA308-7B2C-458E-8485-8747D745DD59} {C67908F9-4A55-4DD8-B993-C26C648226F1} = {EA4FA308-7B2C-458E-8485-8747D745DD59}
{AB4BD8D1-7384-4669-9D75-3BBECFA0A96E} = {9D2F471B-89EE-4F17-B1EA-869069A9A3B8}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3FB3C5DE-ED21-4D2E-ABDD-3A00EE4A2FFF} SolutionGuid = {3FB3C5DE-ED21-4D2E-ABDD-3A00EE4A2FFF}

View File

@@ -1,15 +1,17 @@
services: services:
discord-bot-client: discord-bot-client:
build: build:
context: . context: ./DiscordBot
dockerfile: DiscordBot/Dockerfile dockerfile: Dockerfile
tty: true tty: true
stdin_open: true stdin_open: true
discord-bot-webui: discord-bot-webui:
build: build:
context: . context: ./DiscordBotWebUI
dockerfile: DiscordBotWebUI/Dockerfile dockerfile: Dockerfile
ports:
- '4444:8080'
networks: networks: