// ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; using Microsoft.OpenApi.OData.Generator; using Microsoft.OpenApi.OData.Vocabulary.Capabilities; namespace Microsoft.OpenApi.OData.Operation { /// /// Base class for operation of . /// internal abstract class EdmOperationOperationHandler : OperationHandler { /// /// Gets the navigation source. /// protected IEdmNavigationSource NavigationSource { get; private set; } /// /// Gets the Edm operation. /// protected IEdmOperation EdmOperation { get; private set; } /// /// Gets the OData operation segment. /// protected ODataOperationSegment OperationSegment { get; private set; } /// /// Gets a value indicating whether the path has type cast segment or not. /// protected bool HasTypeCast { get; private set; } /// protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); // It's bound operation, the first segment must be the navigaiton source. ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; NavigationSource = navigationSourceSegment.NavigationSource; OperationSegment = path.LastSegment as ODataOperationSegment; EdmOperation = OperationSegment.Operation; HasTypeCast = path.Segments.Any(s => s is ODataTypeCastSegment); } /// protected override void SetBasicInfo(OpenApiOperation operation) { // Summary operation.Summary = "Invoke " + (EdmOperation.IsAction() ? "action " : "function ") + EdmOperation.Name; // OperationId if (Context.Settings.EnableOperationId) { string operationId = String.Join(".", Path.Segments.Where(s => !(s is ODataKeySegment)).Select(s => s.Identifier)); if (EdmOperation.IsAction()) { operation.OperationId = operationId; } else { ODataOperationSegment operationSegment = Path.LastSegment as ODataOperationSegment; string pathItemName = operationSegment.GetPathItemName(Context.Settings, new HashSet()); if (Context.Model.IsOperationOverload(operationSegment.Operation)) { string hash = pathItemName.GetHashSHA256(); operation.OperationId = operationId + "-" + hash.Substring(0, 4); } else { operation.OperationId = operationId; } } } base.SetBasicInfo(operation); } /// protected override void SetTags(OpenApiOperation operation) { string value = EdmOperation.IsAction() ? "Actions" : "Functions"; OpenApiTag tag = new OpenApiTag { Name = NavigationSource.Name + "." + value, }; tag.Extensions.Add(Constants.xMsTocType, new OpenApiString("container")); operation.Tags.Add(tag); Context.AppendTag(tag); base.SetTags(operation); } /// protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); if (EdmOperation.IsFunction()) { IEdmFunction function = (IEdmFunction)EdmOperation; if (OperationSegment.ParameterMappings != null) { IList parameters = Context.CreateParameters(function, OperationSegment.ParameterMappings); foreach (var parameter in parameters) { AppendParameter(operation, parameter); } } else { IDictionary mappings = ParameterMappings[OperationSegment]; IList parameters = Context.CreateParameters(function, mappings); if (operation.Parameters == null) { operation.Parameters = parameters; } else { foreach (var parameter in parameters) { AppendParameter(operation, parameter); } } } } } /// protected override void SetResponses(OpenApiOperation operation) { if (EdmOperation.IsAction() && EdmOperation.ReturnType == null) { operation.Responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse()); } else { // function should have a return type. OpenApiResponse response = new OpenApiResponse { Description = "Success", Content = new Dictionary { { Constants.ApplicationJsonMediaType, new OpenApiMediaType { Schema = Context.CreateEdmTypeSchema(EdmOperation.ReturnType) } } } }; operation.Responses.Add(Constants.StatusCode200, response); } // both action & function has the default response. operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse()); base.SetResponses(operation); } /// protected override void SetSecurity(OpenApiOperation operation) { OperationRestrictionsType restriction = Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.OperationRestrictions); if (restriction == null || restriction.Permissions == null) { return; } operation.Security = Context.CreateSecurityRequirements(restriction.Permissions).ToList(); } /// protected override void AppendCustomParameters(OpenApiOperation operation) { OperationRestrictionsType restriction = Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.OperationRestrictions); if (restriction == null) { return; } if (restriction.CustomHeaders != null) { AppendCustomParameters(operation, restriction.CustomHeaders, ParameterLocation.Header); } if (restriction.CustomQueryOptions != null) { AppendCustomParameters(operation, restriction.CustomQueryOptions, ParameterLocation.Query); } } } }