private async Task <Core.Models.Execution> ToExecutionAsync(ExecutionRequestContext <ExecutionRequestApiModel> erContext) => new Core.Models.Execution { CreatedDateTimeUtc = DateTime.UtcNow, ExecutionId = erContext.ExtensionVersion.CreateNewExecutionId(userContext.Executor.TenantId), ExecutionModelName = erContext.ExecutionProfile.ExecutionModelName, ExecutionProfileName = erContext.ExecutionProfile.ProfileName, Executor = userContext.Executor, ExtensionId = erContext.Extension.ExtensionId, ExtensionVersionId = erContext.ExtensionVersion.ExtensionVersionId, LastUpdatedDateTimeUtc = DateTime.UtcNow, ObjectProviderName = erContext.ExecutionProfile.ObjectProviderName, Priority = Enum.Parse <ExecutionPriority>(erContext.OriginalRequest.Priority), StatusUpdateKey = Guid.NewGuid().ToString(), ValidateOnly = erContext.OriginalRequest.ValidateOnly, InputObjects = erContext.ExtensionVersion.InputObjects, OutputObjects = erContext.ExtensionVersion.OutputObjects, RequestData = erContext.OriginalRequest.RequestData, Mode = erContext.ExecutionProfile.ExecutionMode, SignatureRsaKeyXml = await extensionRsaKeyProvider.GetExtensionRsaKeyXmlAsync(erContext.Extension), ExecutorProperties = erContext.OriginalRequest.ExecutorProperties };
public async Task <ExecutionRequestContext <ExecutionRequestApiModel> > BuildExecutionRequestContextAsync(ExecutionRequestApiModel apiExecRequest) { // Create a new execution request context... var erContext = new ExecutionRequestContext <ExecutionRequestApiModel>(apiExecRequest); // Did they provide an extension ID? if (string.IsNullOrEmpty(apiExecRequest.ExtensionId)) { erContext.ValidationErrors.Add($"[{ErrorCodes.ExtensionIdNotProvided}]: [extensionId] is required."); } // Did they provide an extension version ID? if (string.IsNullOrEmpty(apiExecRequest.ExtensionVersionId)) { erContext.ValidationErrors.Add($"[{ErrorCodes.ExtensionVersionIdNotProvided}]: [extensionVersionId] is required."); } // Is the execution priority that they provided valid? if (Enum.TryParse <ExecutionPriority>(apiExecRequest.Priority, out var execPriority) == false) { erContext.ValidationErrors.Add($"[{ErrorCodes.InvalidPriority}]: [{apiExecRequest.Priority}] is not a valid [priority]; " + $"valid priorities are [{ExecutionPriority.Low}], [{ExecutionPriority.Normal}], " + $"and [{ExecutionPriority.High}]; if no [priority] is explicitly provided, " + $"[{ExecutionPriority.Normal}] is automatically selected."); } if (string.IsNullOrEmpty(apiExecRequest.ExtensionId) == false) { // Get the extension information... erContext.Extension = await extensionRepository.GetExtensionAsync(apiExecRequest.ExtensionId); // Were we able to find the extension and is it active? if (erContext.Extension == null) { erContext.ValidationErrors.Add($"[{ErrorCodes.ExtensionNotFound}]: Extension [{apiExecRequest.ExtensionId}] not found."); } else if (erContext.Extension.IsActive == false) { erContext.ValidationErrors.Add($"[{ErrorCodes.ExtensionDisabled}]: Extension [{apiExecRequest.ExtensionId}] is currently unavailable."); } else if (string.IsNullOrEmpty(apiExecRequest.ExtensionVersionId) == false) { // Get the extension version information... erContext.ExtensionVersion = erContext.Extension.GetExtensionVersion(apiExecRequest.ExtensionVersionId); // Were we able to find the extension version and is it active? if (erContext.ExtensionVersion == null) { erContext.ValidationErrors.Add($"[{ErrorCodes.ExtensionVersionNotFound}]: Extension [{apiExecRequest.ExtensionId}] version " + $"[{apiExecRequest.ExtensionVersionId}] not found."); } else if (erContext.ExtensionVersion.IsActive == false) { erContext.ValidationErrors.Add($"[{ErrorCodes.ExtensionVersionDisabled}]: Extension [{apiExecRequest.ExtensionId}] version " + $"[{apiExecRequest.ExtensionVersionId}] is currently unavailable."); } else { // If the user has only requested validation (not execution), does the extension version support validation? if (apiExecRequest.ValidateOnly && erContext.ExtensionVersion.SupportsValidation == false) { erContext.ValidationErrors.Add($"[{ErrorCodes.ExtensionVersionDoesNotSupportValidation}]: " + $"Extension [{apiExecRequest.ExtensionId}] version " + $"[{apiExecRequest.ExtensionVersionId}] does not support validation."); } // Get the execution profile information... erContext.ExecutionProfile = erContext.ExtensionVersion.GetExecutionProfile(apiExecRequest.ProfileName); // Were we able to find the execution profile information? if (erContext.ExecutionProfile == null) { erContext.ValidationErrors.Add($"[{ErrorCodes.ExecutionProfileNotFound}]: " + $"Execution profile [{apiExecRequest.ProfileName}] not found."); } else { // And, finally, is the specified priority supported by the execution profile? if (erContext.ExecutionProfile.SupportedPriorities.HasFlag(execPriority) == false) { erContext.ValidationErrors.Add($"[{ErrorCodes.PriorityNotSupported}]: " + $"Execution profile [{apiExecRequest.ProfileName}] does not support " + $"[{execPriority}]-priority execution."); } } } } } return(erContext); }
public async Task <IActionResult> ContinueExecutionAsync([Required] string executionId, [Required, FromBody] ContinueExecutionApiModel continueApiModel) { // Build the execution request context so we can pick up where we left off... var erContext = new ExecutionRequestContext <ContinueExecutionApiModel>(continueApiModel) { Execution = await execRepository.GetExecutionAsync(executionId, userContext.Executor.TenantId) }; // If we can't find the original execution, respond with [404 Not Found]... if (erContext.Execution == null) { return(NotFound($"[{ErrorCodes.ExecutionNotFound}]: Execution [{executionId}] not found.")); } // If we found the execution but we're not expecting any input objects, respond with [400 Bad Request]... if (erContext.Execution.Status != ExecutionStatus.PendingInputObjects) { return(BadRequest($"[{ErrorCodes.UnableToContinue}]: Unable to continue; " + $"execution [{executionId}] is already [{erContext.Execution.Status}].")); } // Augment the execution request context with extension, extension version, and execution profile. // We're going to need all of this information to build and dispatch the core execution request... erContext.Extension = await extensionRepository.GetExtensionAsync(erContext.Execution.ExtensionId); erContext.ExtensionVersion = erContext.Extension.GetExtensionVersion(erContext.Execution.ExtensionVersionId); erContext.ExecutionProfile = erContext.ExtensionVersion.GetExecutionProfile(erContext.Execution.ExecutionProfileName); // Make sure that we have the right input objects and only the right input objects... erContext.Execution.ProvidedInputObjects.AddRange(erContext.OriginalRequest.ProvidedInputObjects.Where(pio => erContext.ExtensionVersion.InputObjects.Any(io => io.Name == pio) && erContext.Execution.ProvidedInputObjects.Contains(pio) == false)); var unknownObjects = erContext.OriginalRequest.ProvidedInputObjects .Where(pio => erContext.Execution.InputObjects.Select(io => io.Name).Contains(pio) == false) .ToArray(); var neededObjects = erContext.Execution.InputObjects .Where(io => io.IsRequired && (erContext.OriginalRequest.ProvidedInputObjects.Contains(io.Name) == false)) .Select(io => io.Name) .ToArray(); // If we don't, respond with [400 Bad Request] + detailed error description... if (unknownObjects.Any() || neededObjects.Any()) { var errorMessages = new List <string>(); if (unknownObjects.Any()) { errorMessages.Add($"[{ErrorCodes.UnknownInputObjects}]: " + $"The following provided input objects are unknown: [{unknownObjects.ToCommaSeparatedString()}]."); } if (neededObjects.Any()) { errorMessages.Add($"[{ErrorCodes.MissingInputObjects}]: " + $"The following input objects are missing: [{neededObjects.ToCommaSeparatedString()}]."); } return(BadRequest(await CreateToContinueApiModelAsync(erContext, errorMessages.ToSpaceSeparatedString()))); } else { // Otherwise, dispatch the execution request to the execution pipeline and respond back to the client appropriately. // For more information on the execution pipeline, see /doc/architecture/execution-pipeline.md. return(await ToExecutionRequestRoutedResultAsync(await ExecuteAsync(erContext))); } }