Ejemplo n.º 1
0
        public override async Task AddSyncComponents(JObject content, IGraphMergeContext context)
        {
            context.MergeNodeCommand.AddProperty <string>(TermContentTypePropertyName, content);

            _embeddedContentItemsGraphSyncer.IsNonLeafEmbeddedTerm = false;
            await _embeddedContentItemsGraphSyncer.AddSyncComponents((JArray?)content[ContainerName], context);
        }
        public Task AddSyncComponents(JObject contentItemField, IGraphMergeContext context)
        {
            //todo requires 'picked' part has a graph sync part
            // add to docs & handle picked part not having graph sync part or throw exception

            return(AddSyncComponents(context, (JArray?)contentItemField[ContentItemIdsKey]));
        }
        public override async Task AddSyncComponents(JObject content, IGraphMergeContext context)
        {
            using var _ = context.SyncNameProvider.PushPropertyNameTransform(_sitemapPropertyNameTransform);

            //todo: helper for these?
            JValue?value = (JValue?)content[OverrideSitemapConfigPropertyName];

            if (value != null && value.Type != JTokenType.Null) //first bool?
            {
                context.MergeNodeCommand.Properties.Add(await context.SyncNameProvider.PropertyName(OverrideSitemapConfigPropertyName), value.As <bool>());
            }

            //todo: we want the change frequency value lowercase (as the sitemap xml format wants it lowercase),
            // but we probably want enums to serialise using normal casing, so can Enum.Parse etc.
            // add flag to any enum helpers, such as EnumContentPropertyMatchesNodeProperty
            value = (JValue?)content[ChangeFrequencyPropertyName];
            if (value != null && value.Type != JTokenType.Null)
            {
                context.MergeNodeCommand.Properties.Add(await context.SyncNameProvider.PropertyName(ChangeFrequencyPropertyName), ((ChangeFrequency)value.As <int>()).ToString().ToLowerInvariant());
            }

            value = (JValue?)content[PriorityPropertyName];
            if (value != null && value.Type != JTokenType.Null)
            {
                context.MergeNodeCommand.Properties.Add(await context.SyncNameProvider.PropertyName(PriorityPropertyName), value.As <int>());
            }

            value = (JValue?)content[ExcludePropertyName];
            if (value != null && value.Type != JTokenType.Null)
            {
                context.MergeNodeCommand.Properties.Add(await context.SyncNameProvider.PropertyName(ExcludePropertyName), value.As <bool>());
            }
        }
Ejemplo n.º 4
0
        public async Task AddSyncComponentsDetaching(IGraphMergeContext context)
        {
            var taxonomyFieldSettings = context.ContentPartFieldDefinition !.GetSettings <TaxonomyFieldSettings>();

            //todo: factor out common code
            //todo: check for null
            ContentItem?taxonomyContentItem = await context.ContentItemVersion.GetContentItem(
                context.ContentManager,
                taxonomyFieldSettings.TaxonomyContentItemId);

            JObject taxonomyPartContent = taxonomyContentItem !.Content[nameof(TaxonomyPart)];
            string  termContentType     = taxonomyPartContent[TermContentType] !.Value <string>();

            string termRelationshipType = TermRelationshipType(termContentType);

            //todo: split into stefull and stateless and put both in the context
            // then can stop stateful contenttype being reset
            IEnumerable <string> destNodeLabels = await context.SyncNameProvider.NodeLabels(termContentType);

            context.ReplaceRelationshipsCommand.RemoveAnyRelationshipsTo(
                termRelationshipType,
                destNodeLabels);

            string taxonomyRelationshipType = TaxonomyRelationshipType(taxonomyContentItem);

            destNodeLabels = await context.SyncNameProvider.NodeLabels(taxonomyContentItem.ContentType);

            context.ReplaceRelationshipsCommand.RemoveAnyRelationshipsTo(
                taxonomyRelationshipType,
                destNodeLabels);
        }
        public override async Task AddSyncComponents(JObject content, IGraphMergeContext context)
        {
            // prefix field property names, so there's no possibility of a clash with the eponymous fields property names
            using var _ = context.SyncNameProvider.PushPropertyNameTransform(_publishLaterFieldsPropertyNameTransform);

            context.MergeNodeCommand.AddProperty <DateTime>(
                await context.SyncNameProvider.PropertyName(ScheduledPublishUtcPropertyName),
                content, ScheduledPublishUtcPropertyName);
        }
