예제 #1
0
        private async Task <DomainId[]> FindIdAsync(BulkTask task)
        {
            var id = task.CommandJob.Id;

            if (id != null)
            {
                return(new[] { id.Value });
            }

            if (task.CommandJob.Query != null)
            {
                task.CommandJob.Query.Take = task.CommandJob.ExpectedCount;

                var existing = await contentQuery.QueryAsync(contextProvider.Context, task.Schema, Q.Empty.WithJsonQuery(task.CommandJob.Query));

                if (existing.Total > task.CommandJob.ExpectedCount)
                {
                    throw new DomainException(T.Get("contents.bulkInsertQueryNotUnique"));
                }

                if (existing.Count == 0 && task.CommandJob.Type == BulkUpdateContentType.Upsert)
                {
                    return(new[] { DomainId.NewGuid() });
                }

                return(existing.Select(x => x.Id).ToArray());
            }

            if (task.CommandJob.Type == BulkUpdateContentType.Create || task.CommandJob.Type == BulkUpdateContentType.Upsert)
            {
                return(new[] { DomainId.NewGuid() });
            }

            return(Array.Empty <DomainId>());
        }
예제 #2
0
        private AssetCommand CreateCommandCore(BulkTask task)
        {
            var job = task.CommandJob;

            switch (job.Type)
            {
            case BulkUpdateAssetType.Annotate:
            {
                var command = new AnnotateAsset();

                EnrichAndCheckPermission(task, command, Permissions.AppAssetsUpdate);
                return(command);
            }

            case BulkUpdateAssetType.Move:
            {
                var command = new MoveAsset();

                EnrichAndCheckPermission(task, command, Permissions.AppAssetsUpdate);
                return(command);
            }

            case BulkUpdateAssetType.Delete:
            {
                var command = new DeleteAsset();

                EnrichAndCheckPermission(task, command, Permissions.AppAssetsDelete);
                return(command);
            }

            default:
                throw new NotSupportedException();
            }
        }
예제 #3
0
        private void EnrichAndCheckPermission <T>(BulkTask task, T command, string permissionId) where T : AssetCommand
        {
            SimpleMapper.Map(task.Command, command);
            SimpleMapper.Map(task.CommandJob, command);

            if (!contextProvider.Context.Allows(permissionId))
            {
                throw new DomainForbiddenException("Forbidden");
            }

            command.ExpectedVersion = task.Command.ExpectedVersion;
        }
        private async Task <IEnumerable <BulkTaskCommand> > CreateCommandsAsync(BulkTask task)
        {
            var commands = new List <BulkTaskCommand>();

            try
            {
                var resolvedIds = await FindIdAsync(task);

                if (resolvedIds.Length == 0)
                {
                    throw new DomainObjectNotFoundException("undefined");
                }

                foreach (var id in resolvedIds)
                {
                    try
                    {
                        var command = await CreateCommandAsync(task);

                        command.ContentId = id;

                        commands.Add(new BulkTaskCommand(task, id, command));
                    }
                    catch (Exception ex)
                    {
                        task.Results.Add(new BulkUpdateResultItem
                        {
                            Id        = id,
                            JobIndex  = task.JobIndex,
                            Exception = ex
                        });
                    }
                }
            }
            catch (Exception ex)
            {
                task.Results.Add(new BulkUpdateResultItem
                {
                    JobIndex  = task.JobIndex,
                    Exception = ex
                });
            }

            return(commands);
        }
        private BulkTaskCommand?CreateCommand(BulkTask task)
        {
            var id = task.CommandJob.Id;

            try
            {
                var command = CreateCommandCore(task);

                command.AssetId = id;

                return(new BulkTaskCommand(task, id, command));
            }
            catch (Exception ex)
            {
                task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex));
                return(null);
            }
        }
