//todo: don't want to do this for embedded items private async Task <IEnumerable <INodeWithOutgoingRelationships> > GetIncomingPreviewContentPickerRelationshipsWhenPublishing( IGraphReplicaSet graphReplicaSet, dynamic graphSyncPartContent, string contentItemId) { // we only need to recreate incoming relationships // if we're publishing and there isn't currently a published version if (graphReplicaSet.Name != GraphReplicaSetNames.Published || await _contentItemsService.HasExistingPublishedVersion(contentItemId)) { return(Enumerable.Empty <INodeWithOutgoingRelationships>()); } // allow sync is called concurrently for preview and published // so we could get the before or after incoming relationships // either should do, but perhaps we should do it serially to consistently fetch the _before_ incoming relationships? IGetIncomingContentPickerRelationshipsQuery getDraftRelationshipsQuery = _serviceProvider.GetRequiredService <IGetIncomingContentPickerRelationshipsQuery>(); getDraftRelationshipsQuery.NodeLabels = MergeNodeCommand.NodeLabels; getDraftRelationshipsQuery.IdPropertyName = MergeNodeCommand.IdPropertyName; getDraftRelationshipsQuery.IdPropertyValue = _syncNameProvider.GetNodeIdPropertyValue( graphSyncPartContent, _previewContentItemVersion); IEnumerable <INodeWithOutgoingRelationships?> incomingContentPickerRelationshipsOrDefault = await _graphCluster.Run(_previewContentItemVersion.GraphReplicaSetName, getDraftRelationshipsQuery); #pragma warning disable S1905 // Sonar needs updating to know about nullable references return(incomingContentPickerRelationshipsOrDefault .Where(n => n != null) .Cast <INodeWithOutgoingRelationships>()); #pragma warning restore S1905 }
public GraphMergeContext( IMergeGraphSyncer mergeGraphSyncer, ISyncNameProvider syncNameProvider, IGraphReplicaSet graphReplicaSet, IMergeNodeCommand mergeNodeCommand, IReplaceRelationshipsCommand replaceRelationshipsCommand, ContentItem contentItem, IContentManager contentManager, IContentItemVersionFactory contentItemVersionFactory, IGraphMergeContext?parentGraphMergeContext, IServiceProvider serviceProvider) : base( contentItem, syncNameProvider, contentManager, contentItemVersionFactory.Get(graphReplicaSet.Name), parentGraphMergeContext, serviceProvider.GetRequiredService <ILogger <GraphMergeContext> >()) { MergeGraphSyncer = mergeGraphSyncer; GraphReplicaSet = graphReplicaSet; MergeNodeCommand = mergeNodeCommand; ReplaceRelationshipsCommand = replaceRelationshipsCommand; ExtraCommands = new List <ICommand>(); }
private async Task Sync(IEnumerable <ContentItem> contentItems, IGraphReplicaSet graphReplicaSet) { foreach (ContentItem contentItem in contentItems) { IMergeGraphSyncer mergeGraphSyncer = _serviceProvider.GetRequiredService <IMergeGraphSyncer>(); //todo: we need to better handle disallowed and failed syncs // can we cancel the part/field detachment? //todo: support many items being updated in a transaction await mergeGraphSyncer.SyncToGraphReplicaSetIfAllowed(graphReplicaSet, contentItem, _contentManager); } }
public async Task <IAllowSync> SyncToGraphReplicaSetIfAllowed( IGraphReplicaSet graphReplicaSet, ContentItem contentItem, IContentManager contentManager, IGraphMergeContext?parentGraphMergeContext = null) { IAllowSync allowSync = await SyncAllowed(graphReplicaSet, contentItem, contentManager, parentGraphMergeContext); if (allowSync.Result == AllowSyncResult.Allowed) { await SyncToGraphReplicaSet(); } return(allowSync); }
public async Task <IAllowSync> SyncAllowed( IGraphReplicaSet graphReplicaSet, ContentItem contentItem, IContentManager contentManager, IGraphMergeContext?parentGraphMergeContext = null) { _logger.LogDebug("SyncAllowed to {GraphReplicaSetName} for '{ContentItem}' {ContentType}?", graphReplicaSet.Name, contentItem.ToString(), contentItem.ContentType); _logger.LogDebug("ContentItem content: {Content}", ((JObject)contentItem.Content).ToString()); // we use the existence of a GraphSync content part as a marker to indicate that the content item should be synced JObject?graphSyncPartContent = (JObject?)contentItem.Content[nameof(GraphSyncPart)]; if (graphSyncPartContent == null) { return(AllowSync.NotRequired); } //todo: ContentType belongs in the context, either combine helper & context, or supply context to helper? _syncNameProvider.ContentType = contentItem.ContentType; _graphMergeContext = new GraphMergeContext( this, _syncNameProvider, graphReplicaSet, MergeNodeCommand, _replaceRelationshipsCommand, contentItem, contentManager, _contentItemVersionFactory, parentGraphMergeContext, _serviceProvider); await PopulateMergeNodeCommand(graphSyncPartContent); SetSourceNodeInReplaceRelationshipsCommand(); //should it go in the context? _incomingPreviewContentPickerRelationships = await GetIncomingPreviewContentPickerRelationshipsWhenPublishing( graphReplicaSet, graphSyncPartContent, contentItem.ContentItemId); return(await SyncAllowed()); }
private async Task AttemptMergeRepair( ContentTypeDefinition contentTypeDefinition, IContentItemVersion contentItemVersion, ValidateAndRepairResult result, ValidationFailure failure) { var mergeGraphSyncer = _serviceProvider.GetRequiredService <IMergeGraphSyncer>(); IGraphReplicaSet graphReplicaSet = _currentGraph !.GetReplicaSetLimitedToThisGraph(); try { await mergeGraphSyncer.SyncToGraphReplicaSetIfAllowed(graphReplicaSet, failure.ContentItem, _contentManager); } catch (Exception ex) { _logger.LogWarning(ex, "Repair of {ContentItem} in {GraphReplicaSet} failed.", failure.ContentItem, graphReplicaSet); } (bool validated, string?validationFailureReason) = await ValidateContentItem(failure.ContentItem, contentTypeDefinition, contentItemVersion); if (validated) { _logger.LogInformation("Repair was successful on {ContentType} {ContentItemId} in {CurrentGraph}.", failure.ContentItem.ContentType, failure.ContentItem.ContentItemId, GraphDescription(_currentGraph !)); result.Repaired.Add(new ValidatedContentItem(failure.ContentItem)); } else { string message = $"Repair was unsuccessful.{Environment.NewLine}{{ValidationFailureReason}}."; _logger.LogWarning(message, validationFailureReason); result.RepairFailures.Add(new RepairFailure(failure.ContentItem, validationFailureReason !)); } }