public static Task <TResult> CreateAsync <TResult>(Guid processStageId, Guid actorId, Guid processStageTypeId, string title, Guid[] viewableActorIds, Guid[] editableActorIds, Guid [] completableActorIds, KeyValuePair <Guid[], Guid>[] confirmableActorIdsNexts, EastFive.Api.Security security, Func <TResult> onCreated, Func <TResult> onAlreadyExists, Func <TResult> onTypeDoesNotExist, Func <Guid, TResult> onConfirmationStageDoesNotExist, Func <TResult> onActorDoesNotExist, Func <string, TResult> onFailure) { // TODO: Security return(ProcessStages.CreateAsync(processStageId, actorId, processStageTypeId, title, viewableActorIds, editableActorIds, completableActorIds, confirmableActorIdsNexts, onCreated, onAlreadyExists, onTypeDoesNotExist, onConfirmationStageDoesNotExist, onActorDoesNotExist, onFailure)); }
public static Task <IHttpResponse> FindByIdAsync( [QueryParameter(CheckFileName = true)] Guid id, EastFive.Api.Security security, ContentResponse onFound, NotFoundResponse onNotFound, UnauthorizedResponse onUnauthorized) { return(stages.First( async(stage, next) => { if (stage.Id.UUID == id) { return onFound(stage); } return await next(); }, () => onNotFound().ToTask())); //return Connectors.FindByIdAsync(id, // security.performingAsActorId, security.claims, // (synchronization, destinationIntegrationId) => onFound(GetResource(synchronization, destinationIntegrationId, url)), // () => onNotFound(), // () => onUnauthorized()); }
public static Task <HttpResponseMessage> FindAllAsync( EastFive.Api.Security security, HttpRequestMessage request, UrlHelper url, MultipartAcceptArrayResponseAsync onMultipart) { return(onMultipart(stages)); }
public static IHttpResponse FindAll( EastFive.Api.Security security, MultipartAcceptArrayResponse onMultipart) { return(onMultipart(stages)); }
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())); }
internal static Task <TResult> UpdateAsync <TResult>(Guid processId, Guid?confirmedById, DateTime?confirmedWhen, KeyValuePair <string, Guid>[] resources, EastFive.Api.Security security, Func <TResult> onUpdated, Func <TResult> onNotFound, Func <TResult> onUnauthorized, Func <string, TResult> onFailure) { return(Persistence.ProcessDocument.UpdateAsync(processId, async(process, saveAsync) => { return await await Persistence.ProcessStageDocument.FindByIdAsync(process.processStageId, async processStage => await await Persistence.ProcessStageTypeDocument.FindByIdAsync(processStage.processStageTypeId, processStageType => { process.confirmedBy = confirmedById; process.confirmedWhen = confirmedWhen; return resources .FlatMap( (resourceKvp, nextProcessStageResource, skip, tail) => processStageType.resourceKeys .First( (kvp, next) => kvp.Key == resourceKvp.Key ? nextProcessStageResource( new Process.ProcessStageResource() { key = resourceKvp.Key, resourceId = resourceKvp.Value, type = kvp.Value, }) : next(), () => tail(onFailure($"Resource key ${resourceKvp.Key} is not valid for this stage.").ToTask())), async(IEnumerable <Process.ProcessStageResource> psrs) => { var procStageResources = psrs.ToArray(); if (procStageResources.Length != processStageType.resourceKeys.Length) { if (confirmedWhen.HasValue || process.confirmedWhen.HasValue) { return onFailure($"Cannot confirm resource without `{processStageType.resourceKeys.SelectKeys().Except(procStageResources.Select(psr => psr.key)).Join(",")}`"); } } process.resources = procStageResources; await saveAsync(process); return onUpdated(); }); }, () => onFailure($"Process stage is no longer valid `{process.processStageId}` => `{processStage.processStageTypeId}`").ToTask()), () => onFailure($"Process is no longer valid `{processId}` => `{process.processStageId}`").ToTask()); }, onNotFound)); }
public static Task <TResult> FindAllAsync <TResult>(EastFive.Api.Security security, Func <ProcessStageType[], TResult> onFound, Func <TResult> onUnauthorized) { return(Persistence.ProcessStageTypeDocument.FindAllAsync(onFound)); }
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())); }
public static async Task <TResult> FindStartByActorAndResourceTypeAsync <TResult>(Guid ownerId, Type resourceType, EastFive.Api.Security security, Func <ProcessStage[], TResult> onFound, Func <TResult> onResourceNotFound, Func <TResult> onUnauthorized) { return(await await Persistence.ProcessStageDocument.FindByOwnerAsync(ownerId, async (processStages) => { var typeIds = await processStages .Select(processStage => processStage.processStageTypeId) .Distinct() .FlatMap( async(processStageTypeId, add, skip) => await await Persistence.ProcessStageTypeDocument.FindByIdAsync(processStageTypeId, processStageTypeDoc => processStageTypeDoc.resourceType == resourceType ? add(processStageTypeId) : skip(), () => skip()), (IEnumerable <Guid> processStageTypeIds) => processStageTypeIds.ToLookup(v => v).ToTask()); var listedAsNext = processStages.SelectMany(procStage => procStage.confirmableIds.SelectValues()).ToLookup(v => v); return onFound( processStages .Where(procStage => typeIds.Contains(procStage.processStageTypeId)) .Where(procStage => !listedAsNext.Contains(procStage.processStageId)) .ToArray()); }, onResourceNotFound.AsAsyncFunc())); }