From c69be2836ee8e2b5f3529caa2617ea6fc8a492df Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 6 Sep 2023 20:39:43 +0200 Subject: [PATCH] Workshop - Added installed entries and update profiles when reinstalling them --- .../Models/Profile/ProfileCategory.cs | 1 + .../Storage/Interfaces/IProfileService.cs | 14 +++- .../Services/Storage/ProfileService.cs | 15 +++- .../Entities/Workshop/EntryEntity.cs | 21 ++++++ .../Repositories/EntryRepository.cs | 54 ++++++++++++++ .../Interfaces/IEntryRepository.cs | 16 ++++ .../Profile/ProfileDetailsViewModel.cs | 8 +- .../Screens/Workshop/Search/SearchView.axaml | 7 +- .../Workshop/Search/SearchViewModel.cs | 10 ++- ...andler.cs => IEntryInstallationHandler.cs} | 2 +- .../ProfileEntryDownloadHandler.cs | 36 --------- .../ProfileEntryInstallationHandler.cs | 73 +++++++++++++++++++ .../DryIoc/ContainerExtensions.cs | 2 +- .../Services/InstalledEntry.cs | 72 ++++++++++++++++++ .../IAuthenticationService.cs | 0 .../Services/Interfaces/IWorkshopService.cs | 18 +++++ ...IWorkshopService.cs => WorkshopService.cs} | 36 ++++++--- 17 files changed, 327 insertions(+), 58 deletions(-) create mode 100644 src/Artemis.Storage/Entities/Workshop/EntryEntity.cs create mode 100644 src/Artemis.Storage/Repositories/EntryRepository.cs create mode 100644 src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs rename src/Artemis.WebClient.Workshop/DownloadHandlers/{IEntryDownloadHandler.cs => IEntryInstallationHandler.cs} (69%) delete mode 100644 src/Artemis.WebClient.Workshop/DownloadHandlers/Implementations/ProfileEntryDownloadHandler.cs create mode 100644 src/Artemis.WebClient.Workshop/DownloadHandlers/Implementations/ProfileEntryInstallationHandler.cs create mode 100644 src/Artemis.WebClient.Workshop/Services/InstalledEntry.cs rename src/Artemis.WebClient.Workshop/Services/{ => Interfaces}/IAuthenticationService.cs (100%) create mode 100644 src/Artemis.WebClient.Workshop/Services/Interfaces/IWorkshopService.cs rename src/Artemis.WebClient.Workshop/Services/{IWorkshopService.cs => WorkshopService.cs} (83%) diff --git a/src/Artemis.Core/Models/Profile/ProfileCategory.cs b/src/Artemis.Core/Models/Profile/ProfileCategory.cs index 13a3e2f4b..4dc3f73e6 100644 --- a/src/Artemis.Core/Models/Profile/ProfileCategory.cs +++ b/src/Artemis.Core/Models/Profile/ProfileCategory.cs @@ -98,6 +98,7 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel /// public void AddProfileConfiguration(ProfileConfiguration configuration, int? targetIndex) { + // TODO: Look into this, it doesn't seem to make sense // Removing the original will shift every item in the list forwards, keep that in mind with the target index if (configuration.Category == this && targetIndex != null && targetIndex.Value > _profileConfigurations.IndexOf(configuration)) targetIndex -= 1; diff --git a/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs b/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs index 1f1eccf8c..59fae7a9d 100644 --- a/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs +++ b/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs @@ -127,7 +127,7 @@ public interface IProfileService : IArtemisService Task ExportProfile(ProfileConfiguration profileConfiguration); /// - /// Imports the provided base64 encoded GZIPed JSON as a profile configuration. + /// Imports the provided ZIP archive stream as a profile configuration. /// /// The zip archive containing the profile to import. /// The in which to import the profile. @@ -137,8 +137,17 @@ public interface IProfileService : IArtemisService /// any changes are made to it. /// /// Text to add after the name of the profile (separated by a dash). + /// The index at which to import the profile into the category. /// The resulting profile configuration. - Task ImportProfile(Stream archiveStream, ProfileCategory category, bool makeUnique, bool markAsFreshImport, string? nameAffix = "imported"); + Task ImportProfile(Stream archiveStream, ProfileCategory category, bool makeUnique, bool markAsFreshImport, string? nameAffix = "imported", int targetIndex = 0); + + /// + /// Imports the provided ZIP archive stream into the provided profile configuration + /// + /// The zip archive containing the profile to import. + /// The profile configuration to overwrite. + /// The resulting profile configuration. + Task OverwriteProfile(MemoryStream archiveStream, ProfileConfiguration profileConfiguration); /// /// Adapts a given profile to the currently active devices. @@ -176,4 +185,5 @@ public interface IProfileService : IArtemisService /// Occurs whenever a profile category is removed. /// public event EventHandler? ProfileCategoryRemoved; + } \ No newline at end of file diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs index 3975713f2..7321fc6b2 100644 --- a/src/Artemis.Core/Services/Storage/ProfileService.cs +++ b/src/Artemis.Core/Services/Storage/ProfileService.cs @@ -438,7 +438,7 @@ internal class ProfileService : IProfileService } /// - public async Task ImportProfile(Stream archiveStream, ProfileCategory category, bool makeUnique, bool markAsFreshImport, string? nameAffix) + public async Task ImportProfile(Stream archiveStream, ProfileCategory category, bool makeUnique, bool markAsFreshImport, string? nameAffix, int targetIndex = 0) { using ZipArchive archive = new(archiveStream, ZipArchiveMode.Read, true); @@ -500,7 +500,7 @@ internal class ProfileService : IProfileService } profileConfiguration.Entity.ProfileId = profileEntity.Id; - category.AddProfileConfiguration(profileConfiguration, 0); + category.AddProfileConfiguration(profileConfiguration, targetIndex); List modules = _pluginManagementService.GetFeaturesOfType(); profileConfiguration.LoadModules(modules); @@ -509,6 +509,17 @@ internal class ProfileService : IProfileService return profileConfiguration; } + /// + public async Task OverwriteProfile(MemoryStream archiveStream, ProfileConfiguration profileConfiguration) + { + ProfileConfiguration imported = await ImportProfile(archiveStream, profileConfiguration.Category, true, true, null, profileConfiguration.Order + 1); + + DeleteProfile(profileConfiguration); + SaveProfileCategory(imported.Category); + + return imported; + } + /// public void AdaptProfile(Profile profile) { diff --git a/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs b/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs new file mode 100644 index 000000000..e1680ec1f --- /dev/null +++ b/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs @@ -0,0 +1,21 @@ +using System; + +namespace Artemis.Storage.Entities.Workshop; + +public class EntryEntity +{ + public Guid Id { get; set; } + + public Guid EntryId { get; set; } + public int EntryType { get; set; } + + public string Author { get; set; } + public string Name { get; set; } = string.Empty; + public string Summary { get; set; } = string.Empty; + + public Guid ReleaseId { get; set; } + public string ReleaseVersion { get; set; } + public DateTimeOffset InstalledAt { get; set; } + + public string LocalReference { get; set; } +} \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/EntryRepository.cs b/src/Artemis.Storage/Repositories/EntryRepository.cs new file mode 100644 index 000000000..b4a572535 --- /dev/null +++ b/src/Artemis.Storage/Repositories/EntryRepository.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using Artemis.Storage.Entities.Workshop; +using Artemis.Storage.Repositories.Interfaces; +using LiteDB; + +namespace Artemis.Storage.Repositories; + +internal class EntryRepository : IEntryRepository +{ + private readonly LiteRepository _repository; + + public EntryRepository(LiteRepository repository) + { + _repository = repository; + _repository.Database.GetCollection().EnsureIndex(s => s.Id); + _repository.Database.GetCollection().EnsureIndex(s => s.EntryId); + } + + public void Add(EntryEntity entryEntity) + { + _repository.Insert(entryEntity); + } + + public void Remove(EntryEntity entryEntity) + { + _repository.Delete(entryEntity.Id); + } + + public EntryEntity Get(Guid id) + { + return _repository.FirstOrDefault(s => s.Id == id); + } + + public EntryEntity GetByEntryId(Guid entryId) + { + return _repository.FirstOrDefault(s => s.EntryId == entryId); + } + + public List GetAll() + { + return _repository.Query().ToList(); + } + + public void Save(EntryEntity entryEntity) + { + _repository.Upsert(entryEntity); + } + + public void Save(IEnumerable entryEntities) + { + _repository.Upsert(entryEntities); + } +} \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs new file mode 100644 index 000000000..19429b863 --- /dev/null +++ b/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using Artemis.Storage.Entities.Workshop; + +namespace Artemis.Storage.Repositories.Interfaces; + +public interface IEntryRepository : IRepository +{ + void Add(EntryEntity entryEntity); + void Remove(EntryEntity entryEntity); + EntryEntity Get(Guid id); + EntryEntity GetByEntryId(Guid entryId); + List GetAll(); + void Save(EntryEntity entryEntity); + void Save(IEnumerable entryEntities); +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs index 273ee6c9d..2d026efec 100644 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs @@ -20,16 +20,16 @@ namespace Artemis.UI.Screens.Workshop.Profile; public class ProfileDetailsViewModel : RoutableScreen { private readonly IWorkshopClient _client; - private readonly ProfileEntryDownloadHandler _downloadHandler; + private readonly ProfileEntryInstallationHandler _installationHandler; private readonly INotificationService _notificationService; private readonly IWindowService _windowService; private readonly ObservableAsPropertyHelper _updatedAt; private IGetEntryById_Entry? _entry; - public ProfileDetailsViewModel(IWorkshopClient client, ProfileEntryDownloadHandler downloadHandler, INotificationService notificationService, IWindowService windowService) + public ProfileDetailsViewModel(IWorkshopClient client, ProfileEntryInstallationHandler installationHandler, INotificationService notificationService, IWindowService windowService) { _client = client; - _downloadHandler = downloadHandler; + _installationHandler = installationHandler; _notificationService = notificationService; _windowService = windowService; _updatedAt = this.WhenAnyValue(vm => vm.Entry).Select(e => e?.LatestRelease?.CreatedAt ?? e?.CreatedAt).ToProperty(this, vm => vm.UpdatedAt); @@ -70,7 +70,7 @@ public class ProfileDetailsViewModel : RoutableScreen if (!confirm) return; - EntryInstallResult result = await _downloadHandler.InstallProfileAsync(Entry.LatestRelease.Id, new Progress(), cancellationToken); + EntryInstallResult result = await _installationHandler.InstallProfileAsync(Entry, Entry.LatestRelease.Id, new Progress(), cancellationToken); if (result.IsSuccess) _notificationService.CreateNotification().WithTitle("Profile installed").WithSeverity(NotificationSeverity.Success).Show(); else diff --git a/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml b/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml index 8ac1d728f..c66d738c1 100644 --- a/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml @@ -5,6 +5,7 @@ xmlns:search="clr-namespace:Artemis.UI.Screens.Workshop.Search" xmlns:workshop="clr-namespace:Artemis.WebClient.Workshop;assembly=Artemis.WebClient.Workshop" xmlns:windowing="clr-namespace:FluentAvalonia.UI.Windowing;assembly=FluentAvalonia" + xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.Workshop.Search.SearchView" x:DataType="search:SearchViewModel"> @@ -30,12 +31,16 @@ + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs b/src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs index 130bef52d..4fe24197d 100644 --- a/src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Artemis.UI.Screens.Workshop.CurrentUser; +using Artemis.UI.Services.Interfaces; using Artemis.UI.Shared; using Artemis.UI.Shared.Routing; using Artemis.WebClient.Workshop; @@ -18,15 +19,17 @@ public class SearchViewModel : ViewModelBase { private readonly ILogger _logger; private readonly IRouter _router; + private readonly IDebugService _debugService; private readonly IWorkshopClient _workshopClient; private bool _isLoading; private SearchResultViewModel? _selectedEntry; - public SearchViewModel(ILogger logger, IWorkshopClient workshopClient, IRouter router, CurrentUserViewModel currentUserViewModel) + public SearchViewModel(ILogger logger, IWorkshopClient workshopClient, IRouter router, CurrentUserViewModel currentUserViewModel, IDebugService debugService) { _logger = logger; _workshopClient = workshopClient; _router = router; + _debugService = debugService; CurrentUserViewModel = currentUserViewModel; SearchAsync = ExecuteSearchAsync; @@ -49,6 +52,11 @@ public class SearchViewModel : ViewModelBase set => RaiseAndSetIfChanged(ref _isLoading, value); } + public void ShowDebugger() + { + _debugService.ShowDebugger(); + } + private void NavigateToEntry(SearchResultViewModel searchResult) { string? url = null; diff --git a/src/Artemis.WebClient.Workshop/DownloadHandlers/IEntryDownloadHandler.cs b/src/Artemis.WebClient.Workshop/DownloadHandlers/IEntryInstallationHandler.cs similarity index 69% rename from src/Artemis.WebClient.Workshop/DownloadHandlers/IEntryDownloadHandler.cs rename to src/Artemis.WebClient.Workshop/DownloadHandlers/IEntryInstallationHandler.cs index 8d477e7ff..435e17e82 100644 --- a/src/Artemis.WebClient.Workshop/DownloadHandlers/IEntryDownloadHandler.cs +++ b/src/Artemis.WebClient.Workshop/DownloadHandlers/IEntryInstallationHandler.cs @@ -2,6 +2,6 @@ namespace Artemis.WebClient.Workshop.DownloadHandlers; -public interface IEntryDownloadHandler +public interface IEntryInstallationHandler { } \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/DownloadHandlers/Implementations/ProfileEntryDownloadHandler.cs b/src/Artemis.WebClient.Workshop/DownloadHandlers/Implementations/ProfileEntryDownloadHandler.cs deleted file mode 100644 index cb7e6e7a6..000000000 --- a/src/Artemis.WebClient.Workshop/DownloadHandlers/Implementations/ProfileEntryDownloadHandler.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Artemis.Core; -using Artemis.Core.Services; -using Artemis.UI.Shared.Extensions; -using Artemis.UI.Shared.Utilities; - -namespace Artemis.WebClient.Workshop.DownloadHandlers.Implementations; - -public class ProfileEntryDownloadHandler : IEntryDownloadHandler -{ - private readonly IHttpClientFactory _httpClientFactory; - private readonly IProfileService _profileService; - - public ProfileEntryDownloadHandler(IHttpClientFactory httpClientFactory, IProfileService profileService) - { - _httpClientFactory = httpClientFactory; - _profileService = profileService; - } - - public async Task> InstallProfileAsync(Guid releaseId, Progress progress, CancellationToken cancellationToken) - { - try - { - HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.WORKSHOP_CLIENT_NAME); - using MemoryStream stream = new(); - await client.DownloadDataAsync($"releases/download/{releaseId}", stream, progress, cancellationToken); - - ProfileCategory category = _profileService.ProfileCategories.FirstOrDefault(c => c.Name == "Workshop") ?? _profileService.CreateProfileCategory("Workshop", true); - ProfileConfiguration profileConfiguration = await _profileService.ImportProfile(stream, category, true, true, null); - return EntryInstallResult.FromSuccess(profileConfiguration); - } - catch (Exception e) - { - return EntryInstallResult.FromFailure(e.Message); - } - } -} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/DownloadHandlers/Implementations/ProfileEntryInstallationHandler.cs b/src/Artemis.WebClient.Workshop/DownloadHandlers/Implementations/ProfileEntryInstallationHandler.cs new file mode 100644 index 000000000..83d057e61 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/DownloadHandlers/Implementations/ProfileEntryInstallationHandler.cs @@ -0,0 +1,73 @@ +using Artemis.Core; +using Artemis.Core.Services; +using Artemis.UI.Shared.Extensions; +using Artemis.UI.Shared.Utilities; +using Artemis.WebClient.Workshop.Services; + +namespace Artemis.WebClient.Workshop.DownloadHandlers.Implementations; + +public class ProfileEntryInstallationHandler : IEntryInstallationHandler +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly IProfileService _profileService; + private readonly IWorkshopService _workshopService; + + public ProfileEntryInstallationHandler(IHttpClientFactory httpClientFactory, IProfileService profileService, IWorkshopService workshopService) + { + _httpClientFactory = httpClientFactory; + _profileService = profileService; + _workshopService = workshopService; + } + + public async Task> InstallProfileAsync(IGetEntryById_Entry entry, Guid releaseId, Progress progress, CancellationToken cancellationToken) + { + using MemoryStream stream = new(); + + // Download the provided release + try + { + HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.WORKSHOP_CLIENT_NAME); + await client.DownloadDataAsync($"releases/download/{releaseId}", stream, progress, cancellationToken); + } + catch (Exception e) + { + return EntryInstallResult.FromFailure(e.Message); + } + + // Find existing installation to potentially replace the profile + InstalledEntry? installedEntry = _workshopService.GetInstalledEntry(entry); + if (installedEntry != null && Guid.TryParse(installedEntry.LocalReference, out Guid profileId)) + { + ProfileConfiguration? existing = _profileService.ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(c => c.ProfileId == profileId); + if (existing != null) + { + ProfileConfiguration overwritten = await _profileService.OverwriteProfile(stream, existing); + installedEntry.LocalReference = overwritten.ProfileId.ToString(); + + // Update the release and return the profile configuration + UpdateRelease(releaseId, installedEntry); + return EntryInstallResult.FromSuccess(overwritten); + } + } + + // Ensure there is an installed entry + installedEntry ??= _workshopService.CreateInstalledEntry(entry); + + // Add the profile as a fresh import + ProfileCategory category = _profileService.ProfileCategories.FirstOrDefault(c => c.Name == "Workshop") ?? _profileService.CreateProfileCategory("Workshop", true); + ProfileConfiguration imported = await _profileService.ImportProfile(stream, category, true, true, null); + installedEntry.LocalReference = imported.ProfileId.ToString(); + + // Update the release and return the profile configuration + UpdateRelease(releaseId, installedEntry); + return EntryInstallResult.FromSuccess(imported); + } + + private void UpdateRelease(Guid releaseId, InstalledEntry installedEntry) + { + installedEntry.ReleaseId = releaseId; + installedEntry.ReleaseVersion = "TODO"; + installedEntry.InstalledAt = DateTimeOffset.UtcNow; + _workshopService.SaveInstalledEntry(installedEntry); + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs index e98f8c8e7..5a4a29e6e 100644 --- a/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs @@ -49,6 +49,6 @@ public static class ContainerExtensions container.Register(Reuse.Transient); container.RegisterMany(workshopAssembly, type => type.IsAssignableTo(), Reuse.Transient); - container.RegisterMany(workshopAssembly, type => type.IsAssignableTo(), Reuse.Transient); + container.RegisterMany(workshopAssembly, type => type.IsAssignableTo(), Reuse.Transient); } } \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Services/InstalledEntry.cs b/src/Artemis.WebClient.Workshop/Services/InstalledEntry.cs new file mode 100644 index 000000000..8ad0b50ab --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Services/InstalledEntry.cs @@ -0,0 +1,72 @@ +using Artemis.Storage.Entities.Workshop; + +namespace Artemis.WebClient.Workshop.Services; + +public class InstalledEntry +{ + internal InstalledEntry(EntryEntity entity) + { + Entity = entity; + + Load(); + } + + public InstalledEntry(IGetEntryById_Entry entry) + { + Entity = new EntryEntity(); + + EntryId = entry.Id; + EntryType = entry.EntryType; + + Author = entry.Author; + Name = entry.Name; + Summary = entry.Summary; + } + + public Guid EntryId { get; set; } + public EntryType EntryType { get; set; } + + public string Author { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; + public string Summary { get; set; } = string.Empty; + + public Guid ReleaseId { get; set; } + public string ReleaseVersion { get; set; } = string.Empty; + public DateTimeOffset InstalledAt { get; set; } + + public string? LocalReference { get; set; } + + internal EntryEntity Entity { get; } + + internal void Load() + { + EntryId = Entity.EntryId; + EntryType = (EntryType) Entity.EntryType; + + Author = Entity.Author; + Name = Entity.Name; + Summary = Entity.Summary; + + ReleaseId = Entity.ReleaseId; + ReleaseVersion = Entity.ReleaseVersion; + InstalledAt = Entity.InstalledAt; + + LocalReference = Entity.LocalReference; + } + + internal void Save() + { + Entity.EntryId = EntryId; + Entity.EntryType = (int) EntryType; + + Entity.Author = Author; + Entity.Name = Name; + Entity.Summary = Summary; + + Entity.ReleaseId = ReleaseId; + Entity.ReleaseVersion = ReleaseVersion; + Entity.InstalledAt = InstalledAt; + + Entity.LocalReference = LocalReference; + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Services/IAuthenticationService.cs b/src/Artemis.WebClient.Workshop/Services/Interfaces/IAuthenticationService.cs similarity index 100% rename from src/Artemis.WebClient.Workshop/Services/IAuthenticationService.cs rename to src/Artemis.WebClient.Workshop/Services/Interfaces/IAuthenticationService.cs diff --git a/src/Artemis.WebClient.Workshop/Services/Interfaces/IWorkshopService.cs b/src/Artemis.WebClient.Workshop/Services/Interfaces/IWorkshopService.cs new file mode 100644 index 000000000..d7c0f8764 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Services/Interfaces/IWorkshopService.cs @@ -0,0 +1,18 @@ +using Artemis.UI.Shared.Utilities; +using Artemis.WebClient.Workshop.UploadHandlers; + +namespace Artemis.WebClient.Workshop.Services; + +public interface IWorkshopService +{ + Task GetEntryIcon(Guid entryId, CancellationToken cancellationToken); + Task SetEntryIcon(Guid entryId, Progress progress, Stream icon, CancellationToken cancellationToken); + Task GetWorkshopStatus(CancellationToken cancellationToken); + Task ValidateWorkshopStatus(CancellationToken cancellationToken); + Task NavigateToEntry(Guid entryId, EntryType entryType); + InstalledEntry? GetInstalledEntry(IGetEntryById_Entry entry); + InstalledEntry CreateInstalledEntry(IGetEntryById_Entry entry); + void SaveInstalledEntry(InstalledEntry entry); + + public record WorkshopStatus(bool IsReachable, string Message); +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Services/IWorkshopService.cs b/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs similarity index 83% rename from src/Artemis.WebClient.Workshop/Services/IWorkshopService.cs rename to src/Artemis.WebClient.Workshop/Services/WorkshopService.cs index d1e0fb287..af29c9bb0 100644 --- a/src/Artemis.WebClient.Workshop/Services/IWorkshopService.cs +++ b/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs @@ -1,4 +1,6 @@ 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.UploadHandlers; @@ -9,11 +11,13 @@ public class WorkshopService : IWorkshopService { private readonly IHttpClientFactory _httpClientFactory; private readonly IRouter _router; + private readonly IEntryRepository _entryRepository; - public WorkshopService(IHttpClientFactory httpClientFactory, IRouter router) + public WorkshopService(IHttpClientFactory httpClientFactory, IRouter router, IEntryRepository entryRepository) { _httpClientFactory = httpClientFactory; _router = router; + _entryRepository = entryRepository; } public async Task GetEntryIcon(Guid entryId, CancellationToken cancellationToken) @@ -98,15 +102,27 @@ public class WorkshopService : IWorkshopService throw new ArgumentOutOfRangeException(nameof(entryType)); } } -} -public interface IWorkshopService -{ - Task GetEntryIcon(Guid entryId, CancellationToken cancellationToken); - Task SetEntryIcon(Guid entryId, Progress progress, Stream icon, CancellationToken cancellationToken); - Task GetWorkshopStatus(CancellationToken cancellationToken); - Task ValidateWorkshopStatus(CancellationToken cancellationToken); - Task NavigateToEntry(Guid entryId, EntryType entryType); + /// + public InstalledEntry? GetInstalledEntry(IGetEntryById_Entry entry) + { + EntryEntity? entity = _entryRepository.GetByEntryId(entry.Id); + if (entity == null) + return null; - public record WorkshopStatus(bool IsReachable, string Message); + return new InstalledEntry(entity); + } + + /// + public InstalledEntry CreateInstalledEntry(IGetEntryById_Entry entry) + { + return new InstalledEntry(entry); + } + + /// + public void SaveInstalledEntry(InstalledEntry entry) + { + entry.Save(); + _entryRepository.Save(entry.Entity); + } } \ No newline at end of file