예제 #6
0
        private async Task EnrichAndCheckPermissionAsync <T>(BulkTask task, T command, string permissionId) where T : ContentCommand
        {
            SimpleMapper.Map(task.Command, command);
            SimpleMapper.Map(task.CommandJob, command);

            if (!string.IsNullOrWhiteSpace(task.CommandJob.Schema))
            {
                var schema = await contentQuery.GetSchemaOrThrowAsync(contextProvider.Context, task.Schema);

                command.SchemaId = schema.NamedId();
            }

            if (!contextProvider.Context.Allows(permissionId, command.SchemaId.Name))
            {
                throw new DomainForbiddenException("Forbidden");
            }

            command.ExpectedVersion = task.Command.ExpectedVersion;
        }
        private async Task <IEnumerable <BulkTaskCommand> > CreateCommandsAsync(BulkTask task)
        {
            var commands = new List <BulkTaskCommand>();

            try
            {
                var resolvedIds = await FindIdAsync(task);

                if (resolvedIds.Length == 0)
                {
                    throw new DomainObjectNotFoundException("undefined");
                }

                foreach (var id in resolvedIds)
                {
                    try
                    {
                        var command = await CreateCommandAsync(task);

                        command.ContentId = id;

                        commands.Add(new BulkTaskCommand(task, id, command));
                    }
                    catch (Exception ex)
                    {
                        log.LogError(ex, w => w
                                     .WriteProperty("action", "BulkContent")
                                     .WriteProperty("status", "Failed")
                                     .WriteProperty("jobIndex", task.JobIndex)
                                     .WriteProperty("jobType", task.CommandJob.Type.ToString()));

                        task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex));
                    }
                }
            }
            catch (Exception ex)
            {
                task.Results.Add(new BulkUpdateResultItem(null, task.JobIndex, ex));
            }

            return(commands);
        }
예제 #8
0
        private async Task EnrichAsync <TCommand>(DomainId id, BulkTask task, TCommand command, string permissionId) where TCommand : ContentCommand
        {
            SimpleMapper.Map(task.Command, command);

            command.ContentId = id;

            if (!string.IsNullOrWhiteSpace(task.Job.Schema))
            {
                var schema = await contentQuery.GetSchemaOrThrowAsync(task.Context, task.Schema);

                command.SchemaId = schema.NamedId();
            }

            if (!task.Context.Allows(permissionId, command.SchemaId.Name))
            {
                throw new DomainForbiddenException("Forbidden");
            }

            command.ExpectedVersion = task.Command.ExpectedVersion;
        }
예제 #9
0
        private async Task <IEnumerable <BulkTaskCommand> > CreateCommandsAsync(BulkTask task)
        {
            var commands = new List <BulkTaskCommand>();

            try
            {
                var resolvedIds = await FindIdAsync(task);

                if (resolvedIds.Length == 0)
                {
                    throw new DomainObjectNotFoundException("undefined");
                }

                foreach (var id in resolvedIds)
                {
                    try
                    {
                        var command = await CreateCommandAsync(task);

                        command.ContentId = id;

                        commands.Add(new BulkTaskCommand(task, id, command));
                    }
                    catch (Exception ex)
                    {
                        log.LogError(ex, "Failed to execute content bulk job with index {index} of type {type}.",
                                     task.JobIndex,
                                     task.CommandJob.Type);

                        task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex));
                    }
                }
            }
            catch (Exception ex)
            {
                task.Results.Add(new BulkUpdateResultItem(null, task.JobIndex, ex));
            }

            return(commands);
        }
예제 #10
0
        private BulkTaskCommand?CreateCommand(BulkTask task)
        {
            var id = task.CommandJob.Id;

            try
            {
                var command = CreateCommandCore(task);

                command.AssetId = id;

                return(new BulkTaskCommand(task, id, command));
            }
            catch (Exception ex)
            {
                log.LogError(ex, "Faield to execute asset bulk job with index {index} of type {type}.",
                             task.JobIndex,
                             task.CommandJob.Type);

                task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex));
                return(null);
            }
        }
