mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Workshop - Added profile uploading
Submission wizard - Final upload steps
This commit is contained in:
1 parent
e52faf1c9f
commit
ad4da3032d
32 files changed
+621
-93
No files matched your search
@@ -1,5 +1,9 @@
|
||||
using System.Reflection;
|
||||
using Artemis.WebClient.Workshop.Extensions;
|
||||
using Artemis.WebClient.Workshop.Repositories;
|
||||
using Artemis.WebClient.Workshop.Services;
|
||||
using Artemis.WebClient.Workshop.State;
|
||||
using Artemis.WebClient.Workshop.UploadHandlers;
|
||||
using DryIoc;
|
||||
using DryIoc.Microsoft.DependencyInjection;
|
||||
using IdentityModel.Client;
|
||||
@@ -18,11 +22,17 @@ public static class ContainerExtensions
|
||||
/// <param name="container">The builder building the current container</param>
|
||||
public static void RegisterWorkshopClient(this IContainer container)
|
||||
{
|
||||
Assembly[] workshopAssembly = {typeof(WorkshopConstants).Assembly};
|
||||
|
||||
ServiceCollection serviceCollection = new();
|
||||
serviceCollection
|
||||
.AddHttpClient()
|
||||
.AddWorkshopClient()
|
||||
.AddHttpMessageHandler<WorkshopClientStoreAccessor, AuthenticationDelegatingHandler>()
|
||||
.ConfigureHttpClient(client => client.BaseAddress = new Uri(WorkshopConstants.WORKSHOP_URL + "/graphql"));
|
||||
serviceCollection.AddHttpClient(WorkshopConstants.WORKSHOP_CLIENT_NAME)
|
||||
.AddHttpMessageHandler<AuthenticationDelegatingHandler>()
|
||||
.ConfigureHttpClient(client => client.BaseAddress = new Uri(WorkshopConstants.WORKSHOP_URL));
|
||||
|
||||
serviceCollection.AddSingleton<IDiscoveryCache>(r =>
|
||||
{
|
||||
@@ -34,5 +44,8 @@ public static class ContainerExtensions
|
||||
|
||||
container.Register<IAuthenticationRepository, AuthenticationRepository>(Reuse.Singleton);
|
||||
container.Register<IAuthenticationService, AuthenticationService>(Reuse.Singleton);
|
||||
|
||||
container.Register<EntryUploadHandlerFactory>(Reuse.Transient);
|
||||
container.RegisterMany(workshopAssembly, type => type.IsAssignableTo<IEntryUploadHandler>(), Reuse.Transient);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Artemis.Web.Workshop.Entities;
|
||||
|
||||
public class Release
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[MaxLength(64)]
|
||||
public string Version { get; set; } = string.Empty;
|
||||
|
||||
public DateTimeOffset CreatedAt { get; set; }
|
||||
|
||||
public long Downloads { get; set; }
|
||||
|
||||
public long DownloadSize { get; set; }
|
||||
|
||||
[MaxLength(32)]
|
||||
public string? Md5Hash { get; set; }
|
||||
|
||||
public Guid EntryId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Http;
|
||||
using StrawberryShake;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Extensions;
|
||||
|
||||
public static class ClientBuilderExtensions
|
||||
{
|
||||
public static IClientBuilder<T> AddHttpMessageHandler<T, THandler>(this IClientBuilder<T> builder) where THandler : DelegatingHandler where T : IStoreAccessor
|
||||
{
|
||||
builder.Services.Configure<HttpClientFactoryOptions>(
|
||||
builder.ClientName,
|
||||
options => options.HttpMessageHandlerBuilderActions.Add(b => b.AdditionalHandlers.Add(b.Services.GetRequiredService<THandler>()))
|
||||
);
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mutation AddEntry ($input: CreateEntryInput!) {
|
||||
addEntry(input: $input) {
|
||||
id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Services;
|
||||
|
||||
public class AuthenticationDelegatingHandler : DelegatingHandler
|
||||
{
|
||||
private readonly IAuthenticationService _authenticationService;
|
||||
|
||||
/// <inheritdoc />
|
||||
public AuthenticationDelegatingHandler(IAuthenticationService authenticationService)
|
||||
{
|
||||
_authenticationService = authenticationService;
|
||||
}
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
string? token = await _authenticationService.GetBearer();
|
||||
if (token != null)
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||
return await base.SendAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Artemis.WebClient.Workshop.UploadHandlers.Implementations;
|
||||
using DryIoc;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.UploadHandlers;
|
||||
|
||||
public class EntryUploadHandlerFactory
|
||||
{
|
||||
private readonly IContainer _container;
|
||||
|
||||
public EntryUploadHandlerFactory(IContainer container)
|
||||
{
|
||||
_container = container;
|
||||
}
|
||||
|
||||
public IEntryUploadHandler CreateHandler(EntryType entryType)
|
||||
{
|
||||
return entryType switch
|
||||
{
|
||||
EntryType.Profile => _container.Resolve<ProfileEntryUploadHandler>(),
|
||||
EntryType.Layout => _container.Resolve<LayoutEntryUploadHandler>(),
|
||||
_ => throw new NotSupportedException($"EntryType '{entryType}' is not supported.")
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Artemis.Web.Workshop.Entities;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.UploadHandlers;
|
||||
|
||||
public class EntryUploadResult
|
||||
{
|
||||
public bool IsSuccess { get; set; }
|
||||
public string? Message { get; set; }
|
||||
public Release? Release { get; set; }
|
||||
|
||||
public static EntryUploadResult FromFailure(string? message)
|
||||
{
|
||||
return new EntryUploadResult
|
||||
{
|
||||
IsSuccess = false,
|
||||
Message = message
|
||||
};
|
||||
}
|
||||
|
||||
public static EntryUploadResult FromSuccess(Release release)
|
||||
{
|
||||
return new EntryUploadResult
|
||||
{
|
||||
IsSuccess = true,
|
||||
Release = release
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
namespace Artemis.WebClient.Workshop.UploadHandlers;
|
||||
|
||||
public interface IEntryUploadHandler
|
||||
{
|
||||
Task<EntryUploadResult> CreateReleaseAsync(Guid entryId, object file, CancellationToken cancellationToken);
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
using RGB.NET.Layout;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.UploadHandlers.Implementations;
|
||||
|
||||
public class LayoutEntryUploadHandler : IEntryUploadHandler
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task<EntryUploadResult> CreateReleaseAsync(Guid entryId, object file, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
using System.IO.Compression;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Web.Workshop.Entities;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.UploadHandlers.Implementations;
|
||||
|
||||
public class ProfileEntryUploadHandler : IEntryUploadHandler
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IProfileService _profileService;
|
||||
|
||||
public ProfileEntryUploadHandler(IHttpClientFactory httpClientFactory, IProfileService profileService)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_profileService = profileService;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<EntryUploadResult> CreateReleaseAsync(Guid entryId, object file, CancellationToken cancellationToken)
|
||||
{
|
||||
if (file is not ProfileConfiguration profileConfiguration)
|
||||
throw new InvalidOperationException("Can only create releases for profile configurations");
|
||||
|
||||
ProfileConfigurationExportModel export = _profileService.ExportProfile(profileConfiguration);
|
||||
string json = JsonConvert.SerializeObject(export, IProfileService.ExportSettings);
|
||||
|
||||
using MemoryStream archiveStream = new();
|
||||
|
||||
// Create a ZIP archive with a single entry on the archive stream
|
||||
using (ZipArchive archive = new(archiveStream, ZipArchiveMode.Create, true))
|
||||
{
|
||||
ZipArchiveEntry entry = archive.CreateEntry("profile.json");
|
||||
await using (Stream entryStream = entry.Open())
|
||||
{
|
||||
await entryStream.WriteAsync(Encoding.Default.GetBytes(json), cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
// Submit the archive
|
||||
HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.WORKSHOP_CLIENT_NAME);
|
||||
|
||||
// Construct the request
|
||||
archiveStream.Seek(0, SeekOrigin.Begin);
|
||||
MultipartFormDataContent content = new();
|
||||
StreamContent streamContent = new(archiveStream);
|
||||
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/zip");
|
||||
content.Add(streamContent, "file", "file.zip");
|
||||
|
||||
// Submit
|
||||
HttpResponseMessage response = await client.PostAsync("releases/upload/" + entryId, content, cancellationToken);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return EntryUploadResult.FromFailure($"{response.StatusCode} - {await response.Content.ReadAsStringAsync(cancellationToken)}");
|
||||
|
||||
Release? release = JsonConvert.DeserializeObject<Release>(await response.Content.ReadAsStringAsync(cancellationToken));
|
||||
return release != null ? EntryUploadResult.FromSuccess(release) : EntryUploadResult.FromFailure("Failed to deserialize response");
|
||||
}
|
||||
}
|
||||
@@ -4,4 +4,5 @@ public static class WorkshopConstants
|
||||
{
|
||||
public const string AUTHORITY_URL = "https://identity.artemis-rgb.com";
|
||||
public const string WORKSHOP_URL = "https://workshop.artemis-rgb.com";
|
||||
public const string WORKSHOP_CLIENT_NAME = "WorkshopApiClient";
|
||||
}
|
||||
Reference in new issue
Block a user