mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 11:26:27 +00:00
Settings - Added account management
This commit is contained in:
1 parent
3952a268d1
commit
a2fe5d5d08
42 files changed
+681
-30
No files matched your search
@@ -33,6 +33,11 @@ public static class ContainerExtensions
|
||||
.AddWorkshopClient()
|
||||
.AddHttpMessageHandler<WorkshopClientStoreAccessor, AuthenticationDelegatingHandler>()
|
||||
.ConfigureHttpClient(client => client.BaseAddress = new Uri(WorkshopConstants.WORKSHOP_URL + "/graphql"));
|
||||
|
||||
serviceCollection.AddHttpClient(WorkshopConstants.IDENTITY_CLIENT_NAME)
|
||||
.AddHttpMessageHandler<AuthenticationDelegatingHandler>()
|
||||
.ConfigureHttpClient(client => client.BaseAddress = new Uri(WorkshopConstants.AUTHORITY_URL));
|
||||
|
||||
serviceCollection.AddHttpClient(WorkshopConstants.WORKSHOP_CLIENT_NAME)
|
||||
.AddHttpMessageHandler<AuthenticationDelegatingHandler>()
|
||||
.ConfigureHttpClient(client => client.BaseAddress = new Uri(WorkshopConstants.WORKSHOP_URL));
|
||||
@@ -49,7 +54,8 @@ public static class ContainerExtensions
|
||||
container.Register<IAuthenticationService, AuthenticationService>(Reuse.Singleton);
|
||||
container.Register<IWorkshopService, WorkshopService>(Reuse.Singleton);
|
||||
container.Register<ILayoutProvider, WorkshopLayoutProvider>(Reuse.Singleton);
|
||||
|
||||
container.Register<IUserManagementService, UserManagementService>();
|
||||
|
||||
container.Register<EntryUploadHandlerFactory>(Reuse.Transient);
|
||||
container.RegisterMany(workshopAssembly, type => type.IsAssignableTo<IEntryUploadHandler>(), Reuse.Transient);
|
||||
container.RegisterMany(workshopAssembly, type => type.IsAssignableTo<IEntryInstallationHandler>(), Reuse.Transient);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Artemis.WebClient.Workshop.Services;
|
||||
using Artemis.WebClient.Workshop.Models;
|
||||
using Artemis.WebClient.Workshop.Services;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers;
|
||||
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
using Artemis.UI.Shared.Utilities;
|
||||
using Artemis.WebClient.Workshop.Models;
|
||||
using Artemis.WebClient.Workshop.Services;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers;
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ using Artemis.Core.Providers;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared.Extensions;
|
||||
using Artemis.UI.Shared.Utilities;
|
||||
using Artemis.WebClient.Workshop.Models;
|
||||
using Artemis.WebClient.Workshop.Providers;
|
||||
using Artemis.WebClient.Workshop.Services;
|
||||
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared.Extensions;
|
||||
using Artemis.UI.Shared.Utilities;
|
||||
using Artemis.WebClient.Workshop.Models;
|
||||
using Artemis.WebClient.Workshop.Services;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers;
|
||||
|
||||
+5
-5
@@ -1,21 +1,21 @@
|
||||
namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||
|
||||
public class ImageUploadResult
|
||||
public class ApiResult
|
||||
{
|
||||
public bool IsSuccess { get; set; }
|
||||
public string? Message { get; set; }
|
||||
|
||||
public static ImageUploadResult FromFailure(string? message)
|
||||
public static ApiResult FromFailure(string? message)
|
||||
{
|
||||
return new ImageUploadResult
|
||||
return new ApiResult
|
||||
{
|
||||
IsSuccess = false,
|
||||
Message = message
|
||||
};
|
||||
}
|
||||
|
||||
public static ImageUploadResult FromSuccess()
|
||||
public static ApiResult FromSuccess()
|
||||
{
|
||||
return new ImageUploadResult {IsSuccess = true};
|
||||
return new ApiResult {IsSuccess = true};
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.WebClient.Workshop.Exceptions;
|
||||
using IdentityModel.Client;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Services;
|
||||
namespace Artemis.WebClient.Workshop.Models;
|
||||
|
||||
internal class AuthenticationToken
|
||||
{
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.Storage.Entities.Workshop;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Services;
|
||||
namespace Artemis.WebClient.Workshop.Models;
|
||||
|
||||
public class InstalledEntry
|
||||
{
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Artemis.WebClient.Workshop.Models;
|
||||
|
||||
public record PersonalAccessToken(string Key, DateTime CreationTime, DateTime? Expiration, string? Description);
|
||||
@@ -1,5 +1,6 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Providers;
|
||||
using Artemis.WebClient.Workshop.Models;
|
||||
using Artemis.WebClient.Workshop.Services;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Providers;
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Artemis.Core;
|
||||
using Artemis.WebClient.Workshop.Exceptions;
|
||||
using Artemis.WebClient.Workshop.Models;
|
||||
using Artemis.WebClient.Workshop.Repositories;
|
||||
using DynamicData;
|
||||
using IdentityModel;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||
using Artemis.WebClient.Workshop.Models;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Services;
|
||||
|
||||
public interface IUserManagementService : IProtectedArtemisService
|
||||
{
|
||||
Task<ApiResult> ChangePassword(string currentPassword, string newPassword, CancellationToken cancellationToken);
|
||||
Task<ApiResult> ChangeEmailAddress(string emailAddress, CancellationToken cancellationToken);
|
||||
Task<ApiResult> ChangeAvatar(Stream avatar, CancellationToken cancellationToken);
|
||||
Task<ApiResult> RemoveAccount(CancellationToken cancellationToken);
|
||||
Task<string> CreatePersonAccessToken(string description, DateTimeOffset expirationDate, CancellationToken cancellationToken);
|
||||
Task<ApiResult> DeletePersonAccessToken(PersonalAccessToken personalAccessToken, CancellationToken cancellationToken);
|
||||
Task<List<PersonalAccessToken>> GetPersonAccessTokens(CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
using Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||
using Artemis.WebClient.Workshop.Models;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Services;
|
||||
|
||||
public interface IWorkshopService
|
||||
{
|
||||
Task<Stream?> GetEntryIcon(long entryId, CancellationToken cancellationToken);
|
||||
Task<ImageUploadResult> SetEntryIcon(long entryId, Stream icon, CancellationToken cancellationToken);
|
||||
Task<ImageUploadResult> UploadEntryImage(long entryId, ImageUploadRequest request, CancellationToken cancellationToken);
|
||||
Task<ApiResult> SetEntryIcon(long entryId, Stream icon, CancellationToken cancellationToken);
|
||||
Task<ApiResult> UploadEntryImage(long entryId, ImageUploadRequest request, CancellationToken cancellationToken);
|
||||
Task DeleteEntryImage(Guid id, CancellationToken cancellationToken);
|
||||
Task<WorkshopStatus> GetWorkshopStatus(CancellationToken cancellationToken);
|
||||
Task<bool> ValidateWorkshopStatus(CancellationToken cancellationToken);
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
using Artemis.WebClient.Workshop.Exceptions;
|
||||
using Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||
using Artemis.WebClient.Workshop.Models;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Services;
|
||||
|
||||
internal class UserManagementService : IUserManagementService
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
public UserManagementService(IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ApiResult> ChangePassword(string currentPassword, string newPassword, CancellationToken cancellationToken)
|
||||
{
|
||||
HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.IDENTITY_CLIENT_NAME);
|
||||
HttpResponseMessage response = await client.PostAsync("user/credentials", JsonContent.Create(new {CurrentPassword = currentPassword, NewPassword = newPassword}), cancellationToken);
|
||||
return response.IsSuccessStatusCode
|
||||
? ApiResult.FromSuccess()
|
||||
: ApiResult.FromFailure(await response.Content.ReadAsStringAsync(cancellationToken));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ApiResult> ChangeEmailAddress(string emailAddress, CancellationToken cancellationToken)
|
||||
{
|
||||
HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.IDENTITY_CLIENT_NAME);
|
||||
HttpResponseMessage response = await client.PostAsync("user/email", JsonContent.Create(new {EmailAddress = emailAddress}), cancellationToken);
|
||||
return response.IsSuccessStatusCode
|
||||
? ApiResult.FromSuccess()
|
||||
: ApiResult.FromFailure(await response.Content.ReadAsStringAsync(cancellationToken));
|
||||
}
|
||||
|
||||
public async Task<ApiResult> ChangeAvatar(Stream avatar, CancellationToken cancellationToken)
|
||||
{
|
||||
avatar.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// Submit the archive
|
||||
HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.IDENTITY_CLIENT_NAME);
|
||||
|
||||
// Construct the request
|
||||
MultipartFormDataContent content = new();
|
||||
StreamContent streamContent = new(avatar);
|
||||
streamContent.Headers.ContentType = new MediaTypeHeaderValue("image/png");
|
||||
content.Add(streamContent, "file", "file.png");
|
||||
|
||||
// Submit
|
||||
HttpResponseMessage response = await client.PutAsync($"user/avatar", content, cancellationToken);
|
||||
return response.IsSuccessStatusCode
|
||||
? ApiResult.FromSuccess()
|
||||
: ApiResult.FromFailure(await response.Content.ReadAsStringAsync(cancellationToken));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ApiResult> RemoveAccount(CancellationToken cancellationToken)
|
||||
{
|
||||
HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.IDENTITY_CLIENT_NAME);
|
||||
HttpResponseMessage response = await client.DeleteAsync("user", cancellationToken);
|
||||
return response.IsSuccessStatusCode
|
||||
? ApiResult.FromSuccess()
|
||||
: ApiResult.FromFailure(await response.Content.ReadAsStringAsync(cancellationToken));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<string> CreatePersonAccessToken(string description, DateTimeOffset expirationDate, CancellationToken cancellationToken)
|
||||
{
|
||||
HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.IDENTITY_CLIENT_NAME);
|
||||
HttpResponseMessage response = await client.PostAsync("user/access-token", JsonContent.Create(new {Description = description, ExpirationDate = expirationDate}), cancellationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
string? result = await response.Content.ReadFromJsonAsync<string>(cancellationToken: cancellationToken);
|
||||
if (result == null)
|
||||
throw new ArtemisWebClientException("Failed to deserialize access token");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ApiResult> DeletePersonAccessToken(PersonalAccessToken personalAccessToken, CancellationToken cancellationToken)
|
||||
{
|
||||
HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.IDENTITY_CLIENT_NAME);
|
||||
HttpResponseMessage response = await client.DeleteAsync($"user/access-token/{personalAccessToken.Key}", cancellationToken);
|
||||
return response.IsSuccessStatusCode
|
||||
? ApiResult.FromSuccess()
|
||||
: ApiResult.FromFailure(await response.Content.ReadAsStringAsync(cancellationToken));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<PersonalAccessToken>> GetPersonAccessTokens(CancellationToken cancellationToken)
|
||||
{
|
||||
HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.IDENTITY_CLIENT_NAME);
|
||||
HttpResponseMessage response = await client.GetAsync("user/access-token", cancellationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
List<PersonalAccessToken>? result = await response.Content.ReadFromJsonAsync<List<PersonalAccessToken>>(cancellationToken: cancellationToken);
|
||||
if (result == null)
|
||||
throw new ArtemisWebClientException("Failed to deserialize access tokens");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@ using System.Net.Http.Headers;
|
||||
using Artemis.Storage.Entities.Workshop;
|
||||
using Artemis.Storage.Repositories.Interfaces;
|
||||
using Artemis.UI.Shared.Routing;
|
||||
using Artemis.UI.Shared.Utilities;
|
||||
using Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||
using Artemis.WebClient.Workshop.Models;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Services;
|
||||
|
||||
@@ -36,7 +36,7 @@ public class WorkshopService : IWorkshopService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ImageUploadResult> SetEntryIcon(long entryId, Stream icon, CancellationToken cancellationToken)
|
||||
public async Task<ApiResult> SetEntryIcon(long entryId, Stream icon, CancellationToken cancellationToken)
|
||||
{
|
||||
icon.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
@@ -52,12 +52,12 @@ public class WorkshopService : IWorkshopService
|
||||
// Submit
|
||||
HttpResponseMessage response = await client.PostAsync($"entries/{entryId}/icon", content, cancellationToken);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return ImageUploadResult.FromFailure($"{response.StatusCode} - {await response.Content.ReadAsStringAsync(cancellationToken)}");
|
||||
return ImageUploadResult.FromSuccess();
|
||||
return ApiResult.FromFailure($"{response.StatusCode} - {await response.Content.ReadAsStringAsync(cancellationToken)}");
|
||||
return ApiResult.FromSuccess();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ImageUploadResult> UploadEntryImage(long entryId, ImageUploadRequest request, CancellationToken cancellationToken)
|
||||
public async Task<ApiResult> UploadEntryImage(long entryId, ImageUploadRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
request.File.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
@@ -76,8 +76,8 @@ public class WorkshopService : IWorkshopService
|
||||
// Submit
|
||||
HttpResponseMessage response = await client.PostAsync($"entries/{entryId}/image", content, cancellationToken);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return ImageUploadResult.FromFailure($"{response.StatusCode} - {await response.Content.ReadAsStringAsync(cancellationToken)}");
|
||||
return ImageUploadResult.FromSuccess();
|
||||
return ApiResult.FromFailure($"{response.StatusCode} - {await response.Content.ReadAsStringAsync(cancellationToken)}");
|
||||
return ApiResult.FromSuccess();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -6,5 +6,6 @@ public static class WorkshopConstants
|
||||
// public const string WORKSHOP_URL = "https://localhost:7281";
|
||||
public const string AUTHORITY_URL = "https://identity.artemis-rgb.com";
|
||||
public const string WORKSHOP_URL = "https://workshop.artemis-rgb.com";
|
||||
public const string IDENTITY_CLIENT_NAME = "IdentityApiClient";
|
||||
public const string WORKSHOP_CLIENT_NAME = "WorkshopApiClient";
|
||||
}
|
||||
Reference in new issue
Block a user