예제 #11
0
        private BulkTaskCommand?CreateCommand(BulkTask task)
        {
            var id = task.CommandJob.Id;

            try
            {
                var command = CreateCommandCore(task);

                command.AssetId = id;

                return(new BulkTaskCommand(task, id, command));
            }
            catch (Exception ex)
            {
                log.LogError(ex, w => w
                             .WriteProperty("action", "BulkContent")
                             .WriteProperty("status", "Failed")
                             .WriteProperty("jobIndex", task.JobIndex)
                             .WriteProperty("jobType", task.CommandJob.Type.ToString()));

                task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex));
                return(null);
            }
        }
예제 #12
0
        public async Task HandleAsync(CommandContext context, NextDelegate next)
        {
            if (context.Command is BulkUpdateContents bulkUpdates)
            {
                if (bulkUpdates.Jobs?.Length > 0)
                {
                    var executionOptions = new ExecutionDataflowBlockOptions
                    {
                        MaxDegreeOfParallelism = Math.Max(1, Environment.ProcessorCount / 2)
                    };

                    var createCommandsBlock = new TransformManyBlock <BulkTask, BulkTaskCommand>(async task =>
                    {
                        try
                        {
                            return(await CreateCommandsAsync(task));
                        }
                        catch (OperationCanceledException ex)
                        {
                            // Dataflow swallows operation cancelled exception.
                            throw new AggregateException(ex);
                        }
                    }, executionOptions);

                    var executeCommandBlock = new ActionBlock <BulkTaskCommand>(async command =>
                    {
                        try
                        {
                            await ExecuteCommandAsync(command);
                        }
                        catch (OperationCanceledException ex)
                        {
                            // Dataflow swallows operation cancelled exception.
                            throw new AggregateException(ex);
                        }
                    }, executionOptions);

                    createCommandsBlock.BidirectionalLinkTo(executeCommandBlock);

                    contextProvider.Context.Change(b => b
                                                   .WithoutContentEnrichment()
                                                   .WithoutCleanup()
                                                   .WithUnpublished(true)
                                                   .WithoutTotal());

                    var requestedSchema = bulkUpdates.SchemaId.Name;

                    var results = new ConcurrentBag <BulkUpdateResultItem>();

                    for (var i = 0; i < bulkUpdates.Jobs.Length; i++)
                    {
                        var task = new BulkTask(
                            context.CommandBus,
                            requestedSchema,
                            i,
                            bulkUpdates.Jobs[i],
                            bulkUpdates,
                            results);

                        if (!await createCommandsBlock.SendAsync(task))
                        {
                            break;
                        }
                    }

                    createCommandsBlock.Complete();

                    await executeCommandBlock.Completion;

                    context.Complete(new BulkUpdateResult(results));
                }
                else
                {
                    context.Complete(new BulkUpdateResult());
                }
            }
            else
            {
                await next(context);
            }
        }
예제 #13
0
 private sealed record BulkTaskCommand(BulkTask Task, DomainId Id, ICommand Command)
 {
 }
