Linked Plugin List and Plugin Install endpoints between web and console
This commit is contained in:
@@ -10,7 +10,7 @@ namespace DiscordBotCore.API.Endpoints.PluginManagement;
|
|||||||
public class PluginInstallEndpoint : IEndpoint
|
public class PluginInstallEndpoint : IEndpoint
|
||||||
{
|
{
|
||||||
public string Path => "/api/plugin/install";
|
public string Path => "/api/plugin/install";
|
||||||
public EndpointType HttpMethod => EndpointType.Put;
|
public EndpointType HttpMethod => EndpointType.Post;
|
||||||
public async Task<ApiResponse> HandleRequest(string? jsonRequest)
|
public async Task<ApiResponse> HandleRequest(string? jsonRequest)
|
||||||
{
|
{
|
||||||
Dictionary<string, string> jsonDict = await JsonManager.ConvertFromJson<Dictionary<string, string>>(jsonRequest);
|
Dictionary<string, string> jsonDict = await JsonManager.ConvertFromJson<Dictionary<string, string>>(jsonRequest);
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ public class PluginListEndpoint : IEndpoint
|
|||||||
{
|
{
|
||||||
var onlineInfos = await Application.CurrentApplication.PluginManager.GetPluginsList();
|
var onlineInfos = await Application.CurrentApplication.PluginManager.GetPluginsList();
|
||||||
|
|
||||||
var response = await JsonManager.ConvertToJson(onlineInfos, [nameof(PluginOnlineInfo.Name), nameof(PluginOnlineInfo.Author), nameof(PluginOnlineInfo.Version)]);
|
var response = await JsonManager.ConvertToJson(onlineInfos, [
|
||||||
|
nameof(PluginOnlineInfo.Name),
|
||||||
|
nameof(PluginOnlineInfo.Author),
|
||||||
|
nameof(PluginOnlineInfo.Description)
|
||||||
|
]);
|
||||||
|
|
||||||
return ApiResponse.From(response, true);
|
return ApiResponse.From(response, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public sealed class PluginManager
|
|||||||
_PluginRepository = pluginRepository;
|
_PluginRepository = pluginRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<PluginOnlineInfo>?> GetPluginsList()
|
public async Task<List<PluginOnlineInfo>> GetPluginsList()
|
||||||
{
|
{
|
||||||
var jsonText = await _PluginRepository.JsonGetAllPlugins();
|
var jsonText = await _PluginRepository.JsonGetAllPlugins();
|
||||||
List<PluginOnlineInfo> result = await JsonManager.ConvertFromJson<List<PluginOnlineInfo>>(jsonText);
|
List<PluginOnlineInfo> result = await JsonManager.ConvertFromJson<List<PluginOnlineInfo>>(jsonText);
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
<RadzenCard>
|
<RadzenCard>
|
||||||
<RadzenDataGrid Data="PluginModels" AllowPaging="true" AllowColumnResize="true" PageSize="5">
|
<RadzenDataGrid Data="PluginModels" AllowPaging="true" AllowColumnResize="true" PageSize="5">
|
||||||
<Columns>
|
<Columns>
|
||||||
<RadzenDataGridColumn Property="@nameof(PluginModel.PluginName)" Title="Plugin Name"/>
|
<RadzenDataGridColumn Property="@nameof(PluginModel.Name)" Title="Plugin Name"/>
|
||||||
<RadzenDataGridColumn Property="@nameof(PluginModel.PluginAuthor)" Title="Author"/>
|
<RadzenDataGridColumn Property="@nameof(PluginModel.Author)" Title="Author"/>
|
||||||
<RadzenDataGridColumn Property="@nameof(PluginModel.PluginDescription)" Title="Version"/>
|
<RadzenDataGridColumn Property="@nameof(PluginModel.Description)" Title="Version"/>
|
||||||
<RadzenDataGridColumn Title="Download">
|
<RadzenDataGridColumn Title="Download">
|
||||||
<Template Context="item">
|
<Template Context="item">
|
||||||
<RadzenButton Click="() => OnPluginDownloadClick!(item.PluginName)" Text="Download"/>
|
<RadzenButton Click="() => OnPluginDownloadClick!(item.Name)" Text="Download"/>
|
||||||
</Template>
|
</Template>
|
||||||
</RadzenDataGridColumn>
|
</RadzenDataGridColumn>
|
||||||
</Columns>
|
</Columns>
|
||||||
|
|||||||
@@ -1,24 +1,48 @@
|
|||||||
@page "/plugins"
|
@page "/plugins"
|
||||||
@using DiscordBotWebUI.Components.CustomTags
|
@using DiscordBotWebUI.Components.CustomTags
|
||||||
@using DiscordBotWebUI.Models
|
@using DiscordBotWebUI.Models
|
||||||
|
@using DiscordBotWebUI.ServerCommunication
|
||||||
|
|
||||||
<Marketplace PluginModels="_PluginModels" OnPluginDownloadClick="OnModelSelected"/>
|
<Marketplace PluginModels="_PluginModels" OnPluginDownloadClick="OnModelSelected"/>
|
||||||
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<PluginModel> _PluginModels;
|
private List<PluginModel> _PluginModels;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
public ApiHandler ApiHandler { get; set; }
|
||||||
|
|
||||||
private async void OnModelSelected(string itemName)
|
private async void OnModelSelected(string itemName)
|
||||||
{
|
{
|
||||||
Console.WriteLine(itemName);
|
ApiResponse response = await ApiHandler.PostAsync("/api/plugin/install", new Dictionary<string, string>()
|
||||||
}
|
{
|
||||||
|
{"pluginName", itemName}
|
||||||
|
});
|
||||||
|
if(!response.Success)
|
||||||
|
{
|
||||||
|
Console.WriteLine(response.Message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Plugin installed");
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
_PluginModels = new List<PluginModel>()
|
ApiResponse response = await ApiHandler.GetAsync("/api/plugin/list/online");
|
||||||
|
|
||||||
|
if (!response.Success)
|
||||||
{
|
{
|
||||||
new PluginModel() {PluginName = "Test", PluginAuthor = "Andrei", PluginDescription = "Interesting plugin"}
|
return;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
string jsonStr = response.Message;
|
||||||
|
var result = await JsonManager.ConvertFromJson<List<PluginModel>>(jsonStr);
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
_PluginModels = result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -38,8 +38,4 @@
|
|||||||
<_ContentIncludedByDefault Remove="Components\Pages\Setup\SetupWizard.razor" />
|
<_ContentIncludedByDefault Remove="Components\Pages\Setup\SetupWizard.razor" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="ServerCommunication\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace DiscordBotWebUI.Models;
|
namespace DiscordBotWebUI.Models;
|
||||||
|
|
||||||
public class PluginModel
|
public class PluginModel
|
||||||
{
|
{
|
||||||
public string PluginName { get; set; }
|
public string Name { get; set; }
|
||||||
public string PluginAuthor { get; set; }
|
public string Author { get; set; }
|
||||||
public string PluginDescription { get; set; }
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
[JsonConstructor]
|
||||||
|
public PluginModel(string name, string author, string description)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Author = author;
|
||||||
|
Description = description;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using DiscordBotWebUI.Components;
|
using DiscordBotWebUI.Components;
|
||||||
|
using DiscordBotWebUI.ServerCommunication;
|
||||||
|
using DiscordBotWebUI.ServerCommunication.ApiSettings;
|
||||||
using Radzen;
|
using Radzen;
|
||||||
|
|
||||||
|
|
||||||
@@ -33,6 +35,9 @@ builder.Services.AddRadzenCookieThemeService(options =>
|
|||||||
options.Duration = TimeSpan.FromDays(365); // The duration of the cookie
|
options.Duration = TimeSpan.FromDays(365); // The duration of the cookie
|
||||||
});
|
});
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<IApiSettings>(new ApiSettings("http://localhost", "5000"));
|
||||||
|
builder.Services.AddSingleton<ApiHandler>();
|
||||||
|
|
||||||
builder.Services.AddRadzenComponents();
|
builder.Services.AddRadzenComponents();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|||||||
55
DiscordBotWebUI/ServerCommunication/ApiHandler.cs
Normal file
55
DiscordBotWebUI/ServerCommunication/ApiHandler.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text;
|
||||||
|
using DiscordBotWebUI.ServerCommunication.ApiSettings;
|
||||||
|
|
||||||
|
namespace DiscordBotWebUI.ServerCommunication;
|
||||||
|
|
||||||
|
public class ApiHandler
|
||||||
|
{
|
||||||
|
private IApiSettings ApiSettings { get; }
|
||||||
|
public ApiHandler(IApiSettings apiSettings)
|
||||||
|
{
|
||||||
|
ApiSettings = apiSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse> GetAsync(string endpoint)
|
||||||
|
{
|
||||||
|
using HttpClient client = new HttpClient();
|
||||||
|
client.BaseAddress = new Uri($"{ApiSettings.BaseUrl}:{ApiSettings.BasePort}");
|
||||||
|
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||||
|
HttpResponseMessage response = await client.GetAsync(endpoint);
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
string content = await response.Content.ReadAsStringAsync();
|
||||||
|
return await JsonManager.ConvertFromJson<ApiResponse>(content);
|
||||||
|
}
|
||||||
|
return new ApiResponse("Failed to get response", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse> PostAsync(string endpoint, Dictionary<string, string> jsonValues)
|
||||||
|
{
|
||||||
|
if (jsonValues.Count <= 0)
|
||||||
|
{
|
||||||
|
return new ApiResponse("No values to post", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
string jsonString = await JsonManager.ConvertToJsonString(jsonValues);
|
||||||
|
return await PostAsync(endpoint, jsonString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse> PostAsync(string endpoint, string json)
|
||||||
|
{
|
||||||
|
using HttpClient client = new HttpClient();
|
||||||
|
client.BaseAddress = new Uri($"{ApiSettings.BaseUrl}:{ApiSettings.BasePort}");
|
||||||
|
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||||
|
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||||
|
HttpResponseMessage response = await client.PostAsync(endpoint, content);
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
string responseContent = await response.Content.ReadAsStringAsync();
|
||||||
|
return await JsonManager.ConvertFromJson<ApiResponse>(responseContent);
|
||||||
|
}
|
||||||
|
return new ApiResponse("Failed to get response", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
16
DiscordBotWebUI/ServerCommunication/ApiResponse.cs
Normal file
16
DiscordBotWebUI/ServerCommunication/ApiResponse.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace DiscordBotWebUI.ServerCommunication;
|
||||||
|
|
||||||
|
public class ApiResponse
|
||||||
|
{
|
||||||
|
public bool Success { get; }
|
||||||
|
public string Message { get; }
|
||||||
|
|
||||||
|
[JsonConstructor]
|
||||||
|
public ApiResponse(string message, bool success)
|
||||||
|
{
|
||||||
|
Message = message;
|
||||||
|
Success = success;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace DiscordBotWebUI.ServerCommunication.ApiSettings;
|
||||||
|
|
||||||
|
public class ApiSettings : IApiSettings
|
||||||
|
{
|
||||||
|
public string BaseUrl { get; }
|
||||||
|
public string BasePort { get; }
|
||||||
|
|
||||||
|
public ApiSettings(string baseUrl, string basePort)
|
||||||
|
{
|
||||||
|
BaseUrl = baseUrl;
|
||||||
|
BasePort = basePort;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace DiscordBotWebUI.ServerCommunication.ApiSettings;
|
||||||
|
|
||||||
|
public interface IApiSettings
|
||||||
|
{
|
||||||
|
public string BaseUrl { get; }
|
||||||
|
public string BasePort { get; }
|
||||||
|
}
|
||||||
31
DiscordBotWebUI/ServerCommunication/JsonManager.cs
Normal file
31
DiscordBotWebUI/ServerCommunication/JsonManager.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace DiscordBotWebUI.ServerCommunication;
|
||||||
|
|
||||||
|
public class JsonManager
|
||||||
|
{
|
||||||
|
public static async Task<T?> ConvertFromJson<T>(string jsonString)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(jsonString))
|
||||||
|
throw new ArgumentException("JSON string cannot be null or empty.", nameof(jsonString));
|
||||||
|
|
||||||
|
using MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await JsonSerializer.DeserializeAsync<T>(stream);
|
||||||
|
}
|
||||||
|
catch (JsonException ex)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Failed to deserialize JSON.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<string> ConvertToJsonString<T>(T data)
|
||||||
|
{
|
||||||
|
using MemoryStream stream = new MemoryStream();
|
||||||
|
await JsonSerializer.SerializeAsync(stream, data);
|
||||||
|
return Encoding.UTF8.GetString(stream.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user