Пример #1
0
        private async Task SendBinaryContent(ApiObjectDescriptor sourceDescriptor, ApiObjectDescriptor newAdvertisement)
        {
            foreach (var element in sourceDescriptor.Elements)
            {
                if (IsBinaryAdvertisementElementType(element.Type))
                {
                    var value = element.Value as IBinaryElementValue
                                ?? throw new InvalidOperationException($"Cannot cast advertisement {sourceDescriptor.Id} binary element {element.TemplateCode} value");
                    if (string.IsNullOrEmpty(value.Raw))
                    {
                        continue;
                    }

                    var fileData = await SourceRestClient.DownloadFileAsync(sourceDescriptor.Id, value.DownloadUri);

                    var matchedElement = newAdvertisement.Elements.First(e => e.TemplateCode == element.TemplateCode);
                    EnsureUploadUrlIsValid(sourceDescriptor.Id, matchedElement);
                    var res = await DestRestClient.UploadFileAsync(sourceDescriptor.Id,
                                                                   new Uri(matchedElement.UploadUrl),
                                                                   value.Filename,
                                                                   fileData);

                    Interlocked.Increment(ref _uploadedBinariesCount);
                    element.Value = res;
                }
            }
        }
Пример #2
0
        private async Task CloneTemplateAsync(ApiListTemplate template)
        {
            var templateIdStr  = template.Id.ToString();
            var sourceTemplate = await SourceRestClient.GetTemplateAsync(templateIdStr);

            var destTemplate = await DestRestClient.GetTemplateAsync(templateIdStr);

            if (destTemplate == null)
            {
                await DestRestClient.CreateTemplateAsync(templateIdStr, sourceTemplate);
            }
            else
            {
                _logger.LogInformation("Template {id} already exists in destination", template.Id);
                if (!CompareTemplateDescriptors(destTemplate, sourceTemplate))
                {
                    if (_options.OverwriteUnequalTemplates)
                    {
                        _logger.LogWarning("Updating template {id} with version {versionId} in destination", template.Id, destTemplate.VersionId);
                        await DestRestClient.UpdateTemplateAsync(sourceTemplate, destTemplate.VersionId);
                    }
                    else
                    {
                        throw new InvalidOperationException("Templates with id = " + templateIdStr + " are not equal");
                    }
                }
                else
                {
                    _logger.LogInformation("Templates with id {id} are equal in source and destination", template.Id);
                }
            }
        }
Пример #3
0
        public async Task <bool> ExecuteAsync()
        {
            var sourcePositions = (await SourceRestClient.GetContentPositionsAsync()).ToDictionary(p => p.Id);
            var destPositions   = (await DestRestClient.GetContentPositionsAsync()).ToDictionary(p => p.Id);

            if (destPositions.Count == 0 && sourcePositions.Count > 0)
            {
                throw new InvalidOperationException($"There are {sourcePositions.Count} positions in source, but no positions in destination");
            }

            var diff = new HashSet <long>(sourcePositions.Keys);

            diff.SymmetricExceptWith(destPositions.Keys);
            if (diff.Count > 0)
            {
                var missedInSource = diff.Where(d => !sourcePositions.ContainsKey(d)).ToList();
                if (missedInSource.Count > 0)
                {
                    _logger.LogWarning("Next {count} positions are not present in source: {list}", missedInSource.Count, missedInSource.Select(p => new { Id = p, destPositions[p].Name }));
                }

                var missedInDest = diff.Where(d => !destPositions.ContainsKey(d)).ToList();
                if (missedInDest.Count > 0)
                {
                    _logger.LogWarning("Next {count} positions are not present in destination: {list}", missedInDest.Count, missedInDest);
                }
            }
            else
            {
                _logger.LogInformation("All {count} content positions are present both in source and destination", sourcePositions.Count);
            }

            var positionsLinksToClone = sourcePositions.Values
                                        .Where(p => p.Template != null && destPositions.ContainsKey(p.Id))
                                        .ToList();

            _logger.LogInformation("There are total {count} positions with links in source that are also present in destination", positionsLinksToClone.Count);

            var clonedCount = 0L;
            var failedIds   = new ConcurrentBag <long>();
            await CloneHelpers.ParallelRunAsync(
                positionsLinksToClone,
                _options.MaxDegreeOfParallelism,
                async position =>
            {
                try
                {
                    EnsurePositionsAreEqual(destPositions[position.Id], position);
                    await ClonePositionLinkAsync(position, destPositions[position.Id]);
                    Interlocked.Increment(ref clonedCount);
                    _logger.LogInformation("Position link cloning succeeded: {position}", position);
                }
                catch (Exception ex)
                {
                    failedIds.Add(position.Id);
                    _logger.LogError(default, ex, "Position link cloning error: {position}", position);
Пример #4
0
        public async Task <bool> ExecuteAsync()
        {
            ResetCounters();
            await EnsureTemplatesAreLoaded();

            var advertisements = new List <ApiListAdvertisement>(_destTemplates.Count * _options.TruncatedCloneSize);

            foreach (var templateId in _destTemplates.Keys)
            {
                if (_options.AdvertisementsTemplateId.HasValue && templateId != _options.AdvertisementsTemplateId)
                {
                    _logger.LogInformation("Skip fetching ads for template {templateId}", templateId);
                    continue;
                }

                if (_sourceTemplates.ContainsKey(templateId))
                {
                    var templateAds = await SourceRestClient.GetAdvertisementsByTemplateAsync(templateId, _isTruncatedCloning?_options.TruncatedCloneSize : (int?)null);

                    _logger.LogInformation("Found {count} ads for template {templateId}", templateAds.Count, templateId);
                    advertisements.AddRange(_options.AdvertisementsCreatedAtBeginDate.HasValue
                                            ? templateAds.Where(a => a.CreatedAt >= _options.AdvertisementsCreatedAtBeginDate.Value)
                                            : templateAds);
                }
                else
                {
                    _logger.LogWarning("Template {template} does not exist in source", _destTemplates[templateId]);
                }
            }

            var clonedCount = 0L;
            var failedAds   = new ConcurrentBag <ApiListAdvertisement>();

            _logger.LogInformation("Total advertisements to clone: {total}", advertisements.Count);
            await CloneHelpers.ParallelRunAsync(advertisements,
                                                _options.MaxDegreeOfParallelism,
                                                async advertisement =>
            {
                try
                {
                    _logger.LogInformation("Start to clone advertisement {id} with created date {createdAt:o}",
                                           advertisement.Id,
                                           advertisement.CreatedAt);

                    await CloneAdvertisementAsync(advertisement, _options.FetchAdvertisementBeforeClone);
                    Interlocked.Increment(ref clonedCount);
                }
                catch (Exception ex)
                {
                    failedAds.Add(advertisement);
                    _logger.LogError(new EventId(), ex, "Advertisement {id} cloning error", advertisement.Id);
                }
            });

            _logger.LogInformation("Total cloned advertisements: {cloned} of {total}", clonedCount, advertisements.Count);
            _logger.LogInformation("Total uploaded binaries: {totalBinaries}", _uploadedBinariesCount);
            _logger.LogInformation("Total advertisements selected to whitelist: {selectedToWhitelistCount}", _selectedToWhitelistCount);
            _logger.LogInformation("Total moderated advertisements: {totalModerated} (approved: {approvedCount}; rejected: {rejectedCount}). Total drafted: {draftedCount}; nominally approved: {nominallyCount}",
                                   _approvedCount + _rejectedCount,
                                   _approvedCount,
                                   _rejectedCount,
                                   _draftedCount,
                                   _nominallyApprovedCount);

            // All advertisements have been cloned, check the failed ones:
            if (failedAds.Count > 0)
            {
                return(!_isTruncatedCloning && await CloneFailedAdvertisements(failedAds));
            }

            return(true);
        }
Пример #5
0
        private async Task CloneAdvertisementAsync(ApiListAdvertisement advertisement, bool fetchAdvertisementBeforeCloning)
        {
            var versionId = string.Empty;
            var objectId  = advertisement.Id.ToString();

            if (fetchAdvertisementBeforeCloning)
            {
                versionId = await DestRestClient.GetAdvertisementVersionAsync(advertisement.Id);

                _logger.LogInformation("Object {id} has been fetched from destination preliminarily with version {versionId}", objectId, versionId);
            }

            if (string.IsNullOrEmpty(versionId))
            {
                var sourceDescriptor = await SourceRestClient.GetAdvertisementAsync(advertisement.Id);

                sourceDescriptor.TemplateVersionId = _destTemplates[sourceDescriptor.TemplateId].VersionId;
                if (sourceDescriptor.Elements.Any(e => IsBinaryAdvertisementElementType(e.Type)))
                {
                    var newAm = await DestRestClient.CreateAdvertisementPrototypeAsync(advertisement.Template.Id, advertisement.Language.ToString(), advertisement.Firm.Id);
                    await SendBinaryContent(sourceDescriptor, newAm);
                }

                try
                {
                    versionId = await DestRestClient.CreateAdvertisementAsync(advertisement.Id, advertisement.Firm.Id, sourceDescriptor);
                }
                catch (ObjectAlreadyExistsException ex)
                {
                    _logger.LogWarning(new EventId(), ex, "Object {id} already exists in destination, try to continue execution", objectId);
                }
            }

            if (advertisement.IsWhiteListed)
            {
                await DestRestClient.SelectAdvertisementToWhitelistAsync(objectId);

                Interlocked.Increment(ref _selectedToWhitelistCount);
            }

            if (advertisement.Moderation != null && advertisement.Moderation.Status != ModerationStatus.OnApproval &&
                advertisement.Moderation.Status != ModerationStatus.NominallyApproved)
            {
                if (string.IsNullOrEmpty(versionId))
                {
                    _logger.LogWarning("VersionId for object {id} is unknown, need to get latest version", objectId);
                    versionId = await SourceRestClient.GetAdvertisementVersionAsync(advertisement.Id);
                }

                await DestRestClient.UpdateAdvertisementModerationStatusAsync(objectId, versionId, advertisement.Moderation);
            }

            switch (advertisement.Moderation?.Status)
            {
            case null:
                break;

            case ModerationStatus.Approved:
                Interlocked.Increment(ref _approvedCount);
                break;

            case ModerationStatus.Rejected:
                Interlocked.Increment(ref _rejectedCount);
                break;

            case ModerationStatus.OnApproval:
                Interlocked.Increment(ref _draftedCount);
                break;

            case ModerationStatus.NominallyApproved:
                Interlocked.Increment(ref _nominallyApprovedCount);
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(advertisement.Moderation), advertisement.Moderation.Status, "Unsupported moderation status");
            }
        }
Пример #6
0
 private async Task EnsureTemplatesAreLoaded()
 {
     _sourceTemplates = _sourceTemplates ?? (await SourceRestClient.GetTemplatesAsync()).ToDictionary(p => p.Id);
     _destTemplates   = _destTemplates ?? (await DestRestClient.GetTemplatesAsync()).ToDictionary(p => p.Id);
 }
Пример #7
0
        private async Task SendBinaryContent(ApiObjectDescriptor sourceDescriptor, ApiObjectDescriptor newAdvertisement)
        {
            var binaryElements = sourceDescriptor.Elements.Where(e => IsBinaryAdvertisementElementType(e.Type));

            foreach (var element in binaryElements)
            {
                var value = element.Value as IBinaryElementValue
                            ?? throw new InvalidOperationException($"Cannot cast advertisement {sourceDescriptor.Id} binary element {element.TemplateCode} value");
                if (string.IsNullOrEmpty(value.Raw))
                {
                    continue;
                }

                var fileData = await SourceRestClient.DownloadFileAsync(sourceDescriptor.Id, value.DownloadUri);

                var matchedElement = newAdvertisement.Elements.First(e => e.TemplateCode == element.TemplateCode);
                EnsureUploadUrlIsValid(sourceDescriptor.Id, matchedElement);
                var uploadResponse = await DestRestClient.UploadFileAsync(
                    sourceDescriptor.Id,
                    new Uri(matchedElement.UploadUrl),
                    value.Filename,
                    fileData);

                Interlocked.Increment(ref _uploadedBinariesCount);

                if (element.Type == ElementDescriptorType.CompositeBitmapImage)
                {
                    var compositeBitmapImageElementValue = element.Value as ICompositeBitmapImageElementValue
                                                           ?? throw new InvalidOperationException($"Cannot cast advertisement {sourceDescriptor.Id} composite image element {element.TemplateCode} value");

                    var sizeSpecificImagesUploadTasks = compositeBitmapImageElementValue
                                                        .SizeSpecificImages
                                                        .Select(async image =>
                    {
                        var imageFileData = await SourceRestClient.DownloadFileAsync(sourceDescriptor.Id, image.DownloadUri);
                        var headers       = new[]
                        {
                            new NameValueHeaderValue(HeaderNames.AmsFileType, FileType.SizeSpecificBitmapImage.ToString()),
                            new NameValueHeaderValue(HeaderNames.AmsImageSize, image.Size.ToString())
                        };

                        var imageUploadResponse = await DestRestClient.UploadFileAsync(
                            sourceDescriptor.Id,
                            new Uri(matchedElement.UploadUrl),
                            image.Filename,
                            imageFileData,
                            headers);
                        Interlocked.Increment(ref _uploadedBinariesCount);
                        return(new SizeSpecificImage
                        {
                            Size = image.Size,
                            Raw = imageUploadResponse.Raw
                        });
                    })
                                                        .ToList();

                    element.Value = new CompositeBitmapImageElementValue
                    {
                        Raw                = uploadResponse.Raw,
                        CropArea           = compositeBitmapImageElementValue.CropArea,
                        SizeSpecificImages = await Task.WhenAll(sizeSpecificImagesUploadTasks)
                    };
                }
                else
                {
                    element.Value = uploadResponse;
                }
            }
        }
        public async Task <bool> ExecuteAsync()
        {
            ResetCounters();
            if (!await LoadAndCheckTemplatesWithVersions())
            {
                _logger.LogWarning(
                    "Try to synchronize templates in source and destination by setting {param} option to {mode}",
                    nameof(CloningToolOptions.Mode),
                    nameof(CloneMode.CloneTemplates));

                return(false);
            }

            if (_options.AdvertisementsProjectId.HasValue)
            {
                _logger.LogInformation("Fetching all ads for project {projectId}", _options.AdvertisementsProjectId.Value);
            }

            List <ApiListAdvertisement> advertisements;

            if (string.IsNullOrEmpty(_options.AdvertisementIdsFilename))
            {
                advertisements = new List <ApiListAdvertisement>(_destTemplates.Count * _options.TruncatedCloneSize);
                foreach (var templateId in _destTemplates.Keys)
                {
                    if (_options.AdvertisementsTemplateId.HasValue && templateId != _options.AdvertisementsTemplateId)
                    {
                        _logger.LogInformation("Skip fetching ads for template {templateId}", templateId);
                        continue;
                    }

                    if (_sourceTemplates.ContainsKey(templateId))
                    {
                        var templateAds = await SourceRestClient.GetAdvertisementsByTemplateAsync(
                            templateId,
                            _isTruncatedCloning?_options.TruncatedCloneSize : (int?)null,
                            _options.AdvertisementsProjectId);

                        _logger.LogInformation("Found {count} ads for template {templateId}", templateAds.Count, templateId);
                        advertisements.AddRange(_options.AdvertisementsCreatedAtBeginDate.HasValue
                                                ? templateAds.Where(a => a.CreatedAt >= _options.AdvertisementsCreatedAtBeginDate.Value)
                                                : templateAds);
                    }
                    else
                    {
                        _logger.LogWarning("Template {template} does not exist in source", _destTemplates[templateId]);
                    }
                }
            }
            else
            {
                var ids = LoadAdvertisementIdsFromFile(_options.AdvertisementIdsFilename);
                advertisements = new List <ApiListAdvertisement>(ids.Count);
                for (var i = 0; i <= ids.Count / MaxIdsCountToFetch; ++i)
                {
                    var portionIds = ids.Skip(MaxIdsCountToFetch * i).Take(MaxIdsCountToFetch);
                    var portionAds = await SourceRestClient.GetAdvertisementsByIdsAsync(portionIds);

                    advertisements.AddRange(portionAds);
                    _logger.LogInformation("Found {count} advertisements for {num} batch", portionAds.Count, i + 1);
                }
            }

            var clonedCount = 0L;
            var failedAds   = new ConcurrentBag <ApiListAdvertisement>();

            _logger.LogInformation("Total advertisements to clone: {total}", advertisements.Count);
            await CloneHelpers.ParallelRunAsync(
                advertisements,
                _options.MaxDegreeOfParallelism,
                async advertisement =>
            {
                try
                {
                    _logger.LogInformation(
                        "Start to clone advertisement {id} with created date {createdAt:o}",
                        advertisement.Id,
                        advertisement.CreatedAt);

                    await CloneAdvertisementAsync(advertisement);
                    Interlocked.Increment(ref clonedCount);
                }
                catch (Exception ex)
                {
                    failedAds.Add(advertisement);
                    _logger.LogError(default, ex, "Advertisement {id} cloning error", advertisement.Id);