Пример #1
0
        public Dictionary<string, object> ConvertArticle(Article article, IArticleFilter filter)
        {
            if (article == null || !article.Visible || article.Archived || !filter.Matches(article))
            {
                return null;
            }

            var dict = new Dictionary<string, object> { { IdProp, article.Id } };

            foreach (ArticleField field in article.Fields.Values)
            {
                if (field is ExtensionArticleField extensionArticleField)
                {
                    MergeExtensionFields(dict, extensionArticleField, filter);
                }
                else
                {
                    object value = ConvertField(field, filter);

                    if (value != null && !(value is string && string.IsNullOrEmpty((string)value)))
                    {
                        dict[field.FieldName] = value;
                    }
                }
            }

            return dict;
        }
Пример #2
0
        public void AddExtensionArticle(int parentId, Article article)
        {
            if (!_extensionMap.ContainsKey(parentId))
            {
                _extensionMap[parentId] = new List <Article>();
            }

            _extensionMap[parentId].Add(article);
        }
Пример #3
0
 private void ValidateDates(Article newArticle, Article existingArticle)
 {
     if (existingArticle != null &&
         newArticle.Modified != default(DateTime) &&
         newArticle.Modified != existingArticle.Modified)
     {
         _outdatedArticleIds.Add(newArticle.Id);
     }
 }
Пример #4
0
        private IEnumerable <object> GetFields(Article article, CallContext ctx, bool omitId = false)
        {
            var systemFields = GetAttributes(article);
            var fields       = (article.Fields.Values
                                .Where(
                                    x =>
                                    (x is PlainArticleField && !string.IsNullOrEmpty(((PlainArticleField)x).Value) ||
                                     !(x is PlainArticleField)))
                                .Select(x => Convert(x, ctx)).Where(x => x != null));

            if (omitId)
            {
                return(fields);
            }

            return(systemFields.Union(fields));
        }
Пример #5
0
        private Article DeserializeArticle(IProductDataSource productDataSource, Models.Configuration.Content definition, DBConnector connector, Context context)
        {
            if (productDataSource == null)
            {
                return(null);
            }

            int id = productDataSource.GetArticleId();

            context.TakeIntoAccount(id);

            var qpContent = _contentService.Read(definition.ContentId);

            Article article = new Article
            {
                Id                 = id,
                ContentName        = qpContent.NetName,
                Modified           = productDataSource.GetModified(),
                ContentId          = definition.ContentId,
                ContentDisplayName = qpContent.Name,
                PublishingMode     = definition.PublishingMode,
                IsReadOnly         = definition.IsReadOnly,
                Visible            = true
            };

            foreach (Field fieldInDef in definition.Fields.Where(x => !(x is BaseVirtualField) && !(x is Dictionaries)))
            {
                var field = DeserializeField(fieldInDef, _fieldService.Read(fieldInDef.FieldId), productDataSource, connector, context);

                article.Fields[field.FieldName] = field;
            }

            if (definition.LoadAllPlainFields)
            {
                var qpFields = _fieldService.List(definition.ContentId);

                foreach (var plainFieldFromQp in qpFields.Where(x => x.RelationType == RelationType.None && definition.Fields.All(y => y.FieldId != x.Id)))
                {
                    article.Fields[plainFieldFromQp.Name] = DeserializeField(new PlainField {
                        FieldId = plainFieldFromQp.Id
                    }, plainFieldFromQp, productDataSource, connector, context);
                }
            }

            return(article);
        }
Пример #6
0
        private IEnumerable <Article> GetChildArticles(ArticleField field, IArticleFilter filter)
        {
            if (field is IGetArticle getArticle)
            {
                Article childArticle = getArticle.GetItem(filter);

                return(childArticle != null ? new[] { childArticle } : new Article[0]);
            }
            else if (field is IGetArticles getArticles)
            {
                return(getArticles.GetArticles(filter));
            }
            else
            {
                return(new Article[0]);
            }
        }
