예제 #1
0
        public async static Task <TResult> CreateAsync <TResult>(Guid processStageId, Guid actorId,
                                                                 Guid processStageTypeId, string title,
                                                                 Guid[] viewableActorIds, Guid[] editableActorIds, Guid[] completableActorIds,
                                                                 KeyValuePair <Guid[], Guid>[] confirmableActorIdsNexts,
                                                                 Func <TResult> onCreated,
                                                                 Func <TResult> onAlreadyExists,
                                                                 Func <TResult> onTypeDoesNotExist,
                                                                 Func <Guid, TResult> onStageDoesNotExist,
                                                                 Func <TResult> onActorDoesNotExist,
                                                                 Func <string, TResult> onFailure)
        {
            return(await await ProcessStageTypes.FindIdAsync(processStageTypeId,
                                                             async (stageType) =>
            {
                var computedTitle = title.IsNullOrWhiteSpace() ?
                                    stageType.title
                        :
                                    title;

                // TODO: Validate the stage
                // TODO: Validate the actors
                return await await Persistence.ProcessStageDocument.FindByIdsAsync(
                    confirmableActorIdsNexts.Select(confirmableActorIdsNext => confirmableActorIdsNext.Value),
                    async(confirmableNextStages, missingNextStageIds) =>
                {
                    if (missingNextStageIds.Any())
                    {
                        return onStageDoesNotExist(missingNextStageIds.First());
                    }

                    return await Persistence.ProcessStageDocument.CreateAsync(processStageId, actorId,
                                                                              processStageTypeId, computedTitle,
                                                                              confirmableActorIdsNexts, editableActorIds, viewableActorIds,
                                                                              onCreated,
                                                                              onAlreadyExists);
                });
            },
                                                             () => onTypeDoesNotExist().ToTask()));
        }
예제 #2
0
        public static async Task <TResult> CreateAsync <TResult>(Guid processId,
                                                                 Guid processStageId, Guid resourceId, DateTime createdOn,
                                                                 KeyValuePair <string, Guid>[] resourceIds,
                                                                 Guid?previousStepId, DateTime?confirmedWhen, Guid?confirmedBy,
                                                                 EastFive.Api.Security security,
                                                                 Func <TResult> onCreated,
                                                                 Func <TResult> onAlreadyExists,
                                                                 Func <TResult> onStageDoesNotExist,
                                                                 Func <string, TResult> onFailure)
        {
            return(await await Persistence.ProcessStageDocument.FindByIdAsync(processStageId,
                                                                              async stage =>
            {
                return await await ProcessStageTypes.FindIdAsync(stage.processStageTypeId,
                                                                 async(stageType) =>
                {
                    var resourceType = stageType.resourceType;

                    return await stageType.resourceKeys
                    .FlatMap(resourceIds.ToDictionary(),
                             async(kvp, unusedResourceKvps, next, skip, tail) =>
                    {
                        if (!unusedResourceKvps.ContainsKey(kvp.Key))
                        {
                            if (confirmedWhen.HasValue)
                            {
                                return await tail(onFailure($"Missing resource for `{kvp.Key}`").ToTask());
                            }
                            return await skip(unusedResourceKvps);
                        }
                        return await next(
                            new Process.ProcessStageResource()
                        {
                            key = kvp.Key,
                            resourceId = unusedResourceKvps[kvp.Key],
                            type = kvp.Value,
                        },
                            unusedResourceKvps
                            .Where(kvpR => kvpR.Key != kvp.Key)
                            .ToDictionary());
                    },
                             async(Process.ProcessStageResource[] procStageResources, Dictionary <string, Guid> unusedResourceIds) =>
                    {
                        if (unusedResourceIds.Any())
                        {
                            return onFailure($"`{unusedResourceIds.First().Key}` is not valid resource key for a stage of type `{stageType.processStageTypeId}`");
                        }

                        var applicableActors = stage.completableIds
                                               .Concat(stage.confirmableIds.SelectKeys().SelectMany())
                                               .Concat(stage.editableIds).Concat(stage.viewableIds)
                                               .Distinct()
                                               .ToArray();

                        if (previousStepId.HasValue)
                        {
                            return await await Persistence.ProcessDocument.FindByIdAsync(previousStepId.Value,
                                                                                         async previousStep =>
                            {
                                if (!(previousStep.confirmedBy.HasValue && previousStep.confirmedWhen.HasValue))
                                {
                                    return onFailure("Previous step has not been confirmed.");
                                }

                                //TODO: if(previousStep.nextStep.HasValue)

                                return await Persistence.ProcessDocument.CreateAsync(processId,
                                                                                     processStageId, stage.ownerId,
                                                                                     resourceId, resourceType, createdOn,
                                                                                     procStageResources,
                                                                                     previousStepId, confirmedWhen, confirmedBy,
                                                                                     applicableActors,
                                                                                     onCreated,
                                                                                     onAlreadyExists);
                            },
                                                                                         () => onFailure("Previous step does not exist").ToTask());
                        }

                        // TODO: If confirmed is set, ensure that the security actor posesses a position that is authorized to move the process forward
                        return await Persistence.ProcessDocument.CreateAsync(processId,
                                                                             processStageId, stage.ownerId,
                                                                             resourceId, resourceType, createdOn,
                                                                             procStageResources,
                                                                             previousStepId, confirmedWhen, confirmedBy,
                                                                             applicableActors,
                                                                             onCreated,
                                                                             onAlreadyExists);
                    });
                },
                                                                 onStageDoesNotExist.AsAsyncFunc());
            },
                                                                              onStageDoesNotExist.AsAsyncFunc()));
        }
예제 #3
0
        public async static Task <TResult> FindByResourceAsync <TResult>(Guid actorId, Type resourceType,
                                                                         EastFive.Api.Security security,
                                                                         Func <ProcessResourceView[], TResult> onFound,
                                                                         Func <TResult> onResourceNotFound,
                                                                         Func <TResult> onUnauthorized)
        {
            return(await await Persistence.ProcessDocument.FindAllInFlowByActorAsync(actorId, resourceType,
                                                                                     (processSteps) =>
            {
                return processSteps
                .Select(ps => ps.processStageId)
                .Distinct()
                .FlatMap(
                    async(processStageId, next, skip) => await await Persistence.ProcessStageDocument.FindByIdAsync <Task <TResult> >(processStageId,
                                                                                                                                      processStage => next(processStageId.PairWithValue(processStage)),
                                                                                                                                      () => skip()),
                    (IEnumerable <KeyValuePair <Guid, ProcessStage> > processStages) =>
                {
                    var processStageLookup = processStages.ToDictionary();
                    return processStages
                    .SelectValues(stage => stage.processStageTypeId)
                    .Distinct()
                    .FlatMap <Guid, Guid[], KeyValuePair <Guid, ProcessStageType>, Task <TResult> >(
                        new Guid[] { },
                        async(processStageTypeId, kvpsAggr, next, skip) => await await ProcessStageTypes.FindIdAsync(processStageTypeId,
                                                                                                                     stageType => next(processStageTypeId.PairWithValue(stageType), kvpsAggr),
                                                                                                                     () => skip(kvpsAggr.Append(processStageTypeId).ToArray())),
                        async(KeyValuePair <Guid, ProcessStageType>[] stageTypes, Guid[] missingValues) =>
                    {
                        var processStageTypeLookup = stageTypes.ToDictionary();
                        return processSteps
                        .GroupBy(processStep => processStep.resourceId)
                        .FlatMap(
                            (stepsUnordered, next, skip) =>
                        {
                            var steps = stepsUnordered
                                        .OrderWith(default(Guid?),
                                                   (carry, step) => step.previousStep == carry,
                                                   step => step.processId)
                                        .ToArray();
                            if (!steps.Any())
                            {
                                return skip();
                            }
                            var viewableSteps = steps
                                                .Where(step => processStageLookup[step.processStageId].viewableIds.Contains(actorId))
                                                .ToArray();
                            var activeStep = viewableSteps.Last();
                            var stage = processStageLookup[activeStep.processStageId];

                            var possibleResourceKeys = viewableSteps
                                                       .SelectMany(step => processStageTypeLookup[processStageLookup[step.processStageId].processStageTypeId].resourceKeys.SelectKeys())
                                                       .Distinct()
                                                       .Select(
                                key => key.PairWithValue(new Process.ProcessStageResource
                            {
                                key = key,
                                type = processStageTypeLookup.SelectValues().First(
                                    (v, nextStageType) =>
                                {
                                    return v.resourceKeys.First(
                                        (v2, nextKey) =>
                                    {
                                        if (v2.Key == key)
                                        {
                                            return v2.Value;
                                        }
                                        return nextKey();
                                    },
                                        () => nextStageType());
                                },
                                    () => default(Type)),
                            }))
                                                       .ToDictionary();

                            try
                            {
                                var view = new ProcessResourceView()
                                {
                                    processViewId = activeStep.processId,
                                    resourceId = activeStep.resourceId,
                                    actorId = actorId,
                                    currentProcessStepId = activeStep.processId,
                                    titles = viewableSteps
                                             .Select(step => processStageLookup[step.processStageId].title)
                                             .ToArray(),
                                    completions = viewableSteps
                                                  .Select(step => step.confirmedWhen)
                                                  .ToArray(),
                                    invalidations = viewableSteps
                                                    .Select(step => step.invalidatedWhen)
                                                    .ToArray(),
                                    resourceType = resourceType,
                                    resourcesProvided = steps
                                                        .Where(step => step.confirmedWhen.HasValue)
                                                        .Aggregate(
                                        possibleResourceKeys,
                                        (aggr, step) =>
                                    {
                                        // TODO: This probably does not work
                                        foreach (var resource in step.resources)
                                        {
                                            // In case it is not a resource that is
                                            // referenced in a viewable step
                                            if (!aggr.ContainsKey(resource.key))
                                            {
                                                continue;
                                            }

                                            var aggrv = aggr[resource.key];
                                            if (resource.resourceId.HasValue)
                                            {
                                                aggrv.resourceId = resource.resourceId;
                                            }
                                            aggrv.type = resource.type;
                                        }
                                        return aggr;
                                    })
                                                        .SelectValues()
                                                        .ToArray(),
                                    nextStages = stage.confirmableIds
                                                 .Where(actorKvps => actorKvps.Key.Contains(actorId))
                                                 .Select(actorKvps => new ProcessStage()
                                    {
                                        // TODO: Rest of these values
                                        processStageId = actorKvps.Value,
                                    })
                                                 .ToArray(),
                                    displayResources = processStageLookup[activeStep.processStageId]
                                                       .resourcesDisplayed
                                                       .NullToEmpty()
                                                       .Intersect(possibleResourceKeys.SelectKeys())
                                                       .ToArray(),
                                    editable = processStageLookup[activeStep.processStageId].editableIds.Contains(actorId),
                                    completable = processStageLookup[activeStep.processStageId].completableIds.Contains(actorId),
                                };
                                return next(view);
                            } catch (Exception ex)
                            {
                                return skip();
                            }
                        },
                            (IEnumerable <ProcessResourceView> views) => onFound(views.ToArray()));
                    });
                });
            },
                                                                                     () => onFound(new ProcessResourceView[] { }).ToTask()));
        }