예제 #14
0
        private async Task <ContentCommand> CreateCommandAsync(BulkTask task)
        {
            var job = task.CommandJob;

            switch (job.Type)
            {
            case BulkUpdateContentType.Create:
            {
                var command = new CreateContent();

                await EnrichAndCheckPermissionAsync(task, command, Permissions.AppContentsCreate);

                return(command);
            }

            case BulkUpdateContentType.Update:
            {
                var command = new UpdateContent();

                await EnrichAndCheckPermissionAsync(task, command, Permissions.AppContentsUpdateOwn);

                return(command);
            }

            case BulkUpdateContentType.Upsert:
            {
                var command = new UpsertContent();

                await EnrichAndCheckPermissionAsync(task, command, Permissions.AppContentsUpsert);

                return(command);
            }

            case BulkUpdateContentType.Patch:
            {
                var command = new PatchContent();

                await EnrichAndCheckPermissionAsync(task, command, Permissions.AppContentsUpdateOwn);

                return(command);
            }

            case BulkUpdateContentType.Validate:
            {
                var command = new ValidateContent();

                await EnrichAndCheckPermissionAsync(task, command, Permissions.AppContentsReadOwn);

                return(command);
            }

            case BulkUpdateContentType.ChangeStatus:
            {
                var command = new ChangeContentStatus {
                    Status = job.Status ?? Status.Draft
                };

                await EnrichAndCheckPermissionAsync(task, command, Permissions.AppContentsChangeStatusOwn);

                return(command);
            }

            case BulkUpdateContentType.Delete:
            {
                var command = new DeleteContent();

                await EnrichAndCheckPermissionAsync(task, command, Permissions.AppContentsDeleteOwn);

                return(command);
            }

            default:
                throw new NotSupportedException();
            }
        }
        public async Task HandleAsync(CommandContext context, NextDelegate next)
        {
            if (context.Command is BulkUpdateAssets bulkUpdates)
            {
                if (bulkUpdates.Jobs?.Length > 0)
                {
                    var executionOptions = new ExecutionDataflowBlockOptions
                    {
                        MaxDegreeOfParallelism = Math.Max(1, Environment.ProcessorCount / 2)
                    };

                    var createCommandsBlock = new TransformBlock <BulkTask, BulkTaskCommand?>(task =>
                    {
                        return(CreateCommand(task));
                    }, executionOptions);

                    var executeCommandBlock = new ActionBlock <BulkTaskCommand?>(async command =>
                    {
                        if (command != null)
                        {
                            await ExecuteCommandAsync(command);
                        }
                    }, executionOptions);

                    createCommandsBlock.LinkTo(executeCommandBlock, new DataflowLinkOptions
                    {
                        PropagateCompletion = true
                    });

                    contextProvider.Context.Change(b => b
                                                   .WithoutAssetEnrichment()
                                                   .WithoutCleanup()
                                                   .WithUnpublished(true)
                                                   .WithoutTotal());

                    var results = new ConcurrentBag <BulkUpdateResultItem>();

                    for (var i = 0; i < bulkUpdates.Jobs.Length; i++)
                    {
                        var task = new BulkTask(
                            context.CommandBus,
                            i,
                            bulkUpdates.Jobs[i],
                            bulkUpdates,
                            results);

                        await createCommandsBlock.SendAsync(task);
                    }

                    createCommandsBlock.Complete();

                    await executeCommandBlock.Completion;

                    context.Complete(new BulkUpdateResult(results));
                }
                else
                {
                    context.Complete(new BulkUpdateResult());
                }
            }
            else
            {
                await next(context);
            }
        }
예제 #16
0
        private async Task <ICommand> CreateCommandAsync(DomainId id, BulkTask task)
        {
            var job = task.Job;

            switch (job.Type)
            {
            case BulkUpdateType.Create:
            {
                var command = new CreateContent {
                    Data = job.Data !
                };

                await EnrichAsync(id, task, command, Permissions.AppContentsCreate);

                return(command);
            }

            case BulkUpdateType.Update:
            {
                var command = new UpdateContent {
                    Data = job.Data !
                };

                await EnrichAsync(id, task, command, Permissions.AppContentsUpdateOwn);

                return(command);
            }

            case BulkUpdateType.Upsert:
            {
                var command = new UpsertContent {
                    Data = job.Data !
                };

                await EnrichAsync(id, task, command, Permissions.AppContentsUpsert);

                return(command);
            }

            case BulkUpdateType.Patch:
            {
                var command = new PatchContent {
                    Data = job.Data !
                };

                await EnrichAsync(id, task, command, Permissions.AppContentsUpdateOwn);

                return(command);
            }

            case BulkUpdateType.Validate:
            {
                var command = new ValidateContent();

                await EnrichAsync(id, task, command, Permissions.AppContentsReadOwn);

                return(command);
            }

            case BulkUpdateType.ChangeStatus:
            {
                var command = new ChangeContentStatus {
                    Status = job.Status, DueTime = job.DueTime
                };

                await EnrichAsync(id, task, command, Permissions.AppContentsUpdateOwn);

                return(command);
            }

            case BulkUpdateType.Delete:
            {
                var command = new DeleteContent();

                await EnrichAsync(id, task, command, Permissions.AppContentsDeleteOwn);

                return(command);
            }

            default:
                throw new NotSupportedException();
            }
        }