Ejemplo n.º 6
0
        private async Task <List <CommandRelationship> > GetRequiredRelationshipsAndOptionallySync(
            JArray?contentItems,
            IGraphMergeContext context,
            IAllowSync?allowSync = null)
        {
            ContentItem[] embeddedContentItems = ConvertToContentItems(contentItems);

            List <CommandRelationship> requiredRelationships = new List <CommandRelationship>();

            int relationshipOrdinal = 0;

            foreach (ContentItem contentItem in embeddedContentItems)
            {
                IMergeGraphSyncer?mergeGraphSyncer;

                if (allowSync == null)
                {
                    // we're actually syncing, not checking if it's allowed
                    mergeGraphSyncer = await context.MergeGraphSyncer.SyncEmbedded(contentItem);
                }
                else
                {
                    mergeGraphSyncer = GetNewMergeGraphSyncer();

                    IAllowSync embeddedAllowSync = await mergeGraphSyncer.SyncAllowed(context.GraphReplicaSet, contentItem, context.ContentManager, context);

                    allowSync.AddRelated(embeddedAllowSync);
                    if (embeddedAllowSync.Result != AllowSyncResult.Allowed)
                    {
                        continue;
                    }
                }

                //todo: check embedded items with no graphsyncpart attached
                if (mergeGraphSyncer == null)
                {
                    continue;
                }

                IMergeNodeCommand containedContentMergeNodeCommand = mergeGraphSyncer.MergeNodeCommand;
                containedContentMergeNodeCommand.CheckIsValid();

                string relationshipType = await RelationshipType(contentItem.ContentType);

                var properties = await GetRelationshipProperties(contentItem, relationshipOrdinal, context.SyncNameProvider);

                ++relationshipOrdinal;

                requiredRelationships.Add(new CommandRelationship(
                                              relationshipType,
                                              await TwoWayIncomingRelationshipType(contentItem.ContentType),
                                              properties,
                                              containedContentMergeNodeCommand.NodeLabels,
                                              containedContentMergeNodeCommand.IdPropertyName !,
                                              Enumerable.Repeat(containedContentMergeNodeCommand.Properties[containedContentMergeNodeCommand.IdPropertyName !], 1)));
        private async Task AddSyncComponents(IGraphMergeContext context, JArray?contentItemIdsJArray = null)
        {
            ContentPickerFieldSettings contentPickerFieldSettings =
                context.ContentPartFieldDefinition !.GetSettings <ContentPickerFieldSettings>();

            //todo: use pickedContentSyncNameProvider in RelationshipTypeContentPicker?
            string relationshipType = await RelationshipTypeContentPicker(contentPickerFieldSettings, context.SyncNameProvider);

            //todo: support multiple pickable content types
            string pickedContentType = contentPickerFieldSettings.DisplayedContentTypes[0];

            ISyncNameProvider pickedContentSyncNameProvider = _serviceProvider.GetSyncNameProvider(pickedContentType);

            IEnumerable <string> destNodeLabels = await pickedContentSyncNameProvider.NodeLabels();

            if (contentItemIdsJArray?.HasValues != true)
            {
                context.ReplaceRelationshipsCommand.RemoveAnyRelationshipsTo(
                    relationshipType,
                    destNodeLabels);
                return;
            }

            ContentItem[] foundDestinationContentItems = await GetContentItemsFromIds(
                contentItemIdsJArray,
                context.ContentManager,
                context.ContentItemVersion);

            if (context.ContentItemVersion.GraphReplicaSetName == GraphReplicaSetNames.Preview &&
                foundDestinationContentItems.Count() != contentItemIdsJArray.Count)
            {
                throw new GraphSyncException(
                          $"Missing picked content items. Looked for {string.Join(",", contentItemIdsJArray.Values<string?>())}. Found {string.Join(",", foundDestinationContentItems.Select(i => i.ContentItemId))}. Current merge node command: {context.MergeNodeCommand}.");
            }

            // if we're syncing to the published graph, some items may be draft only,
            // so it's valid to have less found content items than are picked
            //todo: we could also check when publishing and take into account how many we expect not to find as they are draft only

            IEnumerable <object> foundDestinationNodeIds =
                foundDestinationContentItems.Select(ci => GetNodeId(ci !, pickedContentSyncNameProvider, context.ContentItemVersion));

            long ordinal = 0;

            foreach (var item in foundDestinationNodeIds)
            {
                context.ReplaceRelationshipsCommand.AddRelationshipsTo(
                    relationshipType,
                    ContentPickerRelationshipProperties.Concat(new[] { new KeyValuePair <string, object>("Ordinal", ordinal++) }),
                    destNodeLabels,
                    pickedContentSyncNameProvider.IdPropertyName(),
                    item);
            }
        }
        public override async Task AddSyncComponents(JObject content, IGraphMergeContext context)
        {
            //todo: make concurrent?
            await base.AddSyncComponents(content, context);

            // FlowPart allows part definition level fields, but values are on each FlowPart instance
            // prefix flow field property names, so there's no possibility of a clash with the eponymous fields property names
            using var _ = context.SyncNameProvider.PushPropertyNameTransform(_flowFieldsPropertyNameTransform);

            await _contentFieldsGraphSyncer.AddSyncComponents(content, context);
        }
Ejemplo n.º 9
0
        public override Task AddSyncComponents(JObject content, IGraphMergeContext context)
        {
            string?title = context.MergeNodeCommand.AddProperty <string>(NodeTitlePropertyName, content, _contentTitlePropertyName);

            if (title == null)
            {
                context.MergeNodeCommand.Properties.Add(NodeTitlePropertyName, context.ContentItem.DisplayText);
            }

            return(Task.CompletedTask);
        }
        public override async Task AddSyncComponents(JObject content, IGraphMergeContext context)
        {
            // prefix field property names, so there's no possibility of a clash with the eponymous fields property names
            using var _ = context.SyncNameProvider.PushPropertyNameTransform(_htmlBodyFieldsPropertyNameTransform);

            JValue?htmlValue = (JValue?)content[HtmlPropertyName];

            if (htmlValue != null && htmlValue.Type != JTokenType.Null)
            {
                context.MergeNodeCommand.Properties.Add(await context.SyncNameProvider.PropertyName(HtmlPropertyName), htmlValue.As <string>());
            }
        }
        public async Task AddSyncComponents(JObject contentItemField, IGraphMergeContext context)
        {
            string nodePropertyName = await context.SyncNameProvider.PropertyName(context.ContentPartFieldDefinition !.Name);

            if (SyncMultilineToArray(context.ContentPartFieldDefinition))
            {
                context.MergeNodeCommand.AddArrayPropertyFromMultilineString(
                    nodePropertyName, contentItemField, ContentKey);
                return;
            }

            context.MergeNodeCommand.AddProperty <string>(nodePropertyName, contentItemField, ContentKey);
        }
        public async Task AddSyncComponents(JObject contentItemField, IGraphMergeContext context)
        {
            JValue?value = (JValue?)contentItemField[ContentKey];

            if (value == null || value.Type == JTokenType.Null)
            {
                return;
            }

            context.MergeNodeCommand.Properties.Add(
                await context.SyncNameProvider.PropertyName(context.ContentPartFieldDefinition !.Name),
                value.As <string>());
        }
        public override async Task AllowSync(
            JArray?contentItems,
            IGraphMergeContext context,
            IAllowSync allowSync)
        {
            IAllowSync baseAllowSync = new AllowSync();
            await base.AllowSync(contentItems, context, baseAllowSync);

            var baseBlockersWithoutIncomingTaxonomyBlocker =
                baseAllowSync.SyncBlockers.Where(sb => sb.ContentType != "Taxonomy");

            if (baseBlockersWithoutIncomingTaxonomyBlocker.Any())
            {
                allowSync.AddSyncBlockers(baseBlockersWithoutIncomingTaxonomyBlocker);
            }
        }
Ejemplo n.º 14
0
        public async Task AddSyncComponents(JObject contentItemField, IGraphMergeContext context)
        {
            string basePropertyName = await context.SyncNameProvider.PropertyName(context.ContentPartFieldDefinition !.Name);

            JValue?value = (JValue?)contentItemField[UrlFieldKey];

            if (value != null && value.Type != JTokenType.Null)
            {
                context.MergeNodeCommand.Properties.Add($"{basePropertyName}{LinkUrlPostfix}", value.As <string>());
            }

            value = (JValue?)contentItemField[TextFieldKey];
            if (value != null && value.Type != JTokenType.Null)
            {
                context.MergeNodeCommand.Properties.Add($"{basePropertyName}{LinkTextPostfix}", value.As <string>());
            }
        }
Ejemplo n.º 15
0
        public override async Task AddSyncComponents(JObject content, IGraphMergeContext context)
        {
            using var _ = context.SyncNameProvider.PushPropertyNameTransform(_pageLocationPropertyNameTransform);

            context.MergeNodeCommand.AddProperty <string>(await context.SyncNameProvider.PropertyName(UrlNamePropertyName), content, UrlNamePropertyName);
            context.MergeNodeCommand.AddProperty <string>(await context.SyncNameProvider.PropertyName(FullUrlPropertyName), content, FullUrlPropertyName);

            var settings = context.ContentTypePartDefinition.GetSettings <PageLocationPartSettings>();

            //TODO : if this setting changes, do we need to also check/remove these properties from the node?
            if (settings.DisplayRedirectLocationsAndDefaultPageForLocation)
            {
                context.MergeNodeCommand.AddProperty <bool>(await context.SyncNameProvider.PropertyName(DefaultPageForLocationPropertyName), content, DefaultPageForLocationPropertyName);

                context.MergeNodeCommand.AddArrayPropertyFromMultilineString(
                    await context.SyncNameProvider.PropertyName(RedirectLocationsPropertyName), content,
                    RedirectLocationsPropertyName);
            }
        }
Ejemplo n.º 16
0
        public async Task AddSyncComponents(JObject contentItemField, IGraphMergeContext context)
        {
            JValue?value = (JValue?)contentItemField?[ContentKey];

            if (value == null || value.Type == JTokenType.Null)
            {
                return;
            }

            var fieldSettings = context.ContentPartFieldDefinition !.GetSettings <NumericFieldSettings>();

            string propertyName = await context.SyncNameProvider.PropertyName(context.ContentPartFieldDefinition !.Name);

            if (fieldSettings.Scale == 0)
            {
                context.MergeNodeCommand.Properties.Add(propertyName, (int)value);
            }
            else
            {
                context.MergeNodeCommand.Properties.Add(propertyName, (decimal)value);
            }
        }
Ejemplo n.º 17
0
        public override async Task AddSyncComponents(JObject content, IGraphMergeContext context)
        {
            string?taxonomyContentItemId = (string?)content[TaxonomyContentItemId];

            if (taxonomyContentItemId == null)
            {
                throw new GraphSyncException($"{PartName} is missing {TaxonomyContentItemId}.");
            }

            //todo: check for null
            ContentItem?contentItem = await context.ContentItemVersion.GetContentItem(context.ContentManager, taxonomyContentItemId);

            ISyncNameProvider termSyncNameProvider = _serviceProvider.GetSyncNameProvider(contentItem !.ContentType);

            //todo: override/extension that takes a contentitem
            context.ReplaceRelationshipsCommand.AddRelationshipsTo(
                //todo: go through syncNameProvider
                $"has{contentItem.ContentType}",
                null,
                await termSyncNameProvider.NodeLabels(),
                termSyncNameProvider.IdPropertyName(),
                termSyncNameProvider.GetNodeIdPropertyValue(contentItem.Content.GraphSyncPart, context.ContentItemVersion));
        }
        public override Task AddSyncComponents(JObject graphLookupContent, IGraphMergeContext context)
        {
            var settings = context.ContentTypePartDefinition.GetSettings <GraphLookupPartSettings>();

            JArray?nodes = (JArray?)graphLookupContent[NodesPropertyName];

            if (nodes == null || nodes.Count == 0)
            {
                return(Task.CompletedTask);
            }

            if (settings.PropertyName != null)
            {
                context.MergeNodeCommand.Properties.Add(settings.PropertyName, GetId(nodes.First()));
            }

            if (settings.RelationshipType != null)
            {
                //todo: settings should contains destnodelabels
                context.ReplaceRelationshipsCommand.AddRelationshipsTo(
                    settings.RelationshipType !,
                    null,
                    new[] { settings.NodeLabel ! },
 public override Task AddSyncComponentsDetaching(IGraphMergeContext context)
 {
     return(_embeddedContentItemsGraphSyncer.AddSyncComponentsDetaching(context));
 }
Ejemplo n.º 20
0
        public virtual async Task AllowSync(
            JArray?contentItems,
            IGraphMergeContext context,
            IAllowSync allowSync)
        {
            _logger.LogDebug("Do embedded items allow sync?");

            List <CommandRelationship> requiredRelationships = await GetRequiredRelationshipsAndOptionallySync(contentItems, context, allowSync);

            INodeAndOutRelationshipsAndTheirInRelationships?existing = (await context.GraphReplicaSet.Run(
                                                                            new NodeAndOutRelationshipsAndTheirInRelationshipsQuery(
                                                                                context.ReplaceRelationshipsCommand.SourceNodeLabels,
                                                                                context.ReplaceRelationshipsCommand.SourceIdPropertyName !,
                                                                                context.ReplaceRelationshipsCommand.SourceIdPropertyValue !)))
                                                                       .FirstOrDefault();

            if (existing?.OutgoingRelationships.Any() != true)
            {
                // nothing to do here, node is being newly created or existing node has no relationships
                return;
            }

            (string[] embeddableContentTypes, IEnumerable <string> relationshipTypes) =
                await GetEmbeddableContentTypesAndRelationshipTypes(context);

            existing = new NodeAndOutRelationshipsAndTheirInRelationships(
                existing.SourceNode,
                existing.OutgoingRelationships
                .Where(or =>
                       embeddableContentTypes.Contains(
                           context.SyncNameProvider.GetContentTypeFromNodeLabels(
                               or.outgoingRelationship.DestinationNode.Labels)) &&
                       relationshipTypes.Contains(or.outgoingRelationship.Relationship.Type)));

            IEnumerable <CommandRelationship> existingRelationshipsForEmbeddableContentTypes =
                existing.ToCommandRelationships(context.SyncNameProvider);

            _removingRelationships = GetRemovingRelationships(
                existingRelationshipsForEmbeddableContentTypes,
                requiredRelationships,
                context.SyncNameProvider);

            if (!_removingRelationships.Any())
            {
                // nothing to do here, not removing any relationships
                return;
            }

            foreach (var removingRelationship in _removingRelationships)
            {
                foreach (object destinationNodeIdPropertyValue in removingRelationship.DestinationNodeIdPropertyValues)
                {
                    var existingForRemoving = existing.OutgoingRelationships
                                              .Where(er =>
                                                     er.outgoingRelationship.DestinationNode.Properties[
                                                         context.SyncNameProvider.IdPropertyName(
                                                             context.SyncNameProvider.GetContentTypeFromNodeLabels(
                                                                 er.outgoingRelationship.DestinationNode.Labels))] ==
                                                     destinationNodeIdPropertyValue);

                    var nonTwoWayIncomingRelationshipsToEmbeddedItems = existingForRemoving
                                                                        .SelectMany(or => or.incomingRelationships) //todo: null or throws?
                                                                        .Where(ir => !ir.Relationship.Properties.ContainsKey(
                                                                                   NodeWithOutgoingRelationshipsCommand.TwoWayRelationshipPropertyName));

                    allowSync.AddSyncBlockers(
                        nonTwoWayIncomingRelationshipsToEmbeddedItems.Select(r =>
                    {
                        string contentType =
                            context.SyncNameProvider.GetContentTypeFromNodeLabels(r.DestinationNode.Labels);
                        return(new SyncBlocker(
                                   contentType,
                                   r.DestinationNode.Properties[context.SyncNameProvider.IdPropertyName(contentType)],
                                   (string?)r.DestinationNode.Properties[TitlePartGraphSyncer.NodeTitlePropertyName]));
                    }));
                }
            }
        }
 public override Task AllowSync(JObject content, IGraphMergeContext context, IAllowSync allowSync)
 {
     return(Task.WhenAll(
                base.AllowSync(content, context, allowSync),
                _contentFieldsGraphSyncer.AllowSync(content, context, allowSync)));
 }
Ejemplo n.º 22
0
        public async Task AddSyncComponents(JObject contentItemField, IGraphMergeContext context)
        {
            //todo: share code with contentpickerfield?

            //todo: better error message to user if taxonomy is missing
            //todo: check for null
            ContentItem?taxonomyContentItem = await GetTaxonomyContentItem(
                contentItemField, context.ContentItemVersion, context.ContentManager);

            JObject taxonomyPartContent = taxonomyContentItem !.Content[nameof(TaxonomyPart)];
            string  termContentType     = taxonomyPartContent[TermContentType] !.Value <string>();

            string termRelationshipType = TermRelationshipType(termContentType);

            //todo requires 'picked' part has a graph sync part
            // add to docs & handle picked part not having graph sync part or throw exception

            JArray?contentItemIdsJArray = (JArray?)contentItemField[TermContentItemIds];

            if (contentItemIdsJArray == null || !contentItemIdsJArray.HasValues)
            {
                return; //todo:
            }
            IEnumerable <string> contentItemIds = contentItemIdsJArray.Select(jtoken => jtoken.ToObject <string>() !);

            ISyncNameProvider relatedSyncNameProvider = _serviceProvider.GetSyncNameProvider(termContentType);

            var flattenedTermsContentItems = GetFlattenedTermsContentItems(taxonomyPartContent);

            IEnumerable <object> foundDestinationNodeIds = contentItemIds.Select(tid =>
                                                                                 GetNodeId(tid, flattenedTermsContentItems, relatedSyncNameProvider, context.ContentItemVersion) !);

            IEnumerable <string> destNodeLabels = await relatedSyncNameProvider.NodeLabels();

            context.ReplaceRelationshipsCommand.AddRelationshipsTo(
                termRelationshipType,
                null,
                destNodeLabels,
                relatedSyncNameProvider !.IdPropertyName(),
                foundDestinationNodeIds.ToArray());

            // add relationship to taxonomy
            string taxonomyRelationshipType = TaxonomyRelationshipType(taxonomyContentItem);

            relatedSyncNameProvider.ContentType = taxonomyContentItem.ContentType;
            destNodeLabels = await relatedSyncNameProvider.NodeLabels();

            object taxonomyIdValue = relatedSyncNameProvider.GetNodeIdPropertyValue(
                taxonomyContentItem.Content[nameof(GraphSyncPart)], context.ContentItemVersion);

            context.ReplaceRelationshipsCommand.AddRelationshipsTo(
                taxonomyRelationshipType,
                null,
                destNodeLabels,
                relatedSyncNameProvider !.IdPropertyName(),
                taxonomyIdValue);

            // add tagnames
            //using var _ = s  yncNameProvider.PushPropertyNameTransform(_taxonomyPropertyNameTransform);

            //todo: this is there sometimes, but not others (Tag editor is selected and/or non-unique?)
            // find out when it should be there: need to know to know how to validate it
            //context.MergeNodeCommand.AddArrayProperty<string>(TaxonomyTermsNodePropertyName, contentItemField, TagNames);

            //todo: need to store location as string, e.g. "/contact-us"
            // could alter flatten to also include parent and work backwards
            // or do a search, recording the path
        }
Ejemplo n.º 23
0
 public override Task AddSyncComponents(JObject content, IGraphMergeContext context)
 {
     return(_contentFieldsGraphSyncer.AddSyncComponents(content, context));
 }
 public Task AddSyncComponentsDetaching(IGraphMergeContext context)
 {
     return(AddSyncComponents(context));
 }
Ejemplo n.º 25
0
 public override async Task AllowSync(JObject content, IGraphMergeContext context, IAllowSync allowSync)
 {
     await _contentFieldsGraphSyncer.AllowSync(content, context, allowSync);
 }
Ejemplo n.º 26
0
 public override async Task AddSyncComponents(JObject content, IGraphMergeContext context)
 {
     await _contentFieldsGraphSyncer.AddSyncComponents(content, context);
 }
        public override Task AddSyncComponents(JObject content, IGraphMergeContext context)
        {
            context.MergeNodeCommand.AddProperty <string>(NodeAliasPropertyName, content, _contentAliasPropertyName);

            return(Task.CompletedTask);
        }
Ejemplo n.º 28
0
 public async Task AddSyncComponentsForNonLeafEmbeddedTerm(JObject content, IGraphMergeContext context)
 {
     _embeddedContentItemsGraphSyncer.IsNonLeafEmbeddedTerm = true;
     await _embeddedContentItemsGraphSyncer.AddSyncComponents((JArray?)content[ContainerName], context);
 }
        public async Task AddSyncComponents(JObject contentItemField, IGraphMergeContext context)
        {
            string nodePropertyName = await context.SyncNameProvider.PropertyName(context.ContentPartFieldDefinition !.Name);

            context.MergeNodeCommand.AddProperty <bool>(nodePropertyName, contentItemField, ContentKey);
        }
 public async Task AddSyncComponentsDetaching(IGraphMergeContext context)
 {
     await AddSyncComponents(context);
 }