Refactor server importers
Refactors server importers to better handle dependencies on other data in the queue.
This commit is contained in:
parent
b4e8925e0e
commit
54400fdb10
32 changed files with 1313 additions and 887 deletions
|
|
@ -1,3 +1,4 @@
|
|||
using LANCommander.Server.ImportExport.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Factories;
|
||||
|
|
@ -6,8 +7,12 @@ public class ImportContextFactory(IServiceProvider serviceProvider)
|
|||
{
|
||||
public ImportContext Create()
|
||||
{
|
||||
var scope = serviceProvider.CreateScope();
|
||||
var importService = serviceProvider.GetRequiredService<ImportService>();
|
||||
|
||||
var context = new ImportContext(serviceProvider);
|
||||
|
||||
importService.AddContext(context);
|
||||
|
||||
return scope.ServiceProvider.GetRequiredService<ImportContext>();
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,120 +1,133 @@
|
|||
using System.IO.Compression;
|
||||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Helpers;
|
||||
using LANCommander.Server.Data.Models;
|
||||
using LANCommander.Server.ImportExport.Importers;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.ImportExport.Services;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ZipArchive = SharpCompress.Archives.Zip.ZipArchive;
|
||||
|
||||
namespace LANCommander.Server.ImportExport;
|
||||
|
||||
public class ImportContext(
|
||||
GameImporter gameImporter,
|
||||
RedistributableImporter redistributableImporter,
|
||||
ServerImporter serverImporter,
|
||||
ActionImporter actionImporter,
|
||||
ArchiveImporter archiveImporter,
|
||||
CollectionImporter collectionImporter,
|
||||
CustomFieldImporter customFieldImporter,
|
||||
DeveloperImporter developerImporter,
|
||||
PublisherImporter publisherImporter,
|
||||
EngineImporter engineImporter,
|
||||
GenreImporter genreImporter,
|
||||
KeyImporter keyImporter,
|
||||
MediaImporter mediaImporter,
|
||||
MultiplayerModeImporter multiplayerModeImporter,
|
||||
PlatformImporter platformImporter,
|
||||
PlaySessionImporter playSessionImporter,
|
||||
SaveImporter saveImporter,
|
||||
SavePathImporter savePathImporter,
|
||||
ScriptImporter scriptImporter,
|
||||
ServerConsoleImporter serverConsoleImporter,
|
||||
ServerHttpPathImporter serverHttpPathImporter,
|
||||
TagImporter tagImporter,
|
||||
StorageLocationService storageLocationService,
|
||||
IMapper mapper,
|
||||
ILogger<ImportContext> logger) : IDisposable
|
||||
public class ImportContext : IDisposable
|
||||
{
|
||||
private Guid? Id { get; set; }
|
||||
public object Manifest { get; private set; }
|
||||
public BaseModel DataRecord { get; private set; }
|
||||
public StorageLocation ArchiveStorageLocation { get; set; }
|
||||
public ZipArchive Archive { get; private set; }
|
||||
|
||||
public GameImporter Games = gameImporter;
|
||||
public RedistributableImporter Redistributables = redistributableImporter;
|
||||
public ServerImporter Servers = serverImporter;
|
||||
public IImportItemInfo CurrentItem { get; set; }
|
||||
public int Processed => Queue.Count(qi => qi.Processed);
|
||||
public int Total => Queue.Count;
|
||||
|
||||
public ActionImporter Actions = actionImporter;
|
||||
public ArchiveImporter Archives = archiveImporter;
|
||||
public CollectionImporter Collections = collectionImporter;
|
||||
public CustomFieldImporter CustomFields = customFieldImporter;
|
||||
public DeveloperImporter Developers = developerImporter;
|
||||
public EngineImporter Engines = engineImporter;
|
||||
public GenreImporter Genres = genreImporter;
|
||||
public KeyImporter Keys = keyImporter;
|
||||
public MediaImporter Media = mediaImporter;
|
||||
public MultiplayerModeImporter MultiplayerModes = multiplayerModeImporter;
|
||||
public PlatformImporter Platforms = platformImporter;
|
||||
public PlaySessionImporter PlaySessions = playSessionImporter;
|
||||
public PublisherImporter Publishers = publisherImporter;
|
||||
public SaveImporter Saves = saveImporter;
|
||||
public SavePathImporter SavePaths = savePathImporter;
|
||||
public ScriptImporter Scripts = scriptImporter;
|
||||
public ServerConsoleImporter ServerConsoles = serverConsoleImporter;
|
||||
public ServerHttpPathImporter ServerHttpPaths = serverHttpPathImporter;
|
||||
public TagImporter Tags = tagImporter;
|
||||
private Queue<IImportItemInfo> Queue { get; } = new();
|
||||
private IEnumerable<Guid> SelectedRecordIds { get; set; } = [];
|
||||
|
||||
public int Remaining => _queue.Count;
|
||||
public int Processed => _queue.Count(qi => qi.Processed);
|
||||
public int Total => _queue.Count;
|
||||
|
||||
private List<ImportQueueItem> _queue { get; } = new();
|
||||
private IEnumerable<Guid> _selectedRecordIds { get; set; }
|
||||
public Dictionary<ImportQueueItem, string> Errored { get; } = new();
|
||||
|
||||
public EventHandler<ImportQueueItem> OnRecordAdded;
|
||||
public EventHandler<ImportQueueItem> OnRecordProcessed;
|
||||
public EventHandler<ImportQueueItem> OnRecordError;
|
||||
|
||||
private void UseContext(ImportContext context)
|
||||
{
|
||||
Games.UseContext(context);
|
||||
Redistributables.UseContext(context);
|
||||
Servers.UseContext(context);
|
||||
|
||||
Actions.UseContext(context);
|
||||
Archives.UseContext(context);
|
||||
Collections.UseContext(context);
|
||||
CustomFields.UseContext(context);
|
||||
Developers.UseContext(context);
|
||||
Engines.UseContext(context);
|
||||
Genres.UseContext(context);
|
||||
Keys.UseContext(context);
|
||||
Media.UseContext(context);
|
||||
MultiplayerModes.UseContext(context);
|
||||
Platforms.UseContext(context);
|
||||
PlaySessions.UseContext(context);
|
||||
Publishers.UseContext(context);
|
||||
Saves.UseContext(context);
|
||||
SavePaths.UseContext(context);
|
||||
Scripts.UseContext(context);
|
||||
ServerConsoles.UseContext(context);
|
||||
ServerHttpPaths.UseContext(context);
|
||||
Tags.UseContext(context);
|
||||
}
|
||||
public EventHandler<ImportStatusUpdate> OnImportStarted { get; set; }
|
||||
public EventHandler<ImportStatusUpdate> OnImportStatusUpdate { get; set; }
|
||||
public EventHandler<ImportStatusUpdate> OnImportComplete { get; set; }
|
||||
public EventHandler<ImportStatusUpdate> OnImportError;
|
||||
|
||||
#region Initialize Import
|
||||
public async Task<IEnumerable<ImportItemInfo>> InitializeImportAsync(string archivePath)
|
||||
private readonly ImportService _importService;
|
||||
private readonly StorageLocationService _storageLocationService;
|
||||
private readonly ILogger<ImportContext> _logger;
|
||||
|
||||
#region Importers
|
||||
private readonly ActionImporter _actions;
|
||||
private readonly ArchiveImporter _archives;
|
||||
private readonly CollectionImporter _collections;
|
||||
private readonly CustomFieldImporter _customFields;
|
||||
private readonly DeveloperImporter _developers;
|
||||
private readonly EngineImporter _engines;
|
||||
private readonly GameImporter _games;
|
||||
private readonly GenreImporter _genres;
|
||||
private readonly KeyImporter _keys;
|
||||
private readonly MediaImporter _media;
|
||||
private readonly MultiplayerModeImporter _multiplayerModes;
|
||||
private readonly PlatformImporter _platforms;
|
||||
private readonly PlaySessionImporter _playSessions;
|
||||
private readonly PublisherImporter _publishers;
|
||||
private readonly RedistributableImporter _redistributables;
|
||||
private readonly SaveImporter _saves;
|
||||
private readonly SavePathImporter _savePaths;
|
||||
private readonly ScriptImporter _scripts;
|
||||
private readonly ServerConsoleImporter _serverConsoles;
|
||||
private readonly ServerHttpPathImporter _serverHttpPaths;
|
||||
private readonly ServerImporter _servers;
|
||||
private readonly TagImporter _tags;
|
||||
#endregion
|
||||
|
||||
public ImportContext(IServiceProvider serviceProvider)
|
||||
{
|
||||
UseContext(this);
|
||||
_actions = serviceProvider.GetRequiredService<ActionImporter>();
|
||||
_archives = serviceProvider.GetRequiredService<ArchiveImporter>();
|
||||
_collections = serviceProvider.GetRequiredService<CollectionImporter>();
|
||||
_customFields = serviceProvider.GetRequiredService<CustomFieldImporter>();
|
||||
_developers = serviceProvider.GetRequiredService<DeveloperImporter>();
|
||||
_engines = serviceProvider.GetRequiredService<EngineImporter>();
|
||||
_games = serviceProvider.GetRequiredService<GameImporter>();
|
||||
_genres = serviceProvider.GetRequiredService<GenreImporter>();
|
||||
_keys = serviceProvider.GetRequiredService<KeyImporter>();
|
||||
_media = serviceProvider.GetRequiredService<MediaImporter>();
|
||||
_multiplayerModes = serviceProvider.GetRequiredService<MultiplayerModeImporter>();
|
||||
_platforms = serviceProvider.GetRequiredService<PlatformImporter>();
|
||||
_playSessions = serviceProvider.GetRequiredService<PlaySessionImporter>();
|
||||
_publishers = serviceProvider.GetRequiredService<PublisherImporter>();
|
||||
_redistributables = serviceProvider.GetRequiredService<RedistributableImporter>();
|
||||
_saves = serviceProvider.GetRequiredService<SaveImporter>();
|
||||
_savePaths = serviceProvider.GetRequiredService<SavePathImporter>();
|
||||
_scripts = serviceProvider.GetRequiredService<ScriptImporter>();
|
||||
_serverConsoles = serviceProvider.GetRequiredService<ServerConsoleImporter>();
|
||||
_serverHttpPaths = serviceProvider.GetRequiredService<ServerHttpPathImporter>();
|
||||
_servers = serviceProvider.GetRequiredService<ServerImporter>();
|
||||
_tags = serviceProvider.GetRequiredService<TagImporter>();
|
||||
|
||||
_importService = serviceProvider.GetRequiredService<ImportService>();
|
||||
_storageLocationService = serviceProvider.GetRequiredService<StorageLocationService>();
|
||||
_logger = serviceProvider.GetRequiredService<ILogger<ImportContext>>();
|
||||
}
|
||||
|
||||
internal bool InQueue<TRecord>(TRecord record, BaseImporter<TRecord> importer)
|
||||
where TRecord : class =>
|
||||
Queue.Any(qi => qi.Key == importer.GetKey(record));
|
||||
|
||||
public void SetId(Guid id) => Id = id;
|
||||
|
||||
#region Initialize Import
|
||||
public async Task<IEnumerable<IImportItemInfo>> InitializeImportAsync(string archivePath)
|
||||
{
|
||||
_actions.UseContext(this);
|
||||
_archives.UseContext(this);
|
||||
_collections.UseContext(this);
|
||||
_customFields.UseContext(this);
|
||||
_developers.UseContext(this);
|
||||
_engines.UseContext(this);
|
||||
_games.UseContext(this);
|
||||
_genres.UseContext(this);
|
||||
_keys.UseContext(this);
|
||||
_media.UseContext(this);
|
||||
_multiplayerModes.UseContext(this);
|
||||
_platforms.UseContext(this);
|
||||
_playSessions.UseContext(this);
|
||||
_publishers.UseContext(this);
|
||||
_redistributables.UseContext(this);
|
||||
_saves.UseContext(this);
|
||||
_savePaths.UseContext(this);
|
||||
_scripts.UseContext(this);
|
||||
_serverConsoles.UseContext(this);
|
||||
_serverHttpPaths.UseContext(this);
|
||||
_servers.UseContext(this);
|
||||
_tags.UseContext(this);
|
||||
|
||||
Archive = ZipArchive.Open(archivePath);
|
||||
|
||||
var manifestEntry = Archive.Entries.FirstOrDefault(e => e.Key == ManifestHelper.ManifestFilename);
|
||||
|
||||
if (manifestEntry == null)
|
||||
throw new InvalidOperationException("Invalid import file, cannot load manifest");
|
||||
|
||||
using (var reader = new StreamReader(manifestEntry.OpenEntryStream()))
|
||||
{
|
||||
|
|
@ -133,214 +146,275 @@ public class ImportContext(
|
|||
}
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<ImportItemInfo>> InitializeGameImportAsync(SDK.Models.Manifest.Game gameManifest)
|
||||
private async Task<IEnumerable<IImportItemInfo>> InitializeGameImportAsync(SDK.Models.Manifest.Game gameManifest)
|
||||
{
|
||||
Manifest = gameManifest;
|
||||
|
||||
var importItemInfo = new List<ImportItemInfo>();
|
||||
var importItemInfo = new List<IImportItemInfo>();
|
||||
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Actions, Actions).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Archives, Archives).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Collections, Collections).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.CustomFields, CustomFields).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Developers, Developers).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Actions, _actions).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Archives, _archives).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Collections, _collections).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.CustomFields, _customFields).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Developers, _developers).ToListAsync());
|
||||
|
||||
if (gameManifest.Engine != null)
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync([gameManifest.Engine], Engines).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync([gameManifest.Engine], _engines).ToListAsync());
|
||||
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Genres, Genres).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Keys, Keys).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Media, Media).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.MultiplayerModes, MultiplayerModes).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Platforms, Platforms).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.PlaySessions, PlaySessions).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Publishers, Publishers).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Saves, Saves).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.SavePaths, SavePaths).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Scripts, Scripts).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Tags, Tags).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Genres, _genres).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Keys, _keys).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Media, _media).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.MultiplayerModes, _multiplayerModes).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Platforms, _platforms).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.PlaySessions, _playSessions).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Publishers, _publishers).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Saves, _saves).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.SavePaths, _savePaths).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Scripts, _scripts).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(gameManifest.Tags, _tags).ToListAsync());
|
||||
|
||||
return importItemInfo;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<ImportItemInfo>> InitializeRedistributableImportAsync(SDK.Models.Manifest.Redistributable redistributableManifest)
|
||||
private async Task<IEnumerable<IImportItemInfo>> InitializeRedistributableImportAsync(SDK.Models.Manifest.Redistributable redistributableManifest)
|
||||
{
|
||||
Manifest = redistributableManifest;
|
||||
|
||||
var importItemInfo = new List<ImportItemInfo>();
|
||||
var importItemInfo = new List<IImportItemInfo>();
|
||||
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(redistributableManifest.Archives, Archives).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(redistributableManifest.Scripts, Scripts).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(redistributableManifest.Archives, _archives).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(redistributableManifest.Scripts, _scripts).ToListAsync());
|
||||
|
||||
return importItemInfo;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<ImportItemInfo>> InitializeServerImportAsync(SDK.Models.Manifest.Server serverManifest)
|
||||
private async Task<IEnumerable<IImportItemInfo>> InitializeServerImportAsync(SDK.Models.Manifest.Server serverManifest)
|
||||
{
|
||||
Manifest = serverManifest;
|
||||
|
||||
var importItemInfo = new List<ImportItemInfo>();
|
||||
var importItemInfo = new List<IImportItemInfo>();
|
||||
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(serverManifest.Actions, Actions).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(serverManifest.Scripts, Scripts).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(serverManifest.ServerConsoles, ServerConsoles).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(serverManifest.HttpPaths, ServerHttpPaths).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(serverManifest.Actions, _actions).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(serverManifest.Scripts, _scripts).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(serverManifest.ServerConsoles, _serverConsoles).ToListAsync());
|
||||
importItemInfo.AddRange(await GetImportItemInfoAsync(serverManifest.HttpPaths, _serverHttpPaths).ToListAsync());
|
||||
|
||||
return importItemInfo;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Prepare Import Queue
|
||||
public async Task PrepareImportQueueAsync(IEnumerable<Guid> selectedRecordIds, Guid storageLocationId)
|
||||
{
|
||||
_selectedRecordIds = selectedRecordIds;
|
||||
|
||||
ArchiveStorageLocation = await storageLocationService.GetAsync(storageLocationId);
|
||||
SelectedRecordIds = selectedRecordIds;
|
||||
|
||||
ArchiveStorageLocation = await _storageLocationService.GetAsync(storageLocationId);
|
||||
|
||||
if (Manifest is SDK.Models.Manifest.Game gameManifest)
|
||||
await PrepareGameImportQueueAsync(gameManifest);
|
||||
await AddAsync(gameManifest);
|
||||
|
||||
if (Manifest is SDK.Models.Manifest.Redistributable redistributableManifest)
|
||||
await PrepareRedistributableImportQueueAsync(redistributableManifest);
|
||||
await AddAsync(redistributableManifest);
|
||||
|
||||
if (Manifest is SDK.Models.Manifest.Server serverManifest)
|
||||
await PrepareServerImportQueueAsync(serverManifest);
|
||||
await AddAsync(serverManifest);
|
||||
}
|
||||
|
||||
public async Task PrepareGameImportQueueAsync(SDK.Models.Manifest.Game gameManifest)
|
||||
public async Task AddAsync(SDK.Models.Manifest.Game game)
|
||||
{
|
||||
if (!(await Games.ExistsAsync(gameManifest)))
|
||||
DataRecord = await Games.AddAsync(gameManifest);
|
||||
else
|
||||
DataRecord = await Games.UpdateAsync(gameManifest);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Action, gameManifest.Actions);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Archive, gameManifest.Archives);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Collection, gameManifest.Collections);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.CustomField, gameManifest.CustomFields);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Developer, gameManifest.Developers);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Engine, [gameManifest.Engine]);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Genre, gameManifest.Genres);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Key, gameManifest.Keys);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Media, gameManifest.Media);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.MultiplayerMode, gameManifest.MultiplayerModes);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Platform, gameManifest.Platforms);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.PlaySession, gameManifest.PlaySessions);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Publisher, gameManifest.Publishers);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Save, gameManifest.Saves);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.SavePath, gameManifest.SavePaths);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Script, gameManifest.Scripts);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Tag, gameManifest.Tags);
|
||||
await AddAsync(game.Actions, _actions);
|
||||
await AddAsync(game.Archives, _archives);
|
||||
await AddAsync(game.Collections, _collections);
|
||||
await AddAsync(game.CustomFields, _customFields);
|
||||
await AddAsync(game.Developers, _developers);
|
||||
await AddAsync(game.Engine, _engines);
|
||||
await AddAsync(game.Genres, _genres);
|
||||
await AddAsync(game.Keys, _keys);
|
||||
await AddAsync(game.Media, _media);
|
||||
await AddAsync(game.MultiplayerModes, _multiplayerModes);
|
||||
await AddAsync(game.Platforms, _platforms);
|
||||
await AddAsync(game.PlaySessions, _playSessions);
|
||||
await AddAsync(game.Publishers, _publishers);
|
||||
await AddAsync(game.Saves, _saves);
|
||||
await AddAsync(game.Scripts, _scripts);
|
||||
await AddAsync(game.Tags, _tags);
|
||||
await AddAsync(game, _games);
|
||||
}
|
||||
|
||||
public async Task PrepareRedistributableImportQueueAsync(SDK.Models.Manifest.Redistributable redistributableManifest)
|
||||
{
|
||||
if (!(await Redistributables.ExistsAsync(redistributableManifest)))
|
||||
DataRecord = await Redistributables.AddAsync(redistributableManifest);
|
||||
else
|
||||
DataRecord = await Redistributables.UpdateAsync(redistributableManifest);
|
||||
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Archive, redistributableManifest.Archives);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Script, redistributableManifest.Scripts);
|
||||
}
|
||||
|
||||
public async Task PrepareServerImportQueueAsync(SDK.Models.Manifest.Server serverManifest)
|
||||
public async Task AddAsync(SDK.Models.Manifest.Redistributable redistributable)
|
||||
{
|
||||
if (!(await Servers.ExistsAsync(serverManifest)))
|
||||
DataRecord = await Servers.AddAsync(serverManifest);
|
||||
else
|
||||
DataRecord = await Servers.UpdateAsync(serverManifest);
|
||||
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Action, serverManifest.Actions);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.Script, serverManifest.Scripts);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.ServerConsole, serverManifest.ServerConsoles);
|
||||
await AddToImportQueueAsync(ImportExportRecordType.ServerHttpPath, serverManifest.HttpPaths);
|
||||
await AddAsync(redistributable.Archives, _archives);
|
||||
await AddAsync(redistributable.Scripts, _scripts);
|
||||
await AddAsync(redistributable, _redistributables);
|
||||
}
|
||||
#endregion
|
||||
|
||||
private async Task AddToImportQueueAsync<TRecord>(ImportExportRecordType type, IEnumerable<TRecord> records) where TRecord : SDK.Models.Manifest.BaseModel
|
||||
public async Task AddAsync(SDK.Models.Manifest.Server server)
|
||||
{
|
||||
if (records != null)
|
||||
_queue.AddRange(records.Select(r => new ImportQueueItem(type, r)));
|
||||
await AddAsync(server.Actions, _actions);
|
||||
await AddAsync(server.Scripts, _scripts);
|
||||
await AddAsync(server.HttpPaths, _serverHttpPaths);
|
||||
await AddAsync(server.ServerConsoles, _serverConsoles);
|
||||
await AddAsync(server, _servers);
|
||||
}
|
||||
|
||||
private async Task AddAsync<TRecord>(IEnumerable<TRecord> records, BaseImporter<TRecord> importer)
|
||||
where TRecord : class
|
||||
{
|
||||
foreach (var record in records)
|
||||
await AddAsync(record, importer);
|
||||
}
|
||||
|
||||
private async Task AddAsync<TRecord>(TRecord? record, BaseImporter<TRecord> importer)
|
||||
where TRecord : class
|
||||
{
|
||||
if (record != null && !InQueue(record, importer) && await importer.CanImportAsync(record))
|
||||
Queue.Enqueue(await importer.GetImportInfoAsync(record));
|
||||
}
|
||||
|
||||
public async Task ImportQueueAsync()
|
||||
{
|
||||
foreach (var queueItem in _queue)
|
||||
OnImportStarted?.Invoke(this, new ImportStatusUpdate
|
||||
{
|
||||
if (queueItem.Type == ImportExportRecordType.Action)
|
||||
await ImportRecordAsync(queueItem, Actions);
|
||||
else if (queueItem.Type == ImportExportRecordType.Archive)
|
||||
await ImportRecordAsync(queueItem, Archives);
|
||||
else if (queueItem.Type == ImportExportRecordType.Collection)
|
||||
await ImportRecordAsync(queueItem, Collections);
|
||||
else if (queueItem.Type == ImportExportRecordType.CustomField)
|
||||
await ImportRecordAsync(queueItem, CustomFields);
|
||||
else if (queueItem.Type == ImportExportRecordType.Developer)
|
||||
await ImportRecordAsync(queueItem, Developers);
|
||||
else if (queueItem.Type == ImportExportRecordType.Publisher)
|
||||
await ImportRecordAsync(queueItem, Publishers);
|
||||
else if (queueItem.Type == ImportExportRecordType.Engine)
|
||||
await ImportRecordAsync(queueItem, Engines);
|
||||
else if (queueItem.Type == ImportExportRecordType.Genre)
|
||||
await ImportRecordAsync(queueItem, Genres);
|
||||
else if (queueItem.Type == ImportExportRecordType.Key)
|
||||
await ImportRecordAsync(queueItem, Keys);
|
||||
else if (queueItem.Type == ImportExportRecordType.Media)
|
||||
await ImportRecordAsync(queueItem, Media);
|
||||
else if (queueItem.Type == ImportExportRecordType.MultiplayerMode)
|
||||
await ImportRecordAsync(queueItem, MultiplayerModes);
|
||||
else if (queueItem.Type == ImportExportRecordType.Platform)
|
||||
await ImportRecordAsync(queueItem, Platforms);
|
||||
else if (queueItem.Type == ImportExportRecordType.PlaySession)
|
||||
await ImportRecordAsync(queueItem, PlaySessions);
|
||||
else if (queueItem.Type == ImportExportRecordType.Save)
|
||||
await ImportRecordAsync(queueItem, Saves);
|
||||
else if (queueItem.Type == ImportExportRecordType.SavePath)
|
||||
await ImportRecordAsync(queueItem, SavePaths);
|
||||
else if (queueItem.Type == ImportExportRecordType.Script)
|
||||
await ImportRecordAsync(queueItem, Scripts);
|
||||
else if (queueItem.Type == ImportExportRecordType.ServerConsole)
|
||||
await ImportRecordAsync(queueItem, ServerConsoles);
|
||||
else if (queueItem.Type == ImportExportRecordType.ServerHttpPath)
|
||||
await ImportRecordAsync(queueItem, ServerHttpPaths);
|
||||
else if (queueItem.Type == ImportExportRecordType.Tag)
|
||||
await ImportRecordAsync(queueItem, Tags);
|
||||
Index = -1,
|
||||
Total = Queue.Count,
|
||||
});
|
||||
|
||||
int deferred = 0;
|
||||
|
||||
while (Queue.Count > 0)
|
||||
{
|
||||
var queueItem = Queue.Dequeue();
|
||||
|
||||
OnImportStatusUpdate?.Invoke(this, new ImportStatusUpdate
|
||||
{
|
||||
CurrentItem = queueItem,
|
||||
Index = Processed,
|
||||
Total = Total,
|
||||
});
|
||||
|
||||
var success = await TryImportAsync(queueItem);
|
||||
|
||||
if (success)
|
||||
{
|
||||
deferred = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
Queue.Enqueue(queueItem);
|
||||
deferred++;
|
||||
|
||||
if (deferred >= Queue.Count)
|
||||
throw new InvalidOperationException("Import deadlocked: remaining jobs cannot be satisfied.");
|
||||
}
|
||||
|
||||
OnImportComplete?.Invoke(this, new ImportStatusUpdate
|
||||
{
|
||||
Index = Total - 1,
|
||||
Total = Total,
|
||||
});
|
||||
|
||||
_importService.RemoveContext(Id.Value);
|
||||
}
|
||||
|
||||
private async Task<bool> TryImportAsync(IImportItemInfo queueItem)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (queueItem.Type)
|
||||
{
|
||||
case ImportExportRecordType.Action:
|
||||
return await _actions.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Archive:
|
||||
return await _archives.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Collection:
|
||||
return await _collections.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.CustomField:
|
||||
return await _customFields.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Developer:
|
||||
return await _developers.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Engine:
|
||||
return await _engines.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Game:
|
||||
return await _games.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Genre:
|
||||
return await _genres.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Key:
|
||||
return await _keys.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Media:
|
||||
return await _media.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.MultiplayerMode:
|
||||
return await _multiplayerModes.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Platform:
|
||||
return await _platforms.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.PlaySession:
|
||||
return await _playSessions.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Publisher:
|
||||
return await _publishers.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Redistributable:
|
||||
return await _redistributables.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Save:
|
||||
return await _saves.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.SavePath:
|
||||
return await _savePaths.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Script:
|
||||
return await _scripts.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Server:
|
||||
return await _servers.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.ServerConsole:
|
||||
return await _serverConsoles.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.ServerHttpPath:
|
||||
return await _serverHttpPaths.ImportAsync(queueItem);
|
||||
|
||||
case ImportExportRecordType.Tag:
|
||||
return await _tags.ImportAsync(queueItem);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error importing record {RecordName}", queueItem.Name);
|
||||
|
||||
OnImportError?.Invoke(this, new ImportStatusUpdate
|
||||
{
|
||||
CurrentItem = CurrentItem,
|
||||
Index = Processed,
|
||||
Total = Total,
|
||||
Error = ex.Message,
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async IAsyncEnumerable<ImportItemInfo> GetImportItemInfoAsync<TModel, TEntity>(IEnumerable<TModel> records,
|
||||
BaseImporter<TModel, TEntity> importer)
|
||||
private async IAsyncEnumerable<ImportItemInfo<TRecord>> GetImportItemInfoAsync<TRecord>(IEnumerable<TRecord> records,
|
||||
BaseImporter<TRecord> importer) where TRecord : class
|
||||
{
|
||||
if (records != null)
|
||||
foreach (var record in records)
|
||||
{
|
||||
if (record != null && record.GetType() == typeof(TModel))
|
||||
if (record != null && record.GetType() == typeof(TRecord))
|
||||
yield return await importer.GetImportInfoAsync(record);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ImportRecordAsync<TRecord, TEntity>(ImportQueueItem queueItem, BaseImporter<TRecord, TEntity> importer) where TRecord : class
|
||||
{
|
||||
var record = queueItem.Record as TRecord;
|
||||
|
||||
try
|
||||
{
|
||||
if (await importer.ExistsAsync(record))
|
||||
await importer.UpdateAsync(record);
|
||||
else
|
||||
await importer.AddAsync(record);
|
||||
|
||||
queueItem.Processed = true;
|
||||
|
||||
OnRecordProcessed?.Invoke(this, queueItem);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Errored.Add(queueItem, ex.Message);
|
||||
OnRecordError?.Invoke(this, queueItem);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Archive != null)
|
||||
|
|
|
|||
|
|
@ -1,49 +1,78 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Action = LANCommander.SDK.Models.Manifest.Action;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class ActionImporter(
|
||||
IMapper mapper,
|
||||
ActionService actionService) : BaseImporter<Action, Data.Models.Action>
|
||||
ILogger<ActionImporter> logger,
|
||||
ActionService actionService,
|
||||
GameService gameService,
|
||||
ServerService serverService,
|
||||
GameImporter gameImporter,
|
||||
ServerImporter serverImporter) : BaseImporter<Action>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Action record) =>
|
||||
await Task.Run(() => new ImportItemInfo { Name = record.Name, Type = ImportExportRecordType.Action });
|
||||
public override string GetKey(Action record)
|
||||
=> $"{nameof(Action)}/{record.Name}";
|
||||
|
||||
public override bool CanImport(Action record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
|
||||
public override async Task<ImportItemInfo<Action>> GetImportInfoAsync(Action record)
|
||||
=> new()
|
||||
{
|
||||
Name = record.Name,
|
||||
Type = ImportExportRecordType.Action,
|
||||
Record = record,
|
||||
};
|
||||
|
||||
public override async Task<Data.Models.Action> AddAsync(Action record)
|
||||
public override async Task<bool> CanImportAsync(Action record) => ImportContext.Manifest is Game;
|
||||
|
||||
public override async Task<bool> AddAsync(Action record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var action = new Data.Models.Action
|
||||
{
|
||||
Name = record.Name,
|
||||
Game = ImportContext.DataRecord as Data.Models.Game,
|
||||
Path = record.Path,
|
||||
WorkingDirectory = record.WorkingDirectory,
|
||||
PrimaryAction = record.IsPrimaryAction,
|
||||
SortOrder = record.SortOrder,
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
};
|
||||
|
||||
action = await actionService.AddAsync(action);
|
||||
if (ImportContext.Manifest is Game game && !ImportContext.InQueue(game, gameImporter))
|
||||
action.Game = await gameService.GetAsync(game.Id);
|
||||
else if (ImportContext.Manifest is SDK.Models.Manifest.Server server &&
|
||||
!ImportContext.InQueue(server, serverImporter))
|
||||
action.Server = await serverService.GetAsync(server.Id);
|
||||
else
|
||||
return false;
|
||||
|
||||
return action;
|
||||
await actionService.AddAsync(action);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Action>(record, "An unknown error occured while importing action", ex);
|
||||
logger.LogError(ex, "Could not add action | {Key}", GetKey(record));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Action> UpdateAsync(Action record)
|
||||
public override async Task<bool> UpdateAsync(Action record)
|
||||
{
|
||||
var existing = await actionService.FirstOrDefaultAsync(a => a.Name == record.Name);
|
||||
Data.Models.Action existing;
|
||||
|
||||
if (ImportContext.Manifest is Game game)
|
||||
existing = await actionService.FirstOrDefaultAsync(a => a.Name == record.Name && a.GameId == game.Id);
|
||||
else if (ImportContext.Manifest is SDK.Models.Manifest.Server server)
|
||||
existing = await actionService.FirstOrDefaultAsync(a => a.Name == record.Name && a.ServerId == server.Id);
|
||||
else
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -51,20 +80,25 @@ public class ActionImporter(
|
|||
existing.WorkingDirectory = record.WorkingDirectory;
|
||||
existing.PrimaryAction = record.IsPrimaryAction;
|
||||
existing.SortOrder = record.SortOrder;
|
||||
existing.Game = ImportContext.DataRecord as Data.Models.Game;
|
||||
existing.CreatedOn = record.CreatedOn;
|
||||
existing.UpdatedOn = record.UpdatedOn;
|
||||
|
||||
existing = await actionService.UpdateAsync(existing);
|
||||
await actionService.UpdateAsync(existing);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Action>(record, "An unknown error occured while importing action", ex);
|
||||
logger.LogError(ex, "Could not update action | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(Action record)
|
||||
{
|
||||
return await actionService.ExistsAsync(a => a.Name == record.Name && a.GameId == ImportContext.DataRecord.Id);
|
||||
if (ImportContext.Manifest is Game game)
|
||||
return await actionService.ExistsAsync(a => a.Name == record.Name && a.GameId == game.Id);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ using LANCommander.SDK.Models.Manifest;
|
|||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
|
|
@ -13,22 +14,26 @@ namespace LANCommander.Server.ImportExport.Importers;
|
|||
/// <param name="serviceProvider">Valid service provider for injecting the services we need</param>
|
||||
/// <param name="ImportContext">The context (archive, parent record> of the import</param>
|
||||
public class ArchiveImporter(
|
||||
IMapper mapper,
|
||||
ArchiveService archiveService) : BaseImporter<Archive, Data.Models.Archive>
|
||||
ILogger<ArchiveImporter> logger,
|
||||
ArchiveService archiveService,
|
||||
GameService gameService,
|
||||
RedistributableService redistributableService) : BaseImporter<Archive>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Archive record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(Archive record)
|
||||
=> $"{nameof(Archive)}/{record.Id}";
|
||||
|
||||
public override async Task<ImportItemInfo<Archive>> GetImportInfoAsync(Archive record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.Archive,
|
||||
Name = record.Version,
|
||||
Size = ImportContext.Archive.Entries.FirstOrDefault(e => e.Key == $"Archives/{record.Id}")?.Size ?? 0,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Archive record) => ImportContext.DataRecord is Data.Models.Game || ImportContext.DataRecord is Data.Models.Redistributable;
|
||||
public override async Task<bool> CanImportAsync(Archive record) => ImportContext.Manifest is Game || ImportContext.Manifest is Redistributable;
|
||||
|
||||
public override async Task<Data.Models.Archive> AddAsync(Archive record)
|
||||
public override async Task<bool> AddAsync(Archive record)
|
||||
{
|
||||
var archiveEntry = ImportContext.Archive.Entries.FirstOrDefault(e => e.Key == $"Archives/{record.Id}");
|
||||
|
||||
|
|
@ -43,6 +48,7 @@ public class ArchiveImporter(
|
|||
var newArchive = new Data.Models.Archive()
|
||||
{
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
StorageLocation = ImportContext.ArchiveStorageLocation,
|
||||
Version = record.Version,
|
||||
Changelog = record.Changelog,
|
||||
|
|
@ -51,10 +57,10 @@ public class ArchiveImporter(
|
|||
UncompressedSize = record.UncompressedSize,
|
||||
};
|
||||
|
||||
if (ImportContext.DataRecord is Data.Models.Game game)
|
||||
newArchive.Game = game;
|
||||
else if (ImportContext.DataRecord is Data.Models.Redistributable redistributable)
|
||||
newArchive.Redistributable = redistributable;
|
||||
if (ImportContext.Manifest is Game game)
|
||||
newArchive.Game = await gameService.GetAsync(game.Id);
|
||||
else if (ImportContext.Manifest is Redistributable redistributable)
|
||||
newArchive.Redistributable = await redistributableService.GetAsync(redistributable.Id);
|
||||
else
|
||||
throw new ImportSkippedException<Archive>(record,
|
||||
$"Cannot import an archive for a {record.GetType().Name}");
|
||||
|
|
@ -62,18 +68,19 @@ public class ArchiveImporter(
|
|||
archive = await archiveService.AddAsync(newArchive);
|
||||
archive = await archiveService.WriteToFileAsync(archive, archiveEntry.OpenEntryStream());
|
||||
|
||||
return archive;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (archive != null)
|
||||
await archiveService.DeleteAsync(archive);
|
||||
|
||||
throw new ImportSkippedException<Archive>(record, "An unknown error occured while importing archive file", ex);
|
||||
logger.LogError(ex, "Could not add archive | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Archive> UpdateAsync(Archive archive)
|
||||
public override async Task<bool> UpdateAsync(Archive archive)
|
||||
{
|
||||
var archiveEntry = ImportContext.Archive.Entries.FirstOrDefault(e => e.Key == $"Archives/{archive.Id}");
|
||||
var existing = await archiveService.Include(a => a.StorageLocation).FirstOrDefaultAsync(a => archive.Id == a.Id);
|
||||
|
|
@ -87,29 +94,33 @@ public class ArchiveImporter(
|
|||
existing.Version = archive.Version;
|
||||
existing.Changelog = archive.Changelog;
|
||||
existing.StorageLocation = ImportContext.ArchiveStorageLocation;
|
||||
existing.CreatedOn = archive.CreatedOn;
|
||||
existing.UpdatedOn = archive.UpdatedOn;
|
||||
|
||||
existing = await archiveService.UpdateAsync(existing);
|
||||
existing = await archiveService.WriteToFileAsync(existing, archiveEntry.OpenEntryStream());
|
||||
|
||||
await archiveService.WriteToFileAsync(existing, archiveEntry.OpenEntryStream());
|
||||
|
||||
if (File.Exists(existingPath))
|
||||
File.Delete(existingPath);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Archive>(archive, "An unknown error occured while importing archive file", ex);
|
||||
logger.LogError(ex, "Could not update archive | {Key}", GetKey(archive));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(Archive archive)
|
||||
{
|
||||
if (ImportContext.DataRecord is Data.Models.Game game)
|
||||
if (ImportContext.Manifest is Game game)
|
||||
return await archiveService.ExistsAsync(a => a.Version == archive.Version && a.GameId == game.Id);
|
||||
|
||||
if (ImportContext.DataRecord is Data.Models.Redistributable redistributable)
|
||||
if (ImportContext.Manifest is Redistributable redistributable)
|
||||
return await archiveService.ExistsAsync(a => a.Version == archive.Version && a.RedistributableId == redistributable.Id);
|
||||
|
||||
throw new ImportSkippedException<Archive>(archive, $"Cannot import an archive for a {ImportContext.DataRecord.GetType().Name}");
|
||||
throw new ImportSkippedException<Archive>(archive, $"Cannot import archive, incompatible manifest");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +1,53 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class CollectionImporter(
|
||||
IMapper mapper,
|
||||
CollectionService collectionService,
|
||||
GameService gameService) : BaseImporter<Collection, Data.Models.Collection>
|
||||
ILogger<CollectionImporter> logger,
|
||||
CollectionService collectionService) : BaseImporter<Collection>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Collection record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(Collection record)
|
||||
=> $"{nameof(Collection)}/{record.Name}";
|
||||
|
||||
public override async Task<ImportItemInfo<Collection>> GetImportInfoAsync(Collection record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.Collection,
|
||||
Name = record.Name,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Collection record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
public override async Task<bool> CanImportAsync(Collection record)
|
||||
=> await collectionService.ExistsAsync(c => c.Name == record.Name);
|
||||
|
||||
public override async Task<Data.Models.Collection> AddAsync(Collection record)
|
||||
public override async Task<bool> AddAsync(Collection record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var collection = new Data.Models.Collection
|
||||
{
|
||||
Games = new List<Data.Models.Game>() { ImportContext.DataRecord as Data.Models.Game },
|
||||
Name = record.Name,
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
};
|
||||
|
||||
collection = await collectionService.AddAsync(collection);
|
||||
await collectionService.AddAsync(collection);
|
||||
|
||||
return collection;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Collection>(record, "An unknown error occured while importing collection", ex);
|
||||
logger.LogError(ex, "Could not add collection | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Collection> UpdateAsync(Collection record)
|
||||
{
|
||||
var existing = await collectionService.Include(c => c.Games).FirstOrDefaultAsync(c => c.Name == record.Name);
|
||||
var game = ImportContext.DataRecord as Data.Models.Game;
|
||||
|
||||
try
|
||||
{
|
||||
if (existing.Games == null)
|
||||
existing.Games = new List<Data.Models.Game>();
|
||||
|
||||
if (!existing.Games.Any(g => g.Id == game.Id))
|
||||
{
|
||||
existing.Games.Add(await gameService.GetAsync(game.Id));
|
||||
|
||||
existing = await collectionService.UpdateAsync(existing);
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Collection>(record, "An unknown error occured while importing collection", ex);
|
||||
}
|
||||
}
|
||||
public override async Task<bool> UpdateAsync(Collection record) => true;
|
||||
|
||||
public override async Task<bool> ExistsAsync(Collection record)
|
||||
{
|
||||
return await collectionService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
=> await collectionService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
|
|
@ -4,58 +4,83 @@ using LANCommander.SDK.Models.Manifest;
|
|||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class CustomFieldImporter(
|
||||
IMapper mapper,
|
||||
GameCustomFieldService gameCustomFieldService,
|
||||
GameService gameService) : BaseImporter<GameCustomField, Data.Models.GameCustomField>
|
||||
ILogger<CustomFieldImporter> logger,
|
||||
GameService gameService,
|
||||
GameImporter gameImporter) : BaseImporter<GameCustomField>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(GameCustomField record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(GameCustomField record)
|
||||
=> $"{nameof(GameCustomField)}/{record.Name}";
|
||||
|
||||
public override async Task<ImportItemInfo<GameCustomField>> GetImportInfoAsync(GameCustomField record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.CustomField,
|
||||
Name = record.Name,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(GameCustomField record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
|
||||
public override async Task<Data.Models.GameCustomField> AddAsync(GameCustomField record)
|
||||
public override async Task<bool> CanImportAsync(GameCustomField record) => ImportContext.Manifest is Game;
|
||||
|
||||
public override async Task<bool> AddAsync(GameCustomField record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var customField = await gameService.SetCustomFieldAsync(ImportContext.DataRecord.Id, record.Name, record.Value);
|
||||
var game = ImportContext.Manifest as Game;
|
||||
|
||||
return customField;
|
||||
if (game == null)
|
||||
return false;
|
||||
|
||||
if (ImportContext.InQueue(game, gameImporter))
|
||||
return false;
|
||||
|
||||
await gameService.SetCustomFieldAsync(game.Id, record.Name, record.Value);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<GameCustomField>(record, "An unknown error occured while importing customField", ex);
|
||||
logger.LogError(ex, "Could not add custom field | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.GameCustomField> UpdateAsync(GameCustomField record)
|
||||
public override async Task<bool> UpdateAsync(GameCustomField record)
|
||||
{
|
||||
var existing = await gameService.GetCustomFieldAsync(ImportContext.DataRecord.Id, record.Name);
|
||||
|
||||
try
|
||||
{
|
||||
var game = ImportContext.Manifest as Game;
|
||||
|
||||
if (game == null)
|
||||
return false;
|
||||
|
||||
var existing = await gameService.GetCustomFieldAsync(game.Id, record.Name);
|
||||
|
||||
if (existing.Value != record.Value)
|
||||
existing = await gameService.SetCustomFieldAsync(ImportContext.DataRecord.Id, record.Name, record.Value);
|
||||
await gameService.SetCustomFieldAsync(game.Id, record.Name, record.Value);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<GameCustomField>(record, "An unknown error occured while importing customField", ex);
|
||||
logger.LogError(ex, "Could not update custom field | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(GameCustomField record)
|
||||
{
|
||||
return (await gameService.GetCustomFieldAsync(ImportContext.DataRecord.Id, record.Name)) == null;
|
||||
if (ImportContext.Manifest is Game game)
|
||||
{
|
||||
var customField = await gameService.GetCustomFieldAsync(game.Id, record.Name);
|
||||
|
||||
return customField != null;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,84 +4,53 @@ using LANCommander.SDK.Models.Manifest;
|
|||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class DeveloperImporter(
|
||||
IMapper mapper,
|
||||
ILogger<DeveloperImporter> logger,
|
||||
CompanyService companyService,
|
||||
GameService gameService) : BaseImporter<Company, Data.Models.Company>
|
||||
GameService gameService) : BaseImporter<Company>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Company record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(Company record)
|
||||
=> $"Developer/{record.Name}";
|
||||
|
||||
public override async Task<ImportItemInfo<Company>> GetImportInfoAsync(Company record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.Developer,
|
||||
Name = record.Name,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Company record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
public override async Task<bool> CanImportAsync(Company record)
|
||||
=> await companyService.ExistsAsync(c => c.Name == record.Name);
|
||||
|
||||
public override async Task<Data.Models.Company> AddAsync(Company record)
|
||||
public override async Task<bool> AddAsync(Company record)
|
||||
{
|
||||
if (ImportContext.DataRecord is not Data.Models.Game)
|
||||
throw new ImportSkippedException<Company>(record, $"Cannot import developers for a {ImportContext.DataRecord.GetType().Name}");
|
||||
|
||||
try
|
||||
{
|
||||
var game = ImportContext.DataRecord as Data.Models.Game;
|
||||
|
||||
var company = new Data.Models.Company
|
||||
{
|
||||
DevelopedGames = [await gameService.GetAsync(game.Id)],
|
||||
Name = record.Name,
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
};
|
||||
|
||||
company = await companyService.AddAsync(company);
|
||||
await companyService.AddAsync(company);
|
||||
|
||||
return company;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Company>(record, "An unknown error occured while importing developer", ex);
|
||||
logger.LogError(ex, "Could not import developer | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Company> UpdateAsync(Company record)
|
||||
{
|
||||
if (ImportContext.DataRecord is not Data.Models.Game)
|
||||
throw new ImportSkippedException<Company>(record, $"Cannot import developers for a {ImportContext.DataRecord.GetType().Name}");
|
||||
|
||||
var existing = await companyService.Include(g => g.DevelopedGames).FirstOrDefaultAsync(c => c.Name == record.Name);
|
||||
|
||||
try
|
||||
{
|
||||
var game = ImportContext.DataRecord as Data.Models.Game;
|
||||
|
||||
if (existing.DevelopedGames == null)
|
||||
existing.DevelopedGames = new List<Data.Models.Game>();
|
||||
|
||||
if (!existing.DevelopedGames.Any(g => g.Id == game.Id))
|
||||
{
|
||||
existing.DevelopedGames.Add(await gameService.GetAsync(game.Id));
|
||||
|
||||
existing = await companyService.UpdateAsync(existing);
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Company>(record, "An unknown error occured while importing developer", ex);
|
||||
}
|
||||
}
|
||||
public override async Task<bool> UpdateAsync(Company record) => true;
|
||||
|
||||
public override async Task<bool> ExistsAsync(Company record)
|
||||
{
|
||||
if (ImportContext.DataRecord is not Data.Models.Game game)
|
||||
throw new ImportSkippedException<Company>(record, $"Cannot import developers for a {ImportContext.DataRecord.GetType().Name}");
|
||||
|
||||
return await companyService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
=> await companyService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
|
|
@ -1,76 +1,53 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class EngineImporter(
|
||||
IMapper mapper,
|
||||
EngineService engineService,
|
||||
GameService gameService) : BaseImporter<Engine, Data.Models.Engine>
|
||||
ILogger<EngineImporter> logger,
|
||||
EngineService engineService) : BaseImporter<Engine>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Engine record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(Engine record)
|
||||
=> $"{nameof(Engine)}/{record.Name}";
|
||||
|
||||
public override async Task<ImportItemInfo<Engine>> GetImportInfoAsync(Engine record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.Engine,
|
||||
Name = record.Name,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Engine record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
public override async Task<bool> CanImportAsync(Engine record)
|
||||
=> await engineService.ExistsAsync(e => e.Name == record.Name);
|
||||
|
||||
public override async Task<Data.Models.Engine> AddAsync(Engine record)
|
||||
public override async Task<bool> AddAsync(Engine record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var engine = new Data.Models.Engine
|
||||
{
|
||||
Games = new List<Data.Models.Game>() { ImportContext.DataRecord as Data.Models.Game },
|
||||
Name = record.Name,
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
};
|
||||
|
||||
engine = await engineService.AddAsync(engine);
|
||||
await engineService.AddAsync(engine);
|
||||
|
||||
return engine;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Engine>(record, "An unknown error occured while importing engine", ex);
|
||||
logger.LogError(ex, "Could not add engine | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Engine> UpdateAsync(Engine record)
|
||||
{
|
||||
var existing = await engineService.Include(g => g.Games).FirstOrDefaultAsync(c => c.Name == record.Name);
|
||||
var game = ImportContext.DataRecord as Data.Models.Game;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
if (existing.Games == null)
|
||||
existing.Games = new List<Data.Models.Game>();
|
||||
public override async Task<bool> UpdateAsync(Engine record) => true;
|
||||
|
||||
if (!existing.Games.Any(g => g.Id == game.Id))
|
||||
{
|
||||
existing.Games.Add(await gameService.GetAsync(game.Id));
|
||||
|
||||
existing = await engineService.UpdateAsync(existing);
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Engine>(record, "An unknown error occured while importing engine", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(Engine record)
|
||||
{
|
||||
return await engineService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
public override async Task<bool> ExistsAsync(Engine record)
|
||||
=> await engineService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
|
|
@ -1,30 +1,36 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class GameImporter(
|
||||
IMapper mapper,
|
||||
ILogger<GameImporter> logger,
|
||||
GameService gameService,
|
||||
UserService userService) : BaseImporter<Game, Data.Models.Game>
|
||||
UserService userService) : BaseImporter<Game>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Game record)
|
||||
public override string GetKey(Game record)
|
||||
=> $"{nameof(Game)}/{record.Id}";
|
||||
|
||||
public override async Task<ImportItemInfo<Game>> GetImportInfoAsync(Game record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
return new ImportItemInfo<Game>
|
||||
{
|
||||
Type = ImportExportRecordType.Game,
|
||||
Name = record.Title,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Game record) => true;
|
||||
public override async Task<bool> CanImportAsync(Game record) => true;
|
||||
|
||||
public override async Task<Data.Models.Game> AddAsync(Game record)
|
||||
public override async Task<bool> AddAsync(Game record)
|
||||
{
|
||||
var game = new Data.Models.Game
|
||||
{
|
||||
Id = record.Id,
|
||||
Title = record.Title,
|
||||
SortTitle = record.SortTitle,
|
||||
Description = record.Description,
|
||||
|
|
@ -46,15 +52,18 @@ public class GameImporter(
|
|||
|
||||
try
|
||||
{
|
||||
return await gameService.AddAsync(game);
|
||||
await gameService.AddAsync(game);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Game>(record, "An unknown error occurred while trying to add game", ex);
|
||||
logger.LogError(ex, "Could not add game | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Game> UpdateAsync(Game record)
|
||||
public override async Task<bool> UpdateAsync(Game record)
|
||||
{
|
||||
var existing = await gameService.FirstOrDefaultAsync(g => g.Id == record.Id || g.Title == record.Title);
|
||||
|
||||
|
|
@ -77,15 +86,14 @@ public class GameImporter(
|
|||
if (!String.IsNullOrWhiteSpace(record.UpdatedBy))
|
||||
existing.UpdatedBy = await userService.GetAsync(record.UpdatedBy);
|
||||
|
||||
existing = await gameService.UpdateAsync(existing);
|
||||
|
||||
// importContext.UseRecord(existing);
|
||||
await gameService.UpdateAsync(existing);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Game>(record, "An unknown error occurred while trying to update game", ex);
|
||||
logger.LogError(ex, "Could not update game | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -93,4 +101,96 @@ public class GameImporter(
|
|||
{
|
||||
return await gameService.ExistsAsync(g => g.Id == record.Id || g.Title == record.Title);
|
||||
}
|
||||
|
||||
public async Task FinalizeAsync()
|
||||
{
|
||||
if (ImportContext.Manifest is not Game)
|
||||
return;
|
||||
|
||||
var manifest = ImportContext.Manifest as Game;
|
||||
|
||||
if (manifest == null)
|
||||
return;
|
||||
|
||||
var game = await gameService
|
||||
.Include(g => g.Collections)
|
||||
.Include(g => g.Developers)
|
||||
.Include(g => g.Genres)
|
||||
.Include(g => g.Platforms)
|
||||
.Include(g => g.Publishers)
|
||||
.Include(g => g.Tags)
|
||||
.GetAsync(manifest.Id);
|
||||
|
||||
await gameService.SyncRelatedCollectionAsync(
|
||||
game,
|
||||
g => g.Collections,
|
||||
manifest.Collections,
|
||||
r => c => c.Name == r.Name,
|
||||
(c, rc) =>
|
||||
{
|
||||
c.Name = rc.Name;
|
||||
c.CreatedOn = rc.CreatedOn;
|
||||
c.UpdatedOn = rc.UpdatedOn;
|
||||
});
|
||||
|
||||
await gameService.SyncRelatedCollectionAsync(
|
||||
game,
|
||||
g => g.Developers,
|
||||
manifest.Developers,
|
||||
r => c => c.Name == r.Name,
|
||||
(d, rd) =>
|
||||
{
|
||||
d.Name = rd.Name;
|
||||
d.CreatedOn = rd.CreatedOn;
|
||||
d.UpdatedOn = rd.UpdatedOn;
|
||||
});
|
||||
|
||||
await gameService.SyncRelatedCollectionAsync(
|
||||
game,
|
||||
g => g.Genres,
|
||||
manifest.Genres,
|
||||
r => g => g.Name == r.Name,
|
||||
(g, gr) =>
|
||||
{
|
||||
g.Name = gr.Name;
|
||||
g.CreatedOn = gr.CreatedOn;
|
||||
g.UpdatedOn = gr.UpdatedOn;
|
||||
});
|
||||
|
||||
await gameService.SyncRelatedCollectionAsync(
|
||||
game,
|
||||
g => g.Platforms,
|
||||
manifest.Platforms,
|
||||
r => p => p.Name == r.Name,
|
||||
(p, pr) =>
|
||||
{
|
||||
p.Name = pr.Name;
|
||||
p.CreatedOn = pr.CreatedOn;
|
||||
p.UpdatedOn = pr.UpdatedOn;
|
||||
});
|
||||
|
||||
await gameService.SyncRelatedCollectionAsync(
|
||||
game,
|
||||
g => g.Publishers,
|
||||
manifest.Publishers,
|
||||
r => p => p.Name == r.Name,
|
||||
(p, pr) =>
|
||||
{
|
||||
p.Name = pr.Name;
|
||||
p.CreatedOn = pr.CreatedOn;
|
||||
p.UpdatedOn = pr.UpdatedOn;
|
||||
});
|
||||
|
||||
await gameService.SyncRelatedCollectionAsync(
|
||||
game,
|
||||
g => g.Tags,
|
||||
manifest.Tags,
|
||||
r => t => t.Name == r.Name,
|
||||
(t, tr) =>
|
||||
{
|
||||
t.Name = tr.Name;
|
||||
t.CreatedOn = tr.CreatedOn;
|
||||
t.UpdatedOn = tr.UpdatedOn;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,75 +1,55 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class GenreImporter(
|
||||
IMapper mapper,
|
||||
GenreService genreService,
|
||||
GameService gameService) : BaseImporter<Genre, Data.Models.Genre>
|
||||
ILogger<GenreImporter> logger,
|
||||
GenreService genreService) : BaseImporter<Genre>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Genre record)
|
||||
public override string GetKey(Genre record)
|
||||
=> $"{nameof(Genre)}/{record.Name}";
|
||||
|
||||
public override async Task<ImportItemInfo<Genre>> GetImportInfoAsync(Genre record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
return new ImportItemInfo<Genre>
|
||||
{
|
||||
Type = ImportExportRecordType.Genre,
|
||||
Name = record.Name,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Genre record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
public override async Task<bool> CanImportAsync(Genre record)
|
||||
=> await genreService.ExistsAsync(g => g.Name == record.Name);
|
||||
|
||||
public override async Task<Data.Models.Genre> AddAsync(Genre record)
|
||||
public override async Task<bool> AddAsync(Genre record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var genre = new Data.Models.Genre
|
||||
{
|
||||
Games = new List<Data.Models.Game>() { ImportContext.DataRecord as Data.Models.Game },
|
||||
Name = record.Name,
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
};
|
||||
|
||||
genre = await genreService.AddAsync(genre);
|
||||
await genreService.AddAsync(genre);
|
||||
|
||||
return genre;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Genre>(record, "An unknown error occured while importing genre", ex);
|
||||
logger.LogError(ex, "Could not add genre | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Genre> UpdateAsync(Genre record)
|
||||
{
|
||||
var existing = await genreService.Include(g => g.Games).FirstOrDefaultAsync(c => c.Name == record.Name);
|
||||
var game = ImportContext.DataRecord as Data.Models.Game;
|
||||
|
||||
try
|
||||
{
|
||||
if (existing.Games == null)
|
||||
existing.Games = new List<Data.Models.Game>();
|
||||
public override async Task<bool> UpdateAsync(Genre record) => true;
|
||||
|
||||
if (!existing.Games.Any(g => g.Id == game.Id))
|
||||
{
|
||||
existing.Games.Add(await gameService.GetAsync(game.Id));
|
||||
|
||||
existing = await genreService.UpdateAsync(existing);
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Genre>(record, "An unknown error occured while importing genre", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(Genre record)
|
||||
{
|
||||
return await genreService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
public override async Task<bool> ExistsAsync(Genre record)
|
||||
=> await genreService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
|
|
@ -1,51 +1,68 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class KeyImporter(
|
||||
IMapper mapper,
|
||||
KeyService keyService) : BaseImporter<Key, Data.Models.Key>
|
||||
ILogger<KeyImporter> logger,
|
||||
KeyService keyService,
|
||||
GameImporter gameImporter,
|
||||
GameService gameService) : BaseImporter<Key>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Key record)
|
||||
public override string GetKey(Key record)
|
||||
=> $"{nameof(Key)}/{record.Value}";
|
||||
|
||||
public override async Task<ImportItemInfo<Key>> GetImportInfoAsync(Key record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
return new ImportItemInfo<Key>
|
||||
{
|
||||
Type = ImportExportRecordType.Key,
|
||||
Name = new String('*', record.Value.Length),
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Key record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
public override async Task<bool> CanImportAsync(Key record)
|
||||
=> await keyService.ExistsAsync(k => k.Value == record.Value);
|
||||
|
||||
public override async Task<Data.Models.Key> AddAsync(Key record)
|
||||
public override async Task<bool> AddAsync(Key record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var game = ImportContext.Manifest as Game;
|
||||
|
||||
if (game == null)
|
||||
return false;
|
||||
|
||||
if (ImportContext.InQueue(game, gameImporter))
|
||||
return false;
|
||||
|
||||
var key = new Data.Models.Key
|
||||
{
|
||||
Game = ImportContext.DataRecord as Data.Models.Game,
|
||||
Game = await gameService.GetAsync(game.Id),
|
||||
AllocationMethod = record.AllocationMethod,
|
||||
ClaimedByComputerName = record.ClaimedByComputerName,
|
||||
ClaimedByIpv4Address = record.ClaimedByIpv4Address,
|
||||
ClaimedByMacAddress = record.ClaimedByMacAddress,
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
};
|
||||
|
||||
key = await keyService.AddAsync(key);
|
||||
await keyService.AddAsync(key);
|
||||
|
||||
return key;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Key>(record, "An unknown error occured while importing key", ex);
|
||||
logger.LogError(ex, "Could not add key | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Key> UpdateAsync(Key record)
|
||||
public override async Task<bool> UpdateAsync(Key record)
|
||||
{
|
||||
var existing = await keyService.FirstOrDefaultAsync(k => k.Value == record.Value);
|
||||
|
||||
|
|
@ -56,18 +73,22 @@ public class KeyImporter(
|
|||
existing.ClaimedByIpv4Address = record.ClaimedByIpv4Address;
|
||||
existing.ClaimedByMacAddress = record.ClaimedByMacAddress;
|
||||
|
||||
existing = await keyService.UpdateAsync(existing);
|
||||
await keyService.UpdateAsync(existing);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Key>(record, "An unknown error occured while importing key", ex);
|
||||
logger.LogError(ex, "Could not update key | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(Key record)
|
||||
{
|
||||
return await keyService.ExistsAsync(k => k.Value == record.Value);
|
||||
if (ImportContext.Manifest is Game game)
|
||||
return await keyService.ExistsAsync(k => k.Value == record.Value && k.GameId == game.Id);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
|
|
@ -9,24 +8,29 @@ using Microsoft.Extensions.Logging;
|
|||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class MediaImporter(
|
||||
IMapper mapper,
|
||||
ILogger<MediaImporter> logger,
|
||||
StorageLocationService storageLocationService,
|
||||
MediaService mediaService) : BaseImporter<Media, Data.Models.Media>
|
||||
MediaService mediaService,
|
||||
GameService gameService,
|
||||
GameImporter gameImporter) : BaseImporter<Media>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Media record)
|
||||
public override string GetKey(Media record)
|
||||
=> $"{nameof(Media)}/{record.Id}";
|
||||
|
||||
public override async Task<ImportItemInfo<Media>> GetImportInfoAsync(Media record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
return new ImportItemInfo<Media>
|
||||
{
|
||||
Type = ImportExportRecordType.Media,
|
||||
Name = String.IsNullOrWhiteSpace(record.Name) ? record.Type.ToString() : $"{record.Type} - {record.Name}",
|
||||
Size = ImportContext.Archive.Entries.FirstOrDefault(e => e.Key == $"Media/{record.Id}")?.Size ?? 0,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Media record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
public override async Task<bool> CanImportAsync(Media record) => ImportContext.Manifest is Game;
|
||||
|
||||
public override async Task<Data.Models.Media> AddAsync(Media record)
|
||||
public override async Task<bool> AddAsync(Media record)
|
||||
{
|
||||
var archiveEntry = ImportContext.Archive.Entries.FirstOrDefault(e => e.Key == $"Media/{record.Id}");
|
||||
|
||||
|
|
@ -37,9 +41,19 @@ public class MediaImporter(
|
|||
|
||||
try
|
||||
{
|
||||
var game = ImportContext.Manifest as Game;
|
||||
|
||||
if (game == null)
|
||||
return false;
|
||||
|
||||
if (ImportContext.InQueue(game, gameImporter))
|
||||
return false;
|
||||
|
||||
media = new Data.Models.Media
|
||||
{
|
||||
Game = ImportContext.DataRecord as Data.Models.Game,
|
||||
Id = record.Id,
|
||||
FileId = record.FileId,
|
||||
Game = await gameService.GetAsync(record.Id),
|
||||
CreatedOn = record.CreatedOn,
|
||||
Type = record.Type,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
|
|
@ -50,23 +64,23 @@ public class MediaImporter(
|
|||
};
|
||||
|
||||
media = await mediaService.AddAsync(media);
|
||||
media = await mediaService.WriteToFileAsync(media, archiveEntry.OpenEntryStream());
|
||||
|
||||
await mediaService.WriteToFileAsync(media, archiveEntry.OpenEntryStream());
|
||||
|
||||
return media;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (media?.Id != Guid.Empty)
|
||||
await mediaService.DeleteAsync(media);
|
||||
|
||||
logger.LogError(ex, "An unknown error occured while trying to import media file");
|
||||
logger.LogError(ex, "An unknown error occured while trying to import media file | {Key}", GetKey(record));
|
||||
|
||||
throw new ImportSkippedException<Media>(record, "An unknown error occured while trying to import media file",
|
||||
ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Media> UpdateAsync(Media record)
|
||||
public override async Task<bool> UpdateAsync(Media record)
|
||||
{
|
||||
var archiveEntry = ImportContext.Archive.Entries.FirstOrDefault(e => e.Key == $"Media/{record.Id}");
|
||||
var existing = await mediaService.Include(m => m.StorageLocation).FirstOrDefaultAsync(m => m.Type == record.Type && m.Game.Id == record.Id);
|
||||
|
|
@ -77,7 +91,16 @@ public class MediaImporter(
|
|||
|
||||
try
|
||||
{
|
||||
existing.Game = ImportContext.DataRecord as Data.Models.Game;
|
||||
var game = ImportContext.Manifest as Game;
|
||||
|
||||
if (game == null)
|
||||
return false;
|
||||
|
||||
if (ImportContext.InQueue(game, gameImporter))
|
||||
return false;
|
||||
|
||||
existing.FileId = record.FileId;
|
||||
existing.Game = await gameService.GetAsync(game.Id);
|
||||
existing.Name = record.Name;
|
||||
existing.MimeType = record.MimeType;
|
||||
existing.CreatedOn = record.CreatedOn;
|
||||
|
|
@ -86,21 +109,21 @@ public class MediaImporter(
|
|||
existing.SourceUrl = record.SourceUrl;
|
||||
|
||||
existing = await mediaService.UpdateAsync(existing);
|
||||
existing = await mediaService.WriteToFileAsync(existing, archiveEntry.OpenEntryStream());
|
||||
|
||||
await mediaService.WriteToFileAsync(existing, archiveEntry.OpenEntryStream());
|
||||
|
||||
if (File.Exists(existingPath))
|
||||
File.Delete(existingPath);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Media>(record, "An unknown error occured while importing media file", ex);
|
||||
logger.LogError(ex, "Could not update media | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override Task<bool> ExistsAsync(Media media)
|
||||
{
|
||||
return mediaService.ExistsAsync(m => m.Type == media.Type && m.Id == media.Id);
|
||||
}
|
||||
=> mediaService.ExistsAsync(m => m.Type == media.Type && m.Id == media.Id);
|
||||
}
|
||||
|
|
@ -1,60 +1,80 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class MultiplayerModeImporter(
|
||||
IMapper mapper,
|
||||
MultiplayerModeService multiplayerModeService) : BaseImporter<MultiplayerMode, Data.Models.MultiplayerMode>
|
||||
ILogger<MultiplayerModeImporter> logger,
|
||||
MultiplayerModeService multiplayerModeService,
|
||||
GameService gameService,
|
||||
GameImporter gameImporter) : BaseImporter<MultiplayerMode>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(MultiplayerMode record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(MultiplayerMode record)
|
||||
=> $"{nameof(MultiplayerMode)}/{record.NetworkProtocol}:{record.Type}";
|
||||
|
||||
public override async Task<ImportItemInfo<MultiplayerMode>> GetImportInfoAsync(MultiplayerMode record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.MultiplayerMode,
|
||||
Name = String.IsNullOrWhiteSpace(record.Description) ? record.Type.ToString() : $"{record.Type} - {record.Description}",
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(MultiplayerMode record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
public override async Task<bool> CanImportAsync(MultiplayerMode record) => ImportContext.Manifest is Game;
|
||||
|
||||
public override async Task<Data.Models.MultiplayerMode> AddAsync(MultiplayerMode record)
|
||||
public override async Task<bool> AddAsync(MultiplayerMode record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var game = ImportContext.Manifest as Game;
|
||||
|
||||
if (game == null)
|
||||
return false;
|
||||
|
||||
if (ImportContext.InQueue(game, gameImporter))
|
||||
return false;
|
||||
|
||||
var multiplayerMode = new Data.Models.MultiplayerMode
|
||||
{
|
||||
Game = ImportContext.DataRecord as Data.Models.Game,
|
||||
Description = record.Description,
|
||||
Type = record.Type,
|
||||
Spectators = record.Spectators,
|
||||
MinPlayers = record.MinPlayers,
|
||||
MaxPlayers = record.MaxPlayers,
|
||||
NetworkProtocol = record.NetworkProtocol,
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
Game = await gameService.GetAsync(game.Id),
|
||||
};
|
||||
|
||||
multiplayerMode = await multiplayerModeService.AddAsync(multiplayerMode);
|
||||
await multiplayerModeService.AddAsync(multiplayerMode);
|
||||
|
||||
return multiplayerMode;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<MultiplayerMode>(record, "An unknown error occured while importing multiplayer mode", ex);
|
||||
logger.LogError(ex, "Could not add multiplayer mode | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.MultiplayerMode> UpdateAsync(MultiplayerMode record)
|
||||
public override async Task<bool> UpdateAsync(MultiplayerMode record)
|
||||
{
|
||||
var game = ImportContext.DataRecord as Data.Models.Game;
|
||||
|
||||
var existing = await multiplayerModeService.FirstOrDefaultAsync(m => m.GameId == game.Id && m.Type == record.Type);
|
||||
|
||||
try
|
||||
{
|
||||
var game = ImportContext.Manifest as Game;
|
||||
|
||||
if (game == null)
|
||||
return false;
|
||||
|
||||
if (ImportContext.InQueue(game, gameImporter))
|
||||
return false;
|
||||
|
||||
var existing = await multiplayerModeService.FirstOrDefaultAsync(m => m.GameId == game.Id && m.Type == record.Type);
|
||||
|
||||
existing.Description = record.Description;
|
||||
existing.Type = record.Type;
|
||||
existing.Spectators = record.Spectators;
|
||||
|
|
@ -62,20 +82,22 @@ public class MultiplayerModeImporter(
|
|||
existing.MaxPlayers = record.MaxPlayers;
|
||||
existing.NetworkProtocol = record.NetworkProtocol;
|
||||
|
||||
existing = await multiplayerModeService.UpdateAsync(existing);
|
||||
await multiplayerModeService.UpdateAsync(existing);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<MultiplayerMode>(record, "An unknown error occured while importing multiplayer mode", ex);
|
||||
logger.LogError(ex, "Could not update multiplayer mode | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(MultiplayerMode record)
|
||||
{
|
||||
var game = ImportContext.DataRecord as Data.Models.Game;
|
||||
|
||||
return await multiplayerModeService.ExistsAsync(m => m.GameId == game.Id && m.Type == record.Type);
|
||||
if (ImportContext.Manifest is Game game)
|
||||
return await multiplayerModeService.ExistsAsync(m => m.GameId == game.Id && m.Type == record.Type);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +1,53 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class PlatformImporter(
|
||||
IMapper mapper,
|
||||
PlatformService platformService,
|
||||
GameService gameService) : BaseImporter<Platform, Data.Models.Platform>
|
||||
ILogger<PlatformImporter> logger,
|
||||
PlatformService platformService) : BaseImporter<Platform>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Platform record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(Platform record)
|
||||
=> $"{nameof(Platform)}/{record.Name}";
|
||||
|
||||
public override async Task<ImportItemInfo<Platform>> GetImportInfoAsync(Platform record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.Platform,
|
||||
Name = record.Name,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Platform record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
public override async Task<bool> CanImportAsync(Platform record)
|
||||
=> await platformService.ExistsAsync(p => p.Name == record.Name);
|
||||
|
||||
public override async Task<Data.Models.Platform> AddAsync(Platform record)
|
||||
public override async Task<bool> AddAsync(Platform record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var platform = new Data.Models.Platform
|
||||
{
|
||||
Games = new List<Data.Models.Game>() { ImportContext.DataRecord as Data.Models.Game },
|
||||
Name = record.Name,
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
};
|
||||
|
||||
platform = await platformService.AddAsync(platform);
|
||||
await platformService.AddAsync(platform);
|
||||
|
||||
return platform;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Platform>(record, "An unknown error occured while importing platform", ex);
|
||||
logger.LogError(ex, "Failed to add platform | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Platform> UpdateAsync(Platform record)
|
||||
{
|
||||
var existing = await platformService.Include(p => p.Games).FirstOrDefaultAsync(c => c.Name == record.Name);
|
||||
var game = ImportContext.DataRecord as Data.Models.Game;
|
||||
|
||||
try
|
||||
{
|
||||
if (existing.Games == null)
|
||||
existing.Games = new List<Data.Models.Game>();
|
||||
|
||||
if (!existing.Games.Any(g => g.Id == game.Id))
|
||||
{
|
||||
existing.Games.Add(await gameService.GetAsync(game.Id));
|
||||
|
||||
existing = await platformService.UpdateAsync(existing);
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Platform>(record, "An unknown error occured while importing platform", ex);
|
||||
}
|
||||
}
|
||||
public override async Task<bool> UpdateAsync(Platform record) => true;
|
||||
|
||||
public override async Task<bool> ExistsAsync(Platform record)
|
||||
{
|
||||
return await platformService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
=> await platformService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
|
|
@ -1,77 +1,99 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class PlaySessionImporter(
|
||||
IMapper mapper,
|
||||
ILogger<PlaySessionImporter> logger,
|
||||
PlaySessionService playSessionService,
|
||||
UserService userService) : BaseImporter<PlaySession, Data.Models.PlaySession>
|
||||
UserService userService,
|
||||
GameService gameService,
|
||||
GameImporter gameImporter) : BaseImporter<PlaySession>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(PlaySession record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(PlaySession record)
|
||||
=> $"{nameof(PlaySession)}/{record.User}:{record.Start}:{record.End}";
|
||||
|
||||
public override async Task<ImportItemInfo<PlaySession>> GetImportInfoAsync(PlaySession record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.PlaySession,
|
||||
Name = $"{record.User} - {record.Start}-{record.End}",
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(PlaySession record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
public override async Task<bool> CanImportAsync(PlaySession record) => ImportContext.Manifest is Game;
|
||||
|
||||
public override async Task<Data.Models.PlaySession> AddAsync(PlaySession record)
|
||||
public override async Task<bool> AddAsync(PlaySession record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var game = ImportContext.Manifest as Game;
|
||||
|
||||
if (game == null)
|
||||
return false;
|
||||
|
||||
if (ImportContext.InQueue(game, gameImporter))
|
||||
return false;
|
||||
|
||||
var playSession = new Data.Models.PlaySession
|
||||
{
|
||||
Start = record.Start,
|
||||
End = record.End,
|
||||
User = await userService.GetAsync(record.User),
|
||||
Game = ImportContext.DataRecord as Data.Models.Game,
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
Game = await gameService.GetAsync(game.Id),
|
||||
};
|
||||
|
||||
playSession = await playSessionService.AddAsync(playSession);
|
||||
await playSessionService.AddAsync(playSession);
|
||||
|
||||
return playSession;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<PlaySession>(record, "An unknown error occured while importing playSession", ex);
|
||||
logger.LogError(ex, "Failed to add play session | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.PlaySession> UpdateAsync(PlaySession record)
|
||||
public override async Task<bool> UpdateAsync(PlaySession record)
|
||||
{
|
||||
var game = ImportContext.DataRecord as Data.Models.Game;
|
||||
var user = await userService.GetAsync(record.User);
|
||||
|
||||
var existing = await playSessionService.FirstOrDefaultAsync(ps => ps.GameId == game.Id && ps.Start == record.Start && ps.UserId == user.Id);
|
||||
|
||||
try
|
||||
{
|
||||
var user = await userService.GetAsync(record.User);
|
||||
var game = ImportContext.Manifest as Game;
|
||||
|
||||
if (game == null)
|
||||
return false;
|
||||
|
||||
var existing = await playSessionService.FirstOrDefaultAsync(ps => ps.GameId == game.Id && ps.Start == record.Start && ps.UserId == user.Id);
|
||||
|
||||
existing.Start = record.Start;
|
||||
existing.End = record.End;
|
||||
|
||||
existing = await playSessionService.UpdateAsync(existing);
|
||||
await playSessionService.UpdateAsync(existing);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<PlaySession>(record, "An unknown error occured while importing playSession", ex);
|
||||
logger.LogError(ex, "Failed to update play session | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(PlaySession record)
|
||||
{
|
||||
var game = ImportContext.DataRecord as Data.Models.Game;
|
||||
var user = await userService.GetAsync(record.User);
|
||||
|
||||
return await playSessionService.ExistsAsync(ps => (ps.Game.Id == game.Id || ps.Game.Title == game.Title) && ps.Start == record.Start && ps.UserId == user.Id);
|
||||
if (ImportContext.Manifest is Game game)
|
||||
{
|
||||
var user = await userService.GetAsync(record.User);
|
||||
|
||||
return await playSessionService.ExistsAsync(ps => (ps.Game.Id == game.Id || ps.Game.Title == game.Title) && ps.Start == record.Start && ps.UserId == user.Id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,77 +1,53 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class PublisherImporter(
|
||||
IMapper mapper,
|
||||
CompanyService companyService,
|
||||
GameService gameService) : BaseImporter<Company, Data.Models.Company>
|
||||
ILogger<PublisherImporter> logger,
|
||||
CompanyService companyService) : BaseImporter<Company>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Company record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(Company record)
|
||||
=> $"Publisher/{record.Name}";
|
||||
|
||||
public override async Task<ImportItemInfo<Company>> GetImportInfoAsync(Company record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.Publisher,
|
||||
Name = record.Name,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Company record) => ImportContext.DataRecord is Data.Models.Company;
|
||||
public override async Task<bool> CanImportAsync(Company record)
|
||||
=> await companyService.ExistsAsync(c => c.Name == record.Name);
|
||||
|
||||
public override async Task<Data.Models.Company> AddAsync(Company record)
|
||||
public override async Task<bool> AddAsync(Company record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var game = ImportContext.DataRecord as Data.Models.Game;
|
||||
|
||||
var company = new Data.Models.Company
|
||||
{
|
||||
PublishedGames = [await gameService.GetAsync(game.Id)],
|
||||
Name = record.Name,
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
};
|
||||
|
||||
company = await companyService.AddAsync(company);
|
||||
await companyService.AddAsync(company);
|
||||
|
||||
return company;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Company>(record, "An unknown error occured while importing publisher", ex);
|
||||
logger.LogError(ex, "Could not add company | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Company> UpdateAsync(Company record)
|
||||
{
|
||||
var existing = await companyService.Include(g => g.PublishedGames).FirstOrDefaultAsync(c => c.Name == record.Name);
|
||||
var game = ImportContext.DataRecord as Data.Models.Game;
|
||||
public override async Task<bool> UpdateAsync(Company record) => true;
|
||||
|
||||
try
|
||||
{
|
||||
if (existing.PublishedGames == null)
|
||||
existing.PublishedGames = new List<Data.Models.Game>();
|
||||
|
||||
if (!existing.PublishedGames.Any(g => g.Id == game.Id))
|
||||
{
|
||||
existing.PublishedGames.Add(await gameService.GetAsync(game.Id));
|
||||
|
||||
existing = await companyService.UpdateAsync(existing);
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Company>(record, "An unknown error occured while importing publisher", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(Company record)
|
||||
{
|
||||
return await companyService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
public override async Task<bool> ExistsAsync(Company record)
|
||||
=> await companyService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
|
|
@ -1,42 +1,49 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class RedistributableImporter(
|
||||
ILogger<RedistributableImporter> logger,
|
||||
IMapper mapper,
|
||||
RedistributableService redistributableService,
|
||||
UserService userService) : BaseImporter<Redistributable, Data.Models.Redistributable>
|
||||
UserService userService) : BaseImporter<Redistributable>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Redistributable record)
|
||||
{
|
||||
return new ImportItemInfo()
|
||||
public override string GetKey(Redistributable record)
|
||||
=> $"{nameof(Redistributable)}/{record.Id}";
|
||||
|
||||
public override async Task<ImportItemInfo<Redistributable>> GetImportInfoAsync(Redistributable record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.Redistributable,
|
||||
Name = record.Name,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Redistributable record) => true;
|
||||
public override async Task<bool> CanImportAsync(Redistributable record) => true;
|
||||
|
||||
public override async Task<Data.Models.Redistributable> AddAsync(Redistributable record)
|
||||
public override async Task<bool> AddAsync(Redistributable record)
|
||||
{
|
||||
var redistributable = mapper.Map<Data.Models.Redistributable>(record);
|
||||
|
||||
try
|
||||
{
|
||||
return await redistributableService.AddAsync(redistributable);
|
||||
await redistributableService.AddAsync(redistributable);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Redistributable>(record,
|
||||
"An unknown error occurred while trying to add redistributable", ex);
|
||||
logger.LogError(ex, "Could not add redistributable | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Redistributable> UpdateAsync(Redistributable record)
|
||||
public override async Task<bool> UpdateAsync(Redistributable record)
|
||||
{
|
||||
var existing = await redistributableService.FirstOrDefaultAsync(r => r.Id == record.Id || r.Name == record.Name);
|
||||
|
||||
|
|
@ -50,19 +57,17 @@ public class RedistributableImporter(
|
|||
existing.UpdatedOn = record.UpdatedOn;
|
||||
existing.UpdatedBy = await userService.GetAsync(record.UpdatedBy);
|
||||
|
||||
existing = await redistributableService.UpdateAsync(existing);
|
||||
await redistributableService.UpdateAsync(existing);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Redistributable>(record,
|
||||
"An unknown error occurred while trying to add redistributable", ex);
|
||||
logger.LogError(ex, "Could not update redistributable | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(Redistributable record)
|
||||
{
|
||||
return await redistributableService.ExistsAsync(r => r.Id == record.Id || r.Name == record.Name);
|
||||
}
|
||||
public override async Task<bool> ExistsAsync(Redistributable record)
|
||||
=> await redistributableService.ExistsAsync(r => r.Id == record.Id || r.Name == record.Name);
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Common;
|
||||
|
||||
|
|
@ -15,23 +15,27 @@ namespace LANCommander.Server.ImportExport.Importers;
|
|||
/// <param name="serviceProvider">Valid service provider for injecting the services we need</param>
|
||||
/// <param name="ImportContext">The context (archive, parent record> of the import</param>
|
||||
public class SaveImporter(
|
||||
IMapper mapper,
|
||||
ILogger<SaveImporter> logger,
|
||||
UserService userService,
|
||||
GameSaveService gameSaveService) : BaseImporter<Save, Data.Models.GameSave>
|
||||
GameSaveService gameSaveService,
|
||||
GameService gameService,
|
||||
GameImporter gameImporter) : BaseImporter<Save>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Save record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(Save record)
|
||||
=> $"{nameof(Save)}/{record.Id}";
|
||||
|
||||
public override async Task<ImportItemInfo<Save>> GetImportInfoAsync(Save record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.Save,
|
||||
Name = $"{record.User} - {record.CreatedOn}",
|
||||
Size = ImportContext.Archive.Entries.FirstOrDefault(e => e.Key == $"Saves/{record.Id}")?.Size ?? 0,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Save record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
public override async Task<bool> CanImportAsync(Save record) => ImportContext.Manifest is Game;
|
||||
|
||||
public override async Task<Data.Models.GameSave> AddAsync(Save record)
|
||||
public override async Task<bool> AddAsync(Save record)
|
||||
{
|
||||
var archiveEntry = ImportContext.Archive.Entries.FirstOrDefault(e => e.Key == $"Saves/{record.Id}");
|
||||
|
||||
|
|
@ -48,12 +52,21 @@ public class SaveImporter(
|
|||
|
||||
try
|
||||
{
|
||||
save = await gameSaveService.AddAsync(new Data.Models.GameSave()
|
||||
var game = ImportContext.Manifest as Game;
|
||||
|
||||
if (game == null)
|
||||
return false;
|
||||
|
||||
if (ImportContext.InQueue(game, gameImporter))
|
||||
return false;
|
||||
|
||||
save = await gameSaveService.AddAsync(new Data.Models.GameSave
|
||||
{
|
||||
CreatedBy = user,
|
||||
User = user,
|
||||
CreatedOn = record.CreatedOn,
|
||||
Game = ImportContext.DataRecord as Data.Models.Game,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
Game = await gameService.GetAsync(game.Id),
|
||||
StorageLocation = await gameSaveService.GetDefaultStorageLocationAsync(),
|
||||
});
|
||||
|
||||
|
|
@ -66,18 +79,19 @@ public class SaveImporter(
|
|||
PreserveFileTime = true,
|
||||
});
|
||||
|
||||
return save;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (save != null)
|
||||
await gameSaveService.DeleteAsync(save);
|
||||
|
||||
throw new ImportSkippedException<Save>(record, "An unknown error occured while importing save file", ex);
|
||||
logger.LogError(ex, "An error occured while adding save | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.GameSave> UpdateAsync(Save record)
|
||||
public override async Task<bool> UpdateAsync(Save record)
|
||||
{
|
||||
var existing = await gameSaveService.FirstOrDefaultAsync(s => s.User.UserName == record.User && s.CreatedOn == record.CreatedOn);
|
||||
|
||||
|
|
@ -98,18 +112,24 @@ public class SaveImporter(
|
|||
PreserveFileTime = true,
|
||||
});
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Save>(record, "An unknown error occured while importing save file", ex);
|
||||
logger.LogError(ex, "Could not update save file {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(Save archive)
|
||||
{
|
||||
return await gameSaveService
|
||||
.Include(s => s.User)
|
||||
.ExistsAsync(s => s.User.UserName == archive.User && s.CreatedOn == archive.CreatedOn && s.GameId == ImportContext.DataRecord.Id);
|
||||
if (ImportContext.Manifest is Game game)
|
||||
{
|
||||
return await gameSaveService
|
||||
.Include(s => s.User)
|
||||
.ExistsAsync(s => s.User.UserName == archive.User && s.CreatedOn == archive.CreatedOn && s.GameId == game.Id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +1,87 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class SavePathImporter(
|
||||
IMapper mapper,
|
||||
SavePathService savePathService) : BaseImporter<SavePath, Data.Models.SavePath>
|
||||
ILogger<SavePathImporter> logger,
|
||||
SavePathService savePathService,
|
||||
GameService gameService,
|
||||
GameImporter gameImporter) : BaseImporter<SavePath>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(SavePath record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(SavePath record)
|
||||
=> $"{nameof(SavePath)}/{record.Id}";
|
||||
|
||||
public override async Task<ImportItemInfo<SavePath>> GetImportInfoAsync(SavePath record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.SavePath,
|
||||
Name = record.Path,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(SavePath record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
public override async Task<bool> CanImportAsync(SavePath record) => ImportContext.Manifest is Game;
|
||||
|
||||
public override async Task<Data.Models.SavePath> AddAsync(SavePath record)
|
||||
public override async Task<bool> AddAsync(SavePath record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var game = ImportContext.Manifest as Game;
|
||||
|
||||
if (game == null)
|
||||
return false;
|
||||
|
||||
if (ImportContext.InQueue(game, gameImporter))
|
||||
return false;
|
||||
|
||||
var savePath = new Data.Models.SavePath
|
||||
{
|
||||
Id = record.Id,
|
||||
Game = ImportContext.DataRecord as Data.Models.Game,
|
||||
Path = record.Path,
|
||||
WorkingDirectory = record.WorkingDirectory,
|
||||
IsRegex = record.IsRegex,
|
||||
Type = record.Type,
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
Game = await gameService.GetAsync(game.Id),
|
||||
};
|
||||
|
||||
savePath = await savePathService.AddAsync(savePath);
|
||||
await savePathService.AddAsync(savePath);
|
||||
|
||||
return savePath;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<SavePath>(record, "An unknown error occured while importing save path", ex);
|
||||
logger.LogError(ex, "Could not add save path | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.SavePath> UpdateAsync(SavePath record)
|
||||
public override async Task<bool> UpdateAsync(SavePath record)
|
||||
{
|
||||
var existing = await savePathService.FirstOrDefaultAsync(p => p.Id == record.Id);
|
||||
|
||||
try
|
||||
{
|
||||
existing.Game = ImportContext.DataRecord as Data.Models.Game;
|
||||
existing.Path = record.Path;
|
||||
existing.WorkingDirectory = record.WorkingDirectory;
|
||||
existing.IsRegex = record.IsRegex;
|
||||
existing.Type = record.Type;
|
||||
|
||||
existing = await savePathService.UpdateAsync(existing);
|
||||
await savePathService.UpdateAsync(existing);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<SavePath>(record, "An unknown error occured while importing save path", ex);
|
||||
logger.LogError(ex, "Could not update save path | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(SavePath record)
|
||||
{
|
||||
return await savePathService.ExistsAsync(p => p.Id == record.Id);
|
||||
}
|
||||
public override async Task<bool> ExistsAsync(SavePath record)
|
||||
=> await savePathService.ExistsAsync(p => p.Id == record.Id);
|
||||
}
|
||||
|
|
@ -1,34 +1,42 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class ScriptImporter(
|
||||
IMapper mapper,
|
||||
ScriptService scriptService) : BaseImporter<Script, Data.Models.Script>
|
||||
ILogger<ScriptImporter> logger,
|
||||
ScriptService scriptService,
|
||||
GameService gameService,
|
||||
RedistributableService redistributableService,
|
||||
ServerService serverService,
|
||||
GameImporter gameImporter,
|
||||
RedistributableImporter redistributableImporter,
|
||||
ServerImporter serverImporter) : BaseImporter<Script>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Script record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(Script record)
|
||||
=> $"{nameof(Script)}/{record.Id}";
|
||||
|
||||
public override async Task<ImportItemInfo<Script>> GetImportInfoAsync(Script record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.Script,
|
||||
Name = record.Name,
|
||||
Size = ImportContext.Archive.Entries.FirstOrDefault(e => e.Key == $"Scripts/{record.Id}")?.Size ?? 0,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Script record) =>
|
||||
ImportContext.DataRecord is Data.Models.Game
|
||||
public override async Task<bool> CanImportAsync(Script record) =>
|
||||
ImportContext.Manifest is Game
|
||||
||
|
||||
ImportContext.DataRecord is Data.Models.Redistributable
|
||||
ImportContext.Manifest is Redistributable
|
||||
||
|
||||
ImportContext.DataRecord is Data.Models.Server;
|
||||
ImportContext.Manifest is SDK.Models.Manifest.Server;
|
||||
|
||||
public override async Task<Data.Models.Script> AddAsync(Script record)
|
||||
public override async Task<bool> AddAsync(Script record)
|
||||
{
|
||||
var archiveEntry = ImportContext.Archive.Entries.FirstOrDefault(e => e.Key == $"Scripts/{record.Id}");
|
||||
|
||||
|
|
@ -43,50 +51,57 @@ public class ScriptImporter(
|
|||
var newScript = new Data.Models.Script
|
||||
{
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
Name = record.Name,
|
||||
Description = record.Description,
|
||||
RequiresAdmin = record.RequiresAdmin,
|
||||
Type = record.Type,
|
||||
};
|
||||
|
||||
if (ImportContext.DataRecord is Data.Models.Game game)
|
||||
newScript.Game = game;
|
||||
else if (ImportContext.DataRecord is Data.Models.Redistributable redistributable)
|
||||
newScript.Redistributable = redistributable;
|
||||
else if (ImportContext.DataRecord is Data.Models.Server server)
|
||||
newScript.Server = server;
|
||||
if (ImportContext.Manifest is Game game)
|
||||
newScript.Game = await gameService.GetAsync(game.Id);
|
||||
else if (ImportContext.Manifest is Redistributable redistributable)
|
||||
newScript.Redistributable = await redistributableService.GetAsync(redistributable.Id);
|
||||
else if (ImportContext.Manifest is SDK.Models.Manifest.Server server)
|
||||
newScript.Server = await serverService.GetAsync(server.Id);
|
||||
else
|
||||
return false;
|
||||
|
||||
using (var streamReader = new StreamReader(archiveEntry.OpenEntryStream()))
|
||||
{
|
||||
newScript.Contents = await streamReader.ReadToEndAsync();
|
||||
}
|
||||
|
||||
script = await scriptService.AddAsync(newScript);
|
||||
await scriptService.AddAsync(newScript);
|
||||
|
||||
return script;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (script != null)
|
||||
await scriptService.DeleteAsync(script);
|
||||
|
||||
throw new ImportSkippedException<Script>(record, "An unknown error occured while importing script", ex);
|
||||
logger.LogError(ex, "Failed to add script | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Script> UpdateAsync(Script record)
|
||||
public override async Task<bool> UpdateAsync(Script record)
|
||||
{
|
||||
var archiveEntry = ImportContext.Archive.Entries.FirstOrDefault(e => e.Key == $"Scripts/{record.Id}");
|
||||
|
||||
Data.Models.Script existing = null;
|
||||
|
||||
if (ImportContext.DataRecord is Data.Models.Game game)
|
||||
if (ImportContext.Manifest is Game game)
|
||||
existing = await scriptService.FirstOrDefaultAsync(s => s.Type == record.Type && s.Name == record.Name && s.GameId == game.Id);
|
||||
else if (ImportContext.DataRecord is Data.Models.Redistributable redistributable)
|
||||
else if (ImportContext.Manifest is Redistributable redistributable)
|
||||
existing = await scriptService.FirstOrDefaultAsync(s => s.Type == record.Type && s.Name == record.Name && s.RedistributableId == redistributable.Id);
|
||||
else if (ImportContext.DataRecord is Data.Models.Server server)
|
||||
else if (ImportContext.Manifest is SDK.Models.Manifest.Server server)
|
||||
existing = await scriptService.FirstOrDefaultAsync(s => s.Type == record.Type && s.Name == record.Name && s.ServerId == server.Id);
|
||||
|
||||
if (existing == null)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
existing.CreatedOn = record.CreatedOn;
|
||||
|
|
@ -100,25 +115,26 @@ public class ScriptImporter(
|
|||
existing.Contents = await streamReader.ReadToEndAsync();
|
||||
}
|
||||
|
||||
existing = await scriptService.UpdateAsync(existing);
|
||||
await scriptService.UpdateAsync(existing);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Script>(record, "An unknown error occured while importing script", ex);
|
||||
logger.LogError(ex, "Failed to update script | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(Script record)
|
||||
{
|
||||
if (ImportContext.DataRecord is Data.Models.Game game)
|
||||
if (ImportContext.Manifest is Game game)
|
||||
return await scriptService.ExistsAsync(s => s.Type == record.Type && s.Name == record.Name && s.GameId == game.Id);
|
||||
|
||||
if (ImportContext.DataRecord is Data.Models.Redistributable redistributable)
|
||||
if (ImportContext.Manifest is Redistributable redistributable)
|
||||
return await scriptService.ExistsAsync(s => s.Type == record.Type && s.Name == record.Name && s.RedistributableId == redistributable.Id);
|
||||
|
||||
if (ImportContext.DataRecord is Data.Models.Server server)
|
||||
if (ImportContext.Manifest is SDK.Models.Manifest.Server server)
|
||||
return await scriptService.ExistsAsync(s => s.Type == record.Type && s.Name == record.Name && s.ServerId == server.Id);
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,31 +1,42 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class ServerConsoleImporter(
|
||||
IMapper mapper,
|
||||
ServerConsoleService serverConsoleService) : BaseImporter<ServerConsole, Data.Models.ServerConsole>
|
||||
ILogger<ServerConsoleImporter> logger,
|
||||
ServerConsoleService serverConsoleService,
|
||||
ServerService serverService,
|
||||
ServerImporter serverImporter) : BaseImporter<ServerConsole>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(ServerConsole record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(ServerConsole record)
|
||||
=> $"{nameof(ServerConsole)}/{record.Name}";
|
||||
|
||||
public override async Task<ImportItemInfo<ServerConsole>> GetImportInfoAsync(ServerConsole record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.ServerConsole,
|
||||
Name = record.Name,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(ServerConsole record) => ImportContext.DataRecord is Data.Models.ServerConsole;
|
||||
public override async Task<bool> CanImportAsync(ServerConsole record) => ImportContext.Manifest is SDK.Models.Manifest.Server;
|
||||
|
||||
public override async Task<Data.Models.ServerConsole> AddAsync(ServerConsole record)
|
||||
public override async Task<bool> AddAsync(ServerConsole record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var server = ImportContext.Manifest as SDK.Models.Manifest.Server;
|
||||
|
||||
if (server == null)
|
||||
return false;
|
||||
|
||||
if (ImportContext.InQueue(server, serverImporter))
|
||||
return false;
|
||||
|
||||
var serverConsole = new Data.Models.ServerConsole
|
||||
{
|
||||
Name = record.Name,
|
||||
|
|
@ -33,47 +44,57 @@ public class ServerConsoleImporter(
|
|||
Path = record.Path,
|
||||
Host = record.Host,
|
||||
Port = record.Port,
|
||||
Server = ImportContext.DataRecord as Data.Models.Server,
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
Server = await serverService.GetAsync(server.Id),
|
||||
};
|
||||
|
||||
serverConsole = await serverConsoleService.AddAsync(serverConsole);
|
||||
await serverConsoleService.AddAsync(serverConsole);
|
||||
|
||||
return serverConsole;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<ServerConsole>(record, "An unknown error occured while importing server console", ex);
|
||||
logger.LogError(ex, "Could not add server console | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.ServerConsole> UpdateAsync(ServerConsole record)
|
||||
public override async Task<bool> UpdateAsync(ServerConsole record)
|
||||
{
|
||||
var existing = await serverConsoleService
|
||||
.Include(c => c.Server)
|
||||
.FirstOrDefaultAsync(c => c.Name == record.Name && c.Server.Name == (ImportContext.DataRecord as Data.Models.Server).Name);
|
||||
|
||||
try
|
||||
{
|
||||
var server = ImportContext.Manifest as SDK.Models.Manifest.Server;
|
||||
|
||||
if (server == null)
|
||||
return false;
|
||||
|
||||
var existing = await serverConsoleService.FirstOrDefaultAsync(c => c.Name == record.Name && c.ServerId == server.Id);
|
||||
|
||||
existing.Name = record.Name;
|
||||
existing.Type = record.Type;
|
||||
existing.Path = record.Path;
|
||||
existing.Host = record.Host;
|
||||
existing.Port = record.Port;
|
||||
|
||||
existing = await serverConsoleService.UpdateAsync(existing);
|
||||
await serverConsoleService.UpdateAsync(existing);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<ServerConsole>(record, "An unknown error occured while importing server console", ex);
|
||||
logger.LogError(ex, "Could not update server console | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(ServerConsole record)
|
||||
{
|
||||
return await serverConsoleService
|
||||
.Include(c => c.Server)
|
||||
.ExistsAsync(c => c.Name == record.Name && c.Server.Name == (ImportContext.DataRecord as Data.Models.Server).Name);
|
||||
if (ImportContext.Manifest is SDK.Models.Manifest.Server server)
|
||||
return await serverConsoleService
|
||||
.Include(c => c.Server)
|
||||
.ExistsAsync(c => c.Name == record.Name && c.ServerId == server.Id);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +1,95 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class ServerHttpPathImporter(
|
||||
IMapper mapper,
|
||||
ILogger<ServerHttpPathImporter> logger,
|
||||
ServerHttpPathService serverHttpPathService,
|
||||
ServerService serverService) : BaseImporter<ServerHttpPath, Data.Models.ServerHttpPath>
|
||||
ServerService serverService,
|
||||
ServerImporter serverImporter) : BaseImporter<ServerHttpPath>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(ServerHttpPath record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(ServerHttpPath record)
|
||||
=> $"{nameof(ServerHttpPath)}/{record.LocalPath}";
|
||||
|
||||
public override async Task<ImportItemInfo<ServerHttpPath>> GetImportInfoAsync(ServerHttpPath record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.ServerHttpPath,
|
||||
Name = record.Path,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(ServerHttpPath record) => ImportContext.DataRecord is Data.Models.Server;
|
||||
public override async Task<bool> CanImportAsync(ServerHttpPath record) => ImportContext.Manifest is SDK.Models.Manifest.Server;
|
||||
|
||||
public override async Task<Data.Models.ServerHttpPath> AddAsync(ServerHttpPath record)
|
||||
public override async Task<bool> AddAsync(ServerHttpPath record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var server = ImportContext.Manifest as SDK.Models.Manifest.Server;
|
||||
|
||||
if (server == null)
|
||||
return false;
|
||||
|
||||
if (ImportContext.InQueue(server, serverImporter))
|
||||
return false;
|
||||
|
||||
var serverHttpPath = new Data.Models.ServerHttpPath
|
||||
{
|
||||
LocalPath = record.LocalPath,
|
||||
Path = record.Path,
|
||||
Server = await serverService.FirstOrDefaultAsync(s => s.Name == (ImportContext.DataRecord as Data.Models.Server).Name),
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
Server = await serverService.GetAsync(server.Id),
|
||||
};
|
||||
|
||||
serverHttpPath = await serverHttpPathService.AddAsync(serverHttpPath);
|
||||
await serverHttpPathService.AddAsync(serverHttpPath);
|
||||
|
||||
return serverHttpPath;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<ServerHttpPath>(record, "An unknown error occured while importing server console", ex);
|
||||
logger.LogError(ex, "Could not add server HTTP path | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.ServerHttpPath> UpdateAsync(ServerHttpPath record)
|
||||
public override async Task<bool> UpdateAsync(ServerHttpPath record)
|
||||
{
|
||||
var existing = await serverHttpPathService.FirstOrDefaultAsync(p => p.Path == record.Path);
|
||||
|
||||
try
|
||||
{
|
||||
var server = ImportContext.Manifest as SDK.Models.Manifest.Server;
|
||||
|
||||
if (server == null)
|
||||
return false;
|
||||
|
||||
existing.LocalPath = record.LocalPath;
|
||||
existing.Path = record.Path;
|
||||
existing.Server =
|
||||
await serverService.FirstOrDefaultAsync(
|
||||
s => s.Name == (ImportContext.DataRecord as Data.Models.Server).Name);
|
||||
existing.Server = await serverService.GetAsync(server.Id);
|
||||
|
||||
existing = await serverHttpPathService.UpdateAsync(existing);
|
||||
await serverHttpPathService.UpdateAsync(existing);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<ServerHttpPath>(record, "An unknown error occured while importing server console", ex);
|
||||
logger.LogError(ex, "Could not update server HTTP path | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(ServerHttpPath record)
|
||||
{
|
||||
return await serverHttpPathService
|
||||
.Include(p => p.Server)
|
||||
.ExistsAsync(p => p.Path == record.Path && p.Server.Name == (ImportContext.DataRecord as Data.Models.Server).Name);
|
||||
if (ImportContext.Manifest is SDK.Models.Manifest.Server server)
|
||||
return await serverHttpPathService
|
||||
.Include(p => p.Server)
|
||||
.ExistsAsync(p => p.Path == record.Path && p.ServerId == server.Id);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +1,57 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class ServerImporter(
|
||||
ILogger<ServerImporter> logger,
|
||||
IMapper mapper,
|
||||
ServerService serverService,
|
||||
GameService gameService,
|
||||
UserService userService) : BaseImporter<SDK.Models.Manifest.Server, Data.Models.Server>
|
||||
UserService userService) : BaseImporter<SDK.Models.Manifest.Server>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(SDK.Models.Manifest.Server record)
|
||||
public override string GetKey(SDK.Models.Manifest.Server record)
|
||||
=> $"{nameof(SDK.Models.Manifest.Server)}/{record.Id}";
|
||||
|
||||
public override async Task<ImportItemInfo<SDK.Models.Manifest.Server>> GetImportInfoAsync(SDK.Models.Manifest.Server record)
|
||||
{
|
||||
var fileEntries = ImportContext.Archive.Entries.Where(e => e.Key.StartsWith("Files/"));
|
||||
|
||||
return new ImportItemInfo
|
||||
return new ImportItemInfo<SDK.Models.Manifest.Server>
|
||||
{
|
||||
Type = ImportExportRecordType.Server,
|
||||
Name = record.Name,
|
||||
Size = fileEntries.Sum(f => f.Size),
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(SDK.Models.Manifest.Server record) => true;
|
||||
public override async Task<bool> CanImportAsync(SDK.Models.Manifest.Server record) => true;
|
||||
|
||||
public override async Task<Data.Models.Server> AddAsync(SDK.Models.Manifest.Server record)
|
||||
public override async Task<bool> AddAsync(SDK.Models.Manifest.Server record)
|
||||
{
|
||||
var server = mapper.Map<Data.Models.Server>(record);
|
||||
|
||||
try
|
||||
{
|
||||
await ExtractFiles(server);
|
||||
|
||||
return await serverService.AddAsync(server);
|
||||
await serverService.AddAsync(server);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<SDK.Models.Manifest.Server>(record, "An unknown error occured while trying to add server", ex);
|
||||
logger.LogError(ex, "Could not add server");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Server> UpdateAsync(SDK.Models.Manifest.Server record)
|
||||
public override async Task<bool> UpdateAsync(SDK.Models.Manifest.Server record)
|
||||
{
|
||||
var existing = await serverService.FirstOrDefaultAsync(s => s.Id == record.Id || s.Name == record.Name);
|
||||
|
||||
|
|
@ -71,11 +80,12 @@ public class ServerImporter(
|
|||
|
||||
await ExtractFiles(existing);
|
||||
|
||||
return existing;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<SDK.Models.Manifest.Server>(record, "An unknown error occurred while trying to update server", ex);
|
||||
logger.LogError(ex, "Could not update server");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,75 +1,53 @@
|
|||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models.Manifest;
|
||||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public class TagImporter(
|
||||
IMapper mapper,
|
||||
TagService tagService,
|
||||
GameService gameService) : BaseImporter<Tag, Data.Models.Tag>
|
||||
ILogger<TagImporter> logger,
|
||||
TagService tagService) : BaseImporter<Tag>
|
||||
{
|
||||
public override async Task<ImportItemInfo> GetImportInfoAsync(Tag record)
|
||||
{
|
||||
return new ImportItemInfo
|
||||
public override string GetKey(Tag record)
|
||||
=> $"{nameof(Tag)}/{record.Name}";
|
||||
|
||||
public override async Task<ImportItemInfo<Tag>> GetImportInfoAsync(Tag record)
|
||||
=> new()
|
||||
{
|
||||
Type = ImportExportRecordType.Tag,
|
||||
Name = record.Name,
|
||||
Record = record,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool CanImport(Tag record) => ImportContext.DataRecord is Data.Models.Game;
|
||||
public override async Task<bool> CanImportAsync(Tag record)
|
||||
=> await tagService.ExistsAsync(t => t.Name == record.Name);
|
||||
|
||||
public override async Task<Data.Models.Tag> AddAsync(Tag record)
|
||||
public override async Task<bool> AddAsync(Tag record)
|
||||
{
|
||||
try
|
||||
{
|
||||
var tag = new Data.Models.Tag
|
||||
{
|
||||
Games = new List<Data.Models.Game>() { ImportContext.DataRecord as Data.Models.Game },
|
||||
Name = record.Name,
|
||||
CreatedOn = record.CreatedOn,
|
||||
UpdatedOn = record.UpdatedOn,
|
||||
};
|
||||
|
||||
tag = await tagService.AddAsync(tag);
|
||||
await tagService.AddAsync(tag);
|
||||
|
||||
return tag;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Tag>(record, "An unknown error occured while importing tag", ex);
|
||||
logger.LogError(ex, "Could not add tag | {Key}", GetKey(record));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<Data.Models.Tag> UpdateAsync(Tag record)
|
||||
{
|
||||
var existing = await tagService.Include(t => t.Games).FirstOrDefaultAsync(c => c.Name == record.Name);
|
||||
var game = ImportContext.DataRecord as Data.Models.Game;
|
||||
|
||||
try
|
||||
{
|
||||
if (existing.Games == null)
|
||||
existing.Games = new List<Data.Models.Game>();
|
||||
public override async Task<bool> UpdateAsync(Tag record) => true;
|
||||
|
||||
if (!existing.Games.Any(g => g.Id == game.Id))
|
||||
{
|
||||
existing.Games.Add(await gameService.GetAsync(game.Id));
|
||||
|
||||
existing = await tagService.UpdateAsync(existing);
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ImportSkippedException<Tag>(record, "An unknown error occured while importing tag", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> ExistsAsync(Tag record)
|
||||
{
|
||||
return await tagService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
public override async Task<bool> ExistsAsync(Tag record)
|
||||
=> await tagService.ExistsAsync(c => c.Name == record.Name);
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
using LANCommander.Server.ImportExport.Exceptions;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Importers;
|
||||
|
||||
public abstract class BaseImporter<TRecord, TEntity> : IImporter<TRecord, TEntity>
|
||||
public abstract class BaseImporter<TRecord> : IImporter<TRecord> where TRecord : class
|
||||
{
|
||||
protected ImportContext ImportContext { get; private set; }
|
||||
|
||||
|
|
@ -10,10 +11,28 @@ public abstract class BaseImporter<TRecord, TEntity> : IImporter<TRecord, TEntit
|
|||
{
|
||||
ImportContext = context;
|
||||
}
|
||||
|
||||
public async Task<bool> ImportAsync(IImportItemInfo importItem)
|
||||
{
|
||||
if (importItem is ImportItemInfo<TRecord> importItemInfo)
|
||||
{
|
||||
if (await ExistsAsync(importItemInfo.Record))
|
||||
{
|
||||
importItem.Processed = true;
|
||||
return await UpdateAsync(importItemInfo.Record);
|
||||
}
|
||||
|
||||
importItem.Processed = true;
|
||||
return await AddAsync(importItemInfo.Record);
|
||||
}
|
||||
|
||||
throw new ImportSkippedException<TRecord>(null, "Import item record is not supported by this importer.");
|
||||
}
|
||||
|
||||
public abstract Task<ImportItemInfo> GetImportInfoAsync(TRecord record);
|
||||
public abstract bool CanImport(TRecord record);
|
||||
public abstract Task<TEntity> AddAsync(TRecord record);
|
||||
public abstract Task<TEntity> UpdateAsync(TRecord record);
|
||||
public abstract string GetKey(TRecord record);
|
||||
public abstract Task<ImportItemInfo<TRecord>> GetImportInfoAsync(TRecord record);
|
||||
public abstract Task<bool> CanImportAsync(TRecord record);
|
||||
public abstract Task<bool> AddAsync(TRecord record);
|
||||
public abstract Task<bool> UpdateAsync(TRecord record);
|
||||
public abstract Task<bool> ExistsAsync(TRecord record);
|
||||
}
|
||||
|
|
@ -8,12 +8,13 @@ namespace LANCommander.Server.ImportExport.Importers;
|
|||
/// this needs to exist for each type.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRecord"></typeparam>
|
||||
public interface IImporter<TRecord, TEntity>
|
||||
public interface IImporter<TRecord> where TRecord : class
|
||||
{
|
||||
void UseContext(ImportContext context);
|
||||
Task<ImportItemInfo> GetImportInfoAsync(TRecord record);
|
||||
bool CanImport(TRecord record);
|
||||
Task<TEntity> AddAsync(TRecord record);
|
||||
Task<TEntity> UpdateAsync(TRecord record);
|
||||
Task<ImportItemInfo<TRecord>> GetImportInfoAsync(TRecord record);
|
||||
Task<bool> CanImportAsync(TRecord record);
|
||||
Task<bool> ImportAsync(IImportItemInfo importItem);
|
||||
Task<bool> AddAsync(TRecord record);
|
||||
Task<bool> UpdateAsync(TRecord record);
|
||||
Task<bool> ExistsAsync(TRecord record);
|
||||
}
|
||||
12
LANCommander.Server.ImportExport/Models/IImportItemInfo.cs
Normal file
12
LANCommander.Server.ImportExport/Models/IImportItemInfo.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using LANCommander.SDK.Enums;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Models;
|
||||
|
||||
public interface IImportItemInfo
|
||||
{
|
||||
string Key { get; set; }
|
||||
ImportExportRecordType Type { get; set; }
|
||||
string Name { get; set; }
|
||||
bool Processed { get; set; }
|
||||
long Size { get; set; }
|
||||
}
|
||||
|
|
@ -2,10 +2,12 @@ using LANCommander.SDK.Enums;
|
|||
|
||||
namespace LANCommander.Server.ImportExport.Models;
|
||||
|
||||
public class ImportItemInfo
|
||||
public class ImportItemInfo<T> : IImportItemInfo where T : class
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
public string Key { get; set; }
|
||||
public ImportExportRecordType Type { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool Processed { get; set; }
|
||||
public long Size { get; set; }
|
||||
public T Record { get; set; }
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ namespace LANCommander.Server.ImportExport.Models;
|
|||
|
||||
public class ImportQueueItem
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Key { get; set; }
|
||||
public ImportExportRecordType Type { get; set; }
|
||||
public object Record { get; set; }
|
||||
public bool Processed { get; set; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
namespace LANCommander.Server.ImportExport.Models;
|
||||
|
||||
public class ImportStatusUpdate
|
||||
{
|
||||
public int Index { get; set; }
|
||||
public int Total { get; set; }
|
||||
public string? Error { get; set; }
|
||||
public IImportItemInfo? CurrentItem { get; set; }
|
||||
}
|
||||
|
|
@ -1,23 +1,46 @@
|
|||
using LANCommander.Server.ImportExport.Importers;
|
||||
using LANCommander.Server.ImportExport.Models;
|
||||
|
||||
namespace LANCommander.Server.ImportExport.Services;
|
||||
|
||||
public class ImportService : IDisposable
|
||||
{
|
||||
private Dictionary<Guid, ImportContext> ImportContexts = new();
|
||||
public EventHandler<ImportStatusUpdate> OnImportStarted;
|
||||
public EventHandler<ImportStatusUpdate> OnImportComplete;
|
||||
public EventHandler<ImportStatusUpdate> OnImportStatusUpdate;
|
||||
public EventHandler<ImportStatusUpdate> OnImportError;
|
||||
|
||||
private Dictionary<Guid, ImportContext> _importContexts = new();
|
||||
|
||||
public Guid EnqueueContext(ImportContext context)
|
||||
public Guid AddContext(ImportContext context)
|
||||
{
|
||||
var id = Guid.NewGuid();
|
||||
|
||||
ImportContexts.Add(id, context);
|
||||
context.SetId(id);
|
||||
|
||||
_importContexts.Add(id, context);
|
||||
|
||||
context.OnImportStarted += OnImportStarted;
|
||||
context.OnImportComplete += OnImportComplete;
|
||||
context.OnImportStatusUpdate += OnImportStatusUpdate;
|
||||
context.OnImportError += OnImportError;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
public void RemoveContext(Guid id)
|
||||
{
|
||||
_importContexts.Remove(id);
|
||||
}
|
||||
|
||||
public IEnumerable<ImportContext> GetContexts()
|
||||
{
|
||||
return _importContexts.Values;
|
||||
}
|
||||
|
||||
public ImportContext GetContext(Guid id)
|
||||
{
|
||||
if (ImportContexts.TryGetValue(id, out var context))
|
||||
if (_importContexts.TryGetValue(id, out var context))
|
||||
return context;
|
||||
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using LANCommander.Server.Services.Models;
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using AutoMapper;
|
||||
using AutoMapper.QueryableExtensions;
|
||||
using LANCommander.Server.Services.Abstractions;
|
||||
|
|
@ -378,6 +379,88 @@ namespace LANCommander.Server.Services
|
|||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task SyncRelatedCollectionAsync<T, TChild, U>(
|
||||
T entity,
|
||||
Expression<Func<T, ICollection<TChild>>> navigationProperty,
|
||||
IEnumerable<U> records,
|
||||
Func<U, Expression<Func<TChild, bool>>> matchExpression,
|
||||
Action<TChild, U> updateAction) where TChild : class where T : class
|
||||
{
|
||||
using var context = await dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var entry = context.Entry(entity);
|
||||
|
||||
var enumerableExpr = Expression.Lambda<Func<T, IEnumerable<TChild>>>(
|
||||
navigationProperty.Body,
|
||||
navigationProperty.Parameters);
|
||||
|
||||
var collectionEntry = entry.Collection(enumerableExpr);
|
||||
|
||||
if (!collectionEntry.IsLoaded)
|
||||
await collectionEntry.LoadAsync();
|
||||
|
||||
var collection = navigationProperty.Compile().Invoke(entity);
|
||||
|
||||
if (collection == null)
|
||||
{
|
||||
collection = new List<TChild>();
|
||||
|
||||
if (navigationProperty.Body is not MemberExpression memberExpression ||
|
||||
memberExpression.Member is not PropertyInfo propertyInfo)
|
||||
throw new InvalidOperationException($"Navigation expression '{navigationProperty}' must point to a property.");
|
||||
|
||||
propertyInfo.SetValue(entity, collection);
|
||||
}
|
||||
|
||||
var matchedChildren = new HashSet<TChild>();
|
||||
|
||||
foreach (var record in records)
|
||||
{
|
||||
var matchPredicate = matchExpression(record);
|
||||
var existingChild = collection.FirstOrDefault(matchPredicate.Compile());
|
||||
|
||||
if (existingChild == null)
|
||||
{
|
||||
existingChild = await context.Set<TChild>()
|
||||
.FirstOrDefaultAsync(matchPredicate);
|
||||
}
|
||||
|
||||
if (existingChild != null)
|
||||
{
|
||||
if (!collection.Contains(existingChild))
|
||||
collection.Add(existingChild);
|
||||
|
||||
updateAction(existingChild, record);
|
||||
matchedChildren.Add(existingChild);
|
||||
}
|
||||
else
|
||||
{
|
||||
var newChild = Activator.CreateInstance<TChild>();
|
||||
|
||||
updateAction(newChild, record);
|
||||
collection.Add(newChild);
|
||||
matchedChildren.Add(newChild);
|
||||
}
|
||||
}
|
||||
|
||||
var toDelete = collection.Where(child => !matchedChildren.Contains(child));
|
||||
|
||||
foreach (var child in toDelete)
|
||||
{
|
||||
collection.Remove(child);
|
||||
context.Remove(child);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<User?> GetCurrentUserAsync(DatabaseContext context)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue