Ejemplo n.º 1
0
        public async Task AddItemListAsync(ICollection <AvatarItem> itemList)
        {
            VerifyManagementPermission();
            var userId = GetClaimId(ClaimType.UserId);

            foreach (var item in itemList)
            {
                await _avatarItemRepository.AddAsync(userId, item);
            }
            await _avatarItemRepository.SaveAsync();
        }
Ejemplo n.º 2
0
        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
                });
            }
        }