Пример #7
0
        public string SerializeProduct(Article article, IArticleFilter filter, bool includeRegionTags = false)
        {
            var sw = new Stopwatch();
            sw.Start();
            Dictionary<string, object> convertedArticle = ConvertArticle(article, filter);
            sw.Stop();
            _logger.Debug("Product {1} conversion took {0} sec", sw.Elapsed.TotalSeconds, article.Id);
            
            sw.Reset();
            sw.Start();
            string productJson = JsonConvert.SerializeObject(convertedArticle, Formatting.Indented);
            sw.Stop();
            _logger.Debug("Product {1} serializing took {0} sec", sw.Elapsed.TotalSeconds, article.Id);

            string result;
            if (includeRegionTags && article.GetField("Regions") is MultiArticleField regionField)
            {
                sw.Reset();
                sw.Start();

                int[] regionIds = regionField.Items.Keys.ToArray();

                TagWithValues[] tags = _regionTagReplaceService.GetRegionTagValues(productJson, regionIds);

                string tagsJson = JsonConvert.SerializeObject(
                    tags,
                    Formatting.Indented,
                    new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });

                sw.Stop();
                _logger.Debug("Product {1} enrichment with regional tags took {0} sec", sw.Elapsed.TotalSeconds, article.Id);

                result = $"{{ \"{ProductProp}\" : {productJson}, \"{RegionTagsProp}\" : {tagsJson} }}";
            }
            else
            {
                result = $"{{ \"{ProductProp}\" : {productJson} }}";
            }

            return result;
        }
Пример #8
0
 public string GetProductXml(Article article, IArticleFilter filter)
 {
     return(ProcessProductWithTags(filter, article));
 }
Пример #9
0
 private IEnumerable <object> GetAttributes(Article article)
 {
     yield return(new XElement("Id", article.Id));
 }
Пример #10
0
        private object Convert(Article article, CallContext ctx, bool omitType = false, bool addXsi = false, string forceName = null)
        {
            if (article == null)
            {
                return(null);
            }
            if (article.ContentId == default(int) && forceName == null)
            {
                return("");
            }
            if (!article.Visible || article.Archived)
            {
                return(null);
            }
            if (omitType)
            {
                return(GetFields(article, ctx));
            }

            var fs = GetFields(article, ctx);

            string nodeName = forceName ?? article.ContentName;

            if (string.IsNullOrWhiteSpace(nodeName))
            {
                throw new Exception(
                          string.Format("Error while xml generation: ContentName is not filled in the article. ContentId={0} Id={1}",
                                        article.ContentId, article.Id));
            }

            var node = new XElement(nodeName, fs);

            if (addXsi)
            {
                var typeField = _settingsService.GetSetting(SettingsTitles.PRODUCT_TYPES_FIELD_NAME);

                ArticleField f;

                if (!string.IsNullOrEmpty(typeField))
                {
                    typeField = "Type";
                }

                if (article.Fields.TryGetValue(typeField, out f))
                {
                    XNamespace ns = "http://www.w3.org/2001/XMLSchema-instance";
                    var        sf = f as SingleArticleField;
                    var        pf = f as PlainArticleField;

                    if (sf != null && sf.Item != null)
                    {
                        node.Add(new XAttribute(ns + "type", sf.Item.ContentName));
                    }
                    else if (pf != null && !string.IsNullOrEmpty(pf.Value))
                    {
                        node.Add(new XAttribute(ns + "type", pf.Value));
                    }
                }
            }
            return(node);
        }
Пример #11
0
        /// <exception cref="ArgumentNullException" />
        /// <exception cref="InvalidOperationException" />
        private void ProcessArticlesTree(Article newArticle, Article existingArticle, Content definition)
        {
            if (newArticle == null || !_filter.Matches(newArticle))
            {
                return;
            }
            if (!_filter.Matches(existingArticle))
            {
                existingArticle = null;
            }
            if (definition == null)
            {
                throw new ArgumentNullException(nameof(definition));
            }

            ValidateDates(newArticle, existingArticle);

            ArticleData newArticleUpdateData = new ArticleData
            {
                ContentId = definition.ContentId,
                Id        = newArticle.Id
            };

            List <int> plainFieldIds = definition.Fields
                                       .Where(x => x is PlainField)
                                       .Select(x => x.FieldId)
                                       .ToList();

            if (definition.LoadAllPlainFields)
            {
                plainFieldIds.AddRange(
                    _fieldService.List(definition.ContentId)
                    .Where(x => x.RelationType == RelationType.None &&
                           definition.Fields.All(y => y.FieldId != x.Id))
                    .Select(x => x.Id));
            }

            // TODO: исключаем Readonly поля
            var updatedFields = newArticle.Fields.Values
                                .OfType <PlainArticleField>()
                                .Where(x => plainFieldIds.Contains(x.FieldId.Value) &&
                                       (existingArticle == null ||
                                        existingArticle.Fields.Values
                                        .OfType <PlainArticleField>()
                                        .All(y => y.FieldId != x.FieldId || !HasEqualNativeValues(x, y))))
                                .Select(x => new FieldData {
                Id = x.FieldId.Value, Value = x.Value
            });

            newArticleUpdateData.Fields.AddRange(updatedFields);

            var associationFieldsInfo = (
                from fieldDef in definition.Fields.OfType <Association>()
                join field in newArticle.Fields.Values on fieldDef.FieldId equals field.FieldId
                select
                new
            {
                field,
                oldField = existingArticle?.Fields.Values.SingleOrDefault(x => x.FieldId == field.FieldId),
                fieldDef
            }).ToArray();

            foreach (var fieldToSyncInfo in associationFieldsInfo)
            {
                if (fieldToSyncInfo.fieldDef is BackwardRelationField backwardRelationFieldDef)
                {
                    BackwardArticleField oldField = (BackwardArticleField)fieldToSyncInfo.oldField;
                    BackwardArticleField field    = (BackwardArticleField)fieldToSyncInfo.field;

                    int[] idsToAdd = field.GetArticles(_filter)
                                     .Where(x => oldField == null || oldField.GetArticles(_filter).All(y => y.Id != x.Id))
                                     .Select(x => x.Id)
                                     .ToArray();

                    int[] idsToRemove = oldField?.GetArticles(_filter)
                                        .Select(x => x.Id)
                                        .Where(x => field.GetArticles(_filter).All(y => y.Id != x))
                                        .ToArray() ?? new int[0];

                    if (idsToAdd.Any())
                    {
                        _updateData.AddRange(idsToAdd.Select(x => new ArticleData
                        {
                            Id        = x,
                            ContentId = backwardRelationFieldDef.Content.ContentId,
                            Fields    = new List <FieldData>
                            {
                                new FieldData {
                                    Id = field.FieldId.Value, ArticleIds = new[] { newArticle.Id }
                                }
                            }
                        }));
                    }

                    if (idsToRemove.Any())
                    {
                        if (backwardRelationFieldDef.DeletingMode == DeletingMode.Delete)
                        {
                            foreach (int idToRemove in idsToRemove)
                            {
                                _articlesToDelete[idToRemove] = backwardRelationFieldDef.Content;
                            }
                        }
                        else
                        {
                            _updateData.AddRange(idsToRemove.Select(x => new ArticleData
                            {
                                Id        = x,
                                ContentId = backwardRelationFieldDef.Content.ContentId
                            }));
                        }
                    }
                }
                else if (fieldToSyncInfo.fieldDef is ExtensionField extensionFieldDef)
                {
                    ExtensionArticleField oldField = (ExtensionArticleField)fieldToSyncInfo.oldField;
                    ExtensionArticleField field    = (ExtensionArticleField)fieldToSyncInfo.field;

                    if (oldField == null || field.Value != oldField.Value)
                    {
                        newArticleUpdateData.Fields.Add(new FieldData
                        {
                            Id         = extensionFieldDef.FieldId,
                            Value      = field.Value,
                            ArticleIds = field.Item == null ? null : new[] { field.Item.Id }
                        });

                        if (oldField?.Item != null)
                        {
                            _articlesToDelete[oldField.Item.Id] = extensionFieldDef
                                                                  .ContentMapping[oldField.Item.ContentId];
                        }
                    }
                }
                else if (fieldToSyncInfo.field is SingleArticleField)
                {
                    SingleArticleField oldField       = (SingleArticleField)fieldToSyncInfo.oldField;
                    SingleArticleField field          = (SingleArticleField)fieldToSyncInfo.field;
                    EntityField        entityFieldDef = (EntityField)fieldToSyncInfo.fieldDef;

                    Article item = field.GetItem(_filter);

                    Article oldItem = oldField?.GetItem(_filter);

                    if (item?.Id != oldItem?.Id)
                    {
                        newArticleUpdateData.Fields.Add(new FieldData
                        {
                            Id         = field.FieldId.Value,
                            ArticleIds = item == null ? null : new[] { item.Id }
                        });

                        if (oldItem != null && entityFieldDef.DeletingMode == DeletingMode.Delete)
                        {
                            _articlesToDelete[oldItem.Id] = entityFieldDef.Content;
                        }
                    }
                }
                else if (fieldToSyncInfo.field is MultiArticleField)
                {
                    MultiArticleField oldField       = (MultiArticleField)fieldToSyncInfo.oldField;
                    MultiArticleField field          = (MultiArticleField)fieldToSyncInfo.field;
                    EntityField       entityFieldDef = (EntityField)fieldToSyncInfo.fieldDef;

                    var items = field.GetArticles(_filter).ToArray();

                    var oldItems = oldField?.GetArticles(_filter).ToArray();

                    if (items.Length != (oldItems?.Length ?? 0) || items.Any(x => oldItems.All(y => y.Id != x.Id)))
                    {
                        newArticleUpdateData.Fields.Add(new FieldData
                        {
                            Id = field.FieldId.Value, ArticleIds = items.Select(x => x.Id).ToArray()
                        });

                        if (entityFieldDef.DeletingMode == DeletingMode.Delete)
                        {
                            int[] idsToRemove = oldItems?
                                                .Where(x => items.All(y => y.Id != x.Id))
                                                .Select(x => x.Id)
                                                .ToArray() ?? new int[0];

                            foreach (int idToRemove in idsToRemove)
                            {
                                _articlesToDelete[idToRemove] = entityFieldDef.Content;
                            }
                        }
                    }
                }
            }

            if (newArticleUpdateData.Fields.Any())
            {
                _updateData.Add(newArticleUpdateData);
            }

            foreach (var fieldInfo in associationFieldsInfo
                     .Where(x => x.fieldDef.UpdatingMode == UpdatingMode.Update || x.fieldDef is ExtensionField))
            {
                Article[] oldFieldsArticles = fieldInfo.oldField == null
                    ? new Article[0]
                    : GetChildArticles(fieldInfo.oldField, _filter).ToArray();

                foreach (Article childArticle in GetChildArticles(fieldInfo.field, _filter))
                {
                    Content childArticleDef = fieldInfo.fieldDef.GetContents()
                                              .SingleOrDefault(x => x.ContentId == childArticle.ContentId);

                    if (childArticleDef == null)
                    {
                        throw new InvalidOperationException($@"There is an conflict in product definition field {fieldInfo.field.FieldId} between ContentId={childArticle.ContentId} and Articleid={childArticle.Id}");
                    }

                    Article oldChildArticle = oldFieldsArticles.SingleOrDefault(x => x.Id == childArticle.Id);

                    ProcessArticlesTree(childArticle, oldChildArticle, childArticleDef);
                }
            }
        }
Пример #12
0
        /// <exception cref="ProductUpdateConcurrencyException" />
        public InsertData[] Update(Article product, ProductDefinition definition, bool isLive = false, bool createVersions = false)
        {
            Article oldProduct = _productService.GetProductById(product.Id, isLive, definition);

            _updateData.Clear();
            _articlesToDelete.Clear();
            _outdatedArticleIds.Clear();

            _filter = isLive ? ArticleFilter.LiveFilter : ArticleFilter.DefaultFilter;

            ProcessArticlesTree(product, oldProduct, definition.StorageSchema);

            if (_outdatedArticleIds.Any())
            {
                throw new ProductUpdateConcurrencyException(_outdatedArticleIds.ToArray());
            }

            using (var transaction = _createTransaction())
            {
                _logger.Info()
                .Message("Batch update for product {id} started", product.Id)
                .Property("updateData", _updateData.ToDictionary(n => n.ToString(), m => m.Fields))
                .Write();

                InsertData[] idMapping = _articleService.BatchUpdate(_updateData, createVersions);

                _logger.Info("Batch update for product {id} completed", product.Id);

                if (_articlesToDelete.Any())
                {
                    _logger.Info()
                    .Message("Deleting articles for product {id} started", product.Id)
                    .Property("articlesToDelete", _articlesToDelete.Keys)
                    .Write();

                    foreach (KeyValuePair <int, Content> articleToDeleteKv in _articlesToDelete)
                    {
                        try
                        {
                            var qpArticle = _articleService.Read(articleToDeleteKv.Key);

                            _deleteAction.DeleteProduct(
                                qpArticle, new ProductDefinition {
                                StorageSchema = articleToDeleteKv.Value
                            },
                                true, false, null);
                        }
                        catch (MessageResultException ex)
                        {
                            _logger.Error()
                            .Exception(ex)
                            .Message("Cannot remove article {id}", articleToDeleteKv.Key)
                            .Write();
                        }
                    }

                    _logger.Info("Deleting articles for product {id} completed", product.Id);
                }

                transaction.Commit();
                return(idMapping);
            }
        }