public async Task AddColorListAsync(ICollection <AvatarColor> colorList) { VerifyManagementPermission(); var userId = GetClaimId(ClaimType.UserId); foreach (var color in colorList) { await _avatarColorRepository.AddAsync(userId, color); } await _avatarColorRepository.SaveAsync(); }
public async Task <JobStatus> ImportAvatarsAsync(int jobId, CancellationToken token, IProgress <JobStatus> progress = null) { var requestingUser = GetClaimId(ClaimType.UserId); if (HasPermission(Permission.ManageAvatars)) { var sw = Stopwatch.StartNew(); var job = await _jobRepository.GetByIdAsync(jobId); var jobDetails = JsonConvert .DeserializeObject <JobDetailsAvatarImport>(job.SerializedParameters); string assetPath = jobDetails.AssetPath; token.Register(() => { _logger.LogWarning("Import avatars for user {User} was cancelled after {Elapsed} ms.", requestingUser, sw?.ElapsedMilliseconds); }); var jsonPath = Path.Combine(assetPath, "default avatars.json"); if (!File.Exists(jsonPath)) { _logger.LogError("Unable to find file {DefaultAvatarsJson}", jsonPath); return(new JobStatus { PercentComplete = 0, Complete = true, Error = true, Status = $"Unable to find the default avatars.json file in {assetPath}." }); } IEnumerable <AvatarLayer> avatarList; using (StreamReader file = File.OpenText(jsonPath)) { var jsonString = await file.ReadToEndAsync(); avatarList = JsonConvert.DeserializeObject <IEnumerable <AvatarLayer> >(jsonString); } var layerCount = avatarList.Count(); _logger.LogInformation("Found {Count} AvatarLayer objects in avatar JSON file", layerCount); // Layers + background/bundles var processingCount = layerCount + 1; var processedCount = 0; var bundleJsonPath = Path.Combine(assetPath, "default bundles.json"); var bundleJsonExists = File.Exists(bundleJsonPath); if (bundleJsonExists) { processingCount++; } var time = _dateTimeProvider.Now; int totalFilesCopied = 0; var siteId = GetCurrentSiteId(); foreach (var layer in avatarList) { progress?.Report(new JobStatus { PercentComplete = processedCount * 100 / processingCount, Status = $"Processing layer {layer.Name}", Error = false }); var colors = layer.AvatarColors; var items = layer.AvatarItems; layer.AvatarColors = null; layer.AvatarItems = null; var addedLayer = await AddLayerAsync(layer); var layerAssetPath = Path.Combine(assetPath, layer.Name); var destinationRoot = Path.Combine($"site{siteId}", "avatars", $"layer{addedLayer.Id}"); var destinationPath = _pathResolver.ResolveContentFilePath(destinationRoot); if (!Directory.Exists(destinationPath)) { Directory.CreateDirectory(destinationPath); } addedLayer.Icon = Path.Combine(destinationRoot, "icon.png"); File.Copy(Path.Combine(layerAssetPath, "icon.png"), Path.Combine(destinationPath, "icon.png")); await UpdateLayerAsync(addedLayer); int lastUpdateSent; if (colors != null) { progress?.Report(new JobStatus { PercentComplete = processedCount * 100 / processingCount, Status = $"Processing layer {layer.Name}: Adding colors...", Error = false }); lastUpdateSent = (int)sw.Elapsed.TotalSeconds; var colorCount = colors.Count; var currentColor = 1; foreach (var color in colors) { var secondsFromLastUpdate = (int)sw.Elapsed.TotalSeconds - lastUpdateSent; if (secondsFromLastUpdate >= 5) { progress.Report(new JobStatus { PercentComplete = processedCount * 100 / processingCount, Status = $"Processing layer {layer.Name}: Adding colors ({currentColor}/{colorCount})...", Error = false }); lastUpdateSent = (int)sw.Elapsed.TotalSeconds; } color.AvatarLayerId = addedLayer.Id; color.CreatedAt = time; color.CreatedBy = requestingUser; await _avatarColorRepository.AddAsync(requestingUser, color); currentColor++; } await _avatarColorRepository.SaveAsync(); colors = await GetColorsByLayerAsync(addedLayer.Id); } progress?.Report(new JobStatus { PercentComplete = processedCount * 100 / processingCount, Status = $"Processing layer {layer.Name}: Adding items...", Error = false }); lastUpdateSent = (int)sw.Elapsed.TotalSeconds; var itemCount = items.Count; var currentItem = 1; foreach (var item in items) { var secondsFromLastUpdate = (int)sw.Elapsed.TotalSeconds - lastUpdateSent; if (secondsFromLastUpdate >= 5) { progress?.Report(new JobStatus { PercentComplete = processedCount * 100 / processingCount, Status = $"Processing layer {layer.Name}: Adding items ({currentItem}/{itemCount})...", Error = false }); lastUpdateSent = (int)sw.Elapsed.TotalSeconds; } item.AvatarLayerId = addedLayer.Id; item.CreatedAt = time; item.CreatedBy = requestingUser; await _avatarItemRepository.AddAsync(requestingUser, item); currentItem++; } await _avatarItemRepository.SaveAsync(); items = await GetItemsByLayerAsync(addedLayer.Id); _logger.LogInformation("Processing {Count} items in {LayerName}", items.Count, layer.Name); progress?.Report(new JobStatus { PercentComplete = processedCount * 100 / processingCount, Status = $"Processing layer {layer.Name}: Copying files...", Error = false }); lastUpdateSent = (int)sw.Elapsed.TotalSeconds; var elementCount = items.Count; if (colors?.Count > 0) { elementCount *= colors.Count; } var currentElement = 1; foreach (var item in items) { var secondsFromLastUpdate = (int)sw.Elapsed.TotalSeconds - lastUpdateSent; if (secondsFromLastUpdate >= 5) { progress?.Report(new JobStatus { PercentComplete = processedCount * 100 / processingCount, Status = $"Processing layer {layer.Name}: Copying files ({currentElement}/{elementCount})...", Error = false }); lastUpdateSent = (int)sw.Elapsed.TotalSeconds; } if (currentElement % 500 == 0) { await _avatarElementRepository.SaveAsync(); } var itemAssetPath = Path.Combine(layerAssetPath, item.Name); var itemRoot = Path.Combine(destinationRoot, $"item{item.Id}"); var itemPath = Path.Combine(destinationPath, $"item{item.Id}"); if (!Directory.Exists(itemPath)) { Directory.CreateDirectory(itemPath); } item.Thumbnail = Path.Combine(itemRoot, "thumbnail.jpg"); File.Copy(Path.Combine(itemAssetPath, "thumbnail.jpg"), Path.Combine(itemPath, "thumbnail.jpg")); await _avatarItemRepository.UpdateAsync(requestingUser, item); if (colors != null) { foreach (var color in colors) { var element = new AvatarElement { AvatarItemId = item.Id, AvatarColorId = color.Id, Filename = Path.Combine(itemRoot, $"item_{color.Id}.png") }; await _avatarElementRepository.AddAsync(requestingUser, element); File.Copy( Path.Combine(itemAssetPath, $"{color.Color}.png"), Path.Combine(itemPath, $"item_{color.Id}.png")); currentElement++; } } else { var element = new AvatarElement { AvatarItemId = item.Id, Filename = Path.Combine(itemRoot, "item.png") }; await _avatarElementRepository.AddAsync(requestingUser, element); File.Copy(Path.Combine(itemAssetPath, "item.png"), Path.Combine(itemPath, "item.png")); currentElement++; } } await _avatarElementRepository.SaveAsync(); totalFilesCopied += elementCount; _logger.LogInformation("Copied {Count} items for {LayerName}", elementCount, layer.Name); processedCount++; } progress?.Report(new JobStatus { PercentComplete = processedCount * 100 / processingCount, Status = "Finishing avatar import...", Error = false }); var backgroundRoot = Path.Combine($"site{siteId}", "avatarbackgrounds"); var backgroundPath = _pathResolver.ResolveContentFilePath(backgroundRoot); if (!Directory.Exists(backgroundPath)) { Directory.CreateDirectory(backgroundPath); } File.Copy(Path.Combine(assetPath, "background.png"), Path.Combine(backgroundPath, "background.png")); totalFilesCopied++; var bundleRoot = Path.Combine($"site{siteId}", "avatarbundles"); var bundlePath = _pathResolver.ResolveContentFilePath(bundleRoot); if (!Directory.Exists(bundlePath)) { Directory.CreateDirectory(bundlePath); } File.Copy(Path.Combine(assetPath, "bundleicon.png"), Path.Combine(bundlePath, "icon.png")); totalFilesCopied++; File.Copy(Path.Combine(assetPath, "bundlenotif.png"), Path.Combine(bundlePath, "notif.png")); totalFilesCopied++; _logger.LogInformation("Copied {TotalFilesCopied} items for all layers.", totalFilesCopied); if (bundleJsonExists) { IEnumerable <AvatarBundle> bundleList; using (StreamReader file = File.OpenText(bundleJsonPath)) { var jsonString = await file.ReadToEndAsync(); bundleList = JsonConvert .DeserializeObject <IEnumerable <AvatarBundle> >(jsonString); } foreach (var bundle in bundleList) { _logger.LogInformation("Processing bundle {BundleName}", bundle.Name); var items = new List <int>(); foreach (var bundleItem in bundle.AvatarItems) { var item = await GetItemByLayerPositionSortOrderAsync( bundleItem.AvatarLayerPosition, bundleItem.SortOrder); items.Add(item.Id); } bundle.AvatarItems = null; await AddBundleAsync(bundle, items); } } var deleteIssues = false; if (jobDetails.UploadedFile) { _logger.LogInformation("Upload successful, clearing out uploaded files from {AssetPath}", assetPath); var directoryInfo = new DirectoryInfo(assetPath); try { directoryInfo.Delete(true); } catch (Exception ex) when( ex is DirectoryNotFoundException || ex is IOException || ex is System.Security.SecurityException || ex is UnauthorizedAccessException) { deleteIssues = true; _logger.LogWarning("Unable to delete uploaded files from {Path}: {Message}", assetPath, ex.Message); } } sw.Stop(); _logger.LogInformation("Default avatars added in {TotalSeconds} seconds.", sw.Elapsed.TotalSeconds); return(new JobStatus { PercentComplete = 100, Complete = true, Status = deleteIssues ? $"<strong>Import Complete</strong> - could not delete all uploaded files" : "<strong>Import Complete</strong>" }); } else { _logger.LogError("User {RequestingUser} doesn't have permission to import avatars.", requestingUser); return(new JobStatus { PercentComplete = 0, Status = "Permission denied.", Error = true, Complete = true }); } }