diff --git a/docs/oas3_0_0/graph.beta.json b/docs/oas3_0_0/graph.beta.json index 9e8aa99..a5ff4ec 100644 --- a/docs/oas3_0_0/graph.beta.json +++ b/docs/oas3_0_0/graph.beta.json @@ -695949,9 +695949,9 @@ }, "microsoft.graph.rgbColor": { "value": { - "b": 0, - "g": 0, - "r": 0 + "b": "AA==", + "g": "AA==", + "r": "AA==" } }, "microsoft.graph.mimeContent": { diff --git a/docs/oas3_0_0/graph1.0.json b/docs/oas3_0_0/graph1.0.json index 52765fc..2ff285f 100644 --- a/docs/oas3_0_0/graph1.0.json +++ b/docs/oas3_0_0/graph1.0.json @@ -515204,9 +515204,9 @@ }, "microsoft.graph.rgbColor": { "value": { - "b": 0, - "g": 0, - "r": 0 + "b": "AA==", + "g": "AA==", + "r": "AA==" } }, "microsoft.graph.deviceCategory": { diff --git a/docs/oas3_0_0/graph1.0_updated.json b/docs/oas3_0_0/graph1.0_updated.json index 52765fc..2ff285f 100644 --- a/docs/oas3_0_0/graph1.0_updated.json +++ b/docs/oas3_0_0/graph1.0_updated.json @@ -515204,9 +515204,9 @@ }, "microsoft.graph.rgbColor": { "value": { - "b": 0, - "g": 0, - "r": 0 + "b": "AA==", + "g": "AA==", + "r": "AA==" } }, "microsoft.graph.deviceCategory": { diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs index ab676a4..2007022 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs @@ -32,7 +32,7 @@ namespace Microsoft.OpenApi.OData.Edm public override ODataSegmentKind Kind => ODataSegmentKind.Key; /// - public override string Name + public override string Identifier { get { diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationPropertySegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationPropertySegment.cs index ac86b12..ad5a2d5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationPropertySegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationPropertySegment.cs @@ -34,7 +34,7 @@ namespace Microsoft.OpenApi.OData.Edm public override ODataSegmentKind Kind => ODataSegmentKind.NavigationProperty; /// - public override string Name { get => NavigationProperty.Name; } + public override string Identifier { get => NavigationProperty.Name; } /// public override string GetPathItemName(OpenApiConvertSettings settings) => NavigationProperty.Name; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationSourceSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationSourceSegment.cs index 871c0af..9bdd6dc 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationSourceSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationSourceSegment.cs @@ -31,7 +31,7 @@ namespace Microsoft.OpenApi.OData.Edm public override IEdmEntityType EntityType => NavigationSource.EntityType(); /// - public override string Name { get => NavigationSource.Name; } + public override string Identifier { get => NavigationSource.Name; } /// public override ODataSegmentKind Kind => ODataSegmentKind.NavigationSource; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationImportSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationImportSegment.cs index 652afc2..5e20b65 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationImportSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationImportSegment.cs @@ -34,7 +34,7 @@ namespace Microsoft.OpenApi.OData.Edm public override ODataSegmentKind Kind => ODataSegmentKind.OperationImport; /// - public override string Name { get => OperationImport.Name; } + public override string Identifier { get => OperationImport.Name; } /// public override string GetPathItemName(OpenApiConvertSettings settings) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs index 4248024..3503071 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs @@ -34,7 +34,7 @@ namespace Microsoft.OpenApi.OData.Edm public override ODataSegmentKind Kind => ODataSegmentKind.Operation; /// - public override string Name { get => Operation.Name; } + public override string Identifier { get => Operation.Name; } /// public override string GetPathItemName(OpenApiConvertSettings settings) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs index 2ead816..37f77e4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs @@ -60,9 +60,9 @@ namespace Microsoft.OpenApi.OData.Edm public abstract ODataSegmentKind Kind { get; } /// - /// Gets the name of this segment. + /// Gets the identifier of this segment. /// - public abstract string Name { get; } + public abstract string Identifier { get; } /// /// Gets the path item name for this segment. diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataTypeCastSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataTypeCastSegment.cs index a289e8e..0247322 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataTypeCastSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataTypeCastSegment.cs @@ -29,7 +29,7 @@ namespace Microsoft.OpenApi.OData.Edm public override ODataSegmentKind Kind => ODataSegmentKind.TypeCast; /// - public override string Name { get => EntityType.FullTypeName(); } + public override string Identifier { get => EntityType.FullTypeName(); } /// public override string GetPathItemName(OpenApiConvertSettings settings) => EntityType.FullTypeName(); diff --git a/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs index 6362d1f..5043276 100644 --- a/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs @@ -20,7 +20,7 @@ namespace Microsoft.OpenApi.OData public static class EdmModelOpenApiExtensions { /// - /// Convert to . + /// Convert to using default settings. /// /// The Edm model. /// The converted Open API document object, . diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecurityRequirementGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecurityRequirementGenerator.cs index e1607ec..323d147 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecurityRequirementGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecurityRequirementGenerator.cs @@ -73,7 +73,7 @@ namespace Microsoft.OpenApi.OData.Generator Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, - Id = permission.Scheme.Authorization + Id = permission.SchemeName } } ] = new List(permission.Scopes?.Select(c => c.Scope) ?? new List()) diff --git a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj index c66de56..b11f91d 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj +++ b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj @@ -20,8 +20,8 @@ - - + + diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs index b0785f6..64039c0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs @@ -27,7 +27,10 @@ namespace Microsoft.OpenApi.OData.Operation IEdmFunctionImport functionImport = EdmOperationImport as IEdmFunctionImport; //The parameters array contains a Parameter Object for each parameter of the function overload, // and it contains specific Parameter Objects for the allowed system query options. - operation.Parameters = Context.CreateParameters(functionImport); + foreach (var param in Context.CreateParameters(functionImport)) + { + operation.Parameters.Add(param); + } } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs index c3c3d6f..4813e49 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs @@ -5,12 +5,14 @@ using System; using System.Collections.Generic; +using System.Linq; 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 { @@ -68,6 +70,38 @@ namespace Microsoft.OpenApi.OData.Operation base.SetResponses(operation); } + /// + protected override void SetSecurity(OpenApiOperation operation) + { + OperationRestrictionsType restriction = Context.Model.GetRecord(EdmOperationImport, 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(EdmOperationImport, 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); + } + } + /// protected override void SetTags(OpenApiOperation operation) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs index 55110e5..bdc6256 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs @@ -61,7 +61,7 @@ namespace Microsoft.OpenApi.OData.Operation // OperationId if (Context.Settings.EnableOperationId) { - string operationId = String.Join(".", Path.Segments.Where(s => !(s is ODataKeySegment)).Select(s => s.Name)); + string operationId = String.Join(".", Path.Segments.Where(s => !(s is ODataKeySegment)).Select(s => s.Identifier)); if (EdmOperation.IsAction()) { operation.OperationId = operationId; @@ -154,40 +154,32 @@ namespace Microsoft.OpenApi.OData.Operation /// protected override void SetSecurity(OpenApiOperation operation) { - IEnumerable restrictions = Context.Model.GetCollection(EdmOperation, CapabilitiesConstants.OperationRestrictions); - if (restrictions == null || !restrictions.Any()) + OperationRestrictionsType restriction = Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.OperationRestrictions); + if (restriction == null || restriction.Permissions == null) { return; } - // TODO: how to use the collection? - OperationRestrictionType operationRestriction = restrictions.First(); - - // the Permission should be collection, however current ODL supports the single permission. - // Will update after ODL change. - operation.Security = Context.CreateSecurityRequirements(new[] { operationRestriction.Permission.Scheme }).ToList(); + operation.Security = Context.CreateSecurityRequirements(restriction.Permissions).ToList(); } /// protected override void AppendCustomParameters(OpenApiOperation operation) { - IEnumerable restrictions = Context.Model.GetCollection(EdmOperation, CapabilitiesConstants.OperationRestrictions); - if (restrictions == null || !restrictions.Any()) + OperationRestrictionsType restriction = Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.OperationRestrictions); + if (restriction == null) { return; } - // TODO: how to use the collection? - OperationRestrictionType operationRestriction = restrictions.First(); - - if (operationRestriction.CustomHeaders != null) + if (restriction.CustomHeaders != null) { - AppendCustomParameters(operation.Parameters, operationRestriction.CustomHeaders, ParameterLocation.Header); + AppendCustomParameters(operation, restriction.CustomHeaders, ParameterLocation.Header); } - if (operationRestriction.CustomQueryOptions != null) + if (restriction.CustomQueryOptions != null) { - AppendCustomParameters(operation.Parameters, operationRestriction.CustomQueryOptions, ParameterLocation.Query); + AppendCustomParameters(operation, restriction.CustomQueryOptions, ParameterLocation.Query); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs index e72a6c9..8314bc9 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs @@ -71,14 +71,12 @@ namespace Microsoft.OpenApi.OData.Operation protected override void SetSecurity(OpenApiOperation operation) { DeleteRestrictionsType delete = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.DeleteRestrictions); - if (delete == null || delete.Permission == null) + if (delete == null || delete.Permissions == null) { return; } - // the Permission should be collection, however current ODL supports the single permission. - // Will update after ODL change. - operation.Security = Context.CreateSecurityRequirements(new[] { delete.Permission.Scheme }).ToList(); + operation.Security = Context.CreateSecurityRequirements(delete.Permissions).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) @@ -91,12 +89,12 @@ namespace Microsoft.OpenApi.OData.Operation if (delete.CustomHeaders != null) { - AppendCustomParameters(operation.Parameters, delete.CustomHeaders, ParameterLocation.Header); + AppendCustomParameters(operation, delete.CustomHeaders, ParameterLocation.Header); } if (delete.CustomQueryOptions != null) { - AppendCustomParameters(operation.Parameters, delete.CustomQueryOptions, ParameterLocation.Query); + AppendCustomParameters(operation, delete.CustomQueryOptions, ParameterLocation.Query); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs index c1655f7..391d5c1 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs @@ -110,14 +110,12 @@ namespace Microsoft.OpenApi.OData.Operation readBase = read.ReadByKeyRestrictions; } - if (readBase == null && readBase.Permission == null) + if (readBase == null && readBase.Permissions == null) { return; } - // the Permission should be collection, however current ODL supports the single permission. - // Will update after ODL change. - operation.Security = Context.CreateSecurityRequirements(new[] { readBase.Permission.Scheme }).ToList(); + operation.Security = Context.CreateSecurityRequirements(readBase.Permissions).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) @@ -136,12 +134,12 @@ namespace Microsoft.OpenApi.OData.Operation if (readBase.CustomHeaders != null) { - AppendCustomParameters(operation.Parameters, readBase.CustomHeaders, ParameterLocation.Header); + AppendCustomParameters(operation, readBase.CustomHeaders, ParameterLocation.Header); } if (readBase.CustomQueryOptions != null) { - AppendCustomParameters(operation.Parameters, readBase.CustomQueryOptions, ParameterLocation.Query); + AppendCustomParameters(operation, readBase.CustomQueryOptions, ParameterLocation.Query); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPatchOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPatchOperationHandler.cs index a0a7fc1..2c4f4e8 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPatchOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPatchOperationHandler.cs @@ -83,14 +83,12 @@ namespace Microsoft.OpenApi.OData.Operation protected override void SetSecurity(OpenApiOperation operation) { UpdateRestrictionsType update = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.UpdateRestrictions); - if (update == null || update.Permission == null) + if (update == null || update.Permissions == null) { return; } - // the Permission should be collection, however current ODL supports the single permission. - // Will update after ODL change. - operation.Security = Context.CreateSecurityRequirements(new[] { update.Permission.Scheme }).ToList(); + operation.Security = Context.CreateSecurityRequirements(update.Permissions).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) @@ -103,12 +101,12 @@ namespace Microsoft.OpenApi.OData.Operation if (update.CustomHeaders != null) { - AppendCustomParameters(operation.Parameters, update.CustomHeaders, ParameterLocation.Header); + AppendCustomParameters(operation, update.CustomHeaders, ParameterLocation.Header); } if (update.CustomQueryOptions != null) { - AppendCustomParameters(operation.Parameters, update.CustomQueryOptions, ParameterLocation.Query); + AppendCustomParameters(operation, update.CustomQueryOptions, ParameterLocation.Query); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs index 5b87c5b..05346de 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs @@ -165,14 +165,12 @@ namespace Microsoft.OpenApi.OData.Operation protected override void SetSecurity(OpenApiOperation operation) { ReadRestrictionsType read = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); - if (read == null || read.Permission == null) + if (read == null || read.Permissions == null) { return; } - // the Permission should be collection, however current ODL supports the single permission. - // Will update after ODL change. - operation.Security = Context.CreateSecurityRequirements(new[] { read.Permission.Scheme }).ToList(); + operation.Security = Context.CreateSecurityRequirements(read.Permissions).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) @@ -185,12 +183,12 @@ namespace Microsoft.OpenApi.OData.Operation if (read.CustomHeaders != null) { - AppendCustomParameters(operation.Parameters, read.CustomHeaders, ParameterLocation.Header); + AppendCustomParameters(operation, read.CustomHeaders, ParameterLocation.Header); } if (read.CustomQueryOptions != null) { - AppendCustomParameters(operation.Parameters, read.CustomQueryOptions, ParameterLocation.Query); + AppendCustomParameters(operation, read.CustomQueryOptions, ParameterLocation.Query); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs index 5b6a514..781c1fb 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs @@ -109,14 +109,12 @@ namespace Microsoft.OpenApi.OData.Operation protected override void SetSecurity(OpenApiOperation operation) { InsertRestrictionsType insert = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.InsertRestrictions); - if (insert == null || insert.Permission == null) + if (insert == null || insert.Permissions == null) { return; } - // the Permission should be collection, however current ODL supports the single permission. - // Will update after ODL change. - operation.Security = Context.CreateSecurityRequirements(new[] { insert.Permission.Scheme }).ToList(); + operation.Security = Context.CreateSecurityRequirements(insert.Permissions).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) @@ -129,12 +127,12 @@ namespace Microsoft.OpenApi.OData.Operation if (insert.CustomQueryOptions != null) { - AppendCustomParameters(operation.Parameters, insert.CustomQueryOptions, ParameterLocation.Query); + AppendCustomParameters(operation, insert.CustomQueryOptions, ParameterLocation.Query); } if (insert.CustomHeaders != null) { - AppendCustomParameters(operation.Parameters, insert.CustomHeaders, ParameterLocation.Header); + AppendCustomParameters(operation, insert.CustomHeaders, ParameterLocation.Header); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs index 4f5b28f..48376af 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs @@ -4,10 +4,13 @@ // ------------------------------------------------------------ using System.Collections.Generic; +using System.Linq; using Microsoft.OData.Edm; 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 { @@ -198,5 +201,51 @@ namespace Microsoft.OpenApi.OData.Operation } } } + + protected override void SetSecurity(OpenApiOperation operation) + { + if (Restriction == null || Restriction.ReadRestrictions == null) + { + return; + } + + ReadRestrictionsBase readBase = Restriction.ReadRestrictions; + if (LastSegmentIsKeySegment) + { + if (Restriction.ReadRestrictions.ReadByKeyRestrictions != null) + { + readBase = Restriction.ReadRestrictions.ReadByKeyRestrictions; + } + } + + operation.Security = Context.CreateSecurityRequirements(readBase.Permissions).ToList(); + } + + protected override void AppendCustomParameters(OpenApiOperation operation) + { + if (Restriction == null || Restriction.ReadRestrictions == null) + { + return; + } + + ReadRestrictionsBase readBase = Restriction.ReadRestrictions; + if (LastSegmentIsKeySegment) + { + if (Restriction.ReadRestrictions.ReadByKeyRestrictions != null) + { + readBase = Restriction.ReadRestrictions.ReadByKeyRestrictions; + } + } + + if (readBase.CustomHeaders != null) + { + AppendCustomParameters(operation, readBase.CustomHeaders, ParameterLocation.Header); + } + + if (readBase.CustomQueryOptions != null) + { + AppendCustomParameters(operation, readBase.CustomQueryOptions, ParameterLocation.Query); + } + } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs index b0c90c5..b0b2e4e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; +using Microsoft.OpenApi.OData.Vocabulary.Capabilities; namespace Microsoft.OpenApi.OData.Operation { @@ -33,6 +34,11 @@ namespace Microsoft.OpenApi.OData.Operation /// protected string NavigationPropertyPath { get; private set; } + /// + /// Gets the navigation restriction. + /// + protected NavigationPropertyRestriction Restriction { get; private set; } + /// /// Gets a bool value indicating whether the last segment is a key segment. /// @@ -56,10 +62,25 @@ namespace Microsoft.OpenApi.OData.Operation NavigationProperty = npSegment.NavigationProperty; NavigationPropertyPath = string.Join("/", - path.Segments.OfType().Select(p => p.NavigationProperty.Name)); + Path.Segments.Where(s => !(s is ODataKeySegment || s is ODataNavigationSourceSegment)).Select(e => e.Identifier)); - // So far, we haven't defined the HttpRequest for the navigation property path. - // Request = Context.FindRequest(NavigationSource, OperationType.ToString()); + IEdmEntitySet entitySet = NavigationSource as IEdmEntitySet; + IEdmSingleton singleton = NavigationSource as IEdmSingleton; + + NavigationRestrictionsType navigation; + if (entitySet != null) + { + navigation = Context.Model.GetRecord(entitySet, CapabilitiesConstants.NavigationRestrictions); + } + else + { + navigation = Context.Model.GetRecord(singleton, CapabilitiesConstants.NavigationRestrictions); + } + + if (navigation != null && navigation.RestrictedProperties != null) + { + Restriction = navigation.RestrictedProperties.FirstOrDefault(r => r.NavigationProperty != null && r.NavigationProperty == NavigationPropertyPath); + } } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPatchOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPatchOperationHandler.cs index fd945f7..e3399b3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPatchOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPatchOperationHandler.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System.Collections.Generic; +using System.Linq; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; @@ -76,5 +77,34 @@ namespace Microsoft.OpenApi.OData.Operation base.SetResponses(operation); } + + protected override void SetSecurity(OpenApiOperation operation) + { + if (Restriction == null || Restriction.UpdateRestrictions == null) + { + return; + } + + + operation.Security = Context.CreateSecurityRequirements(Restriction.UpdateRestrictions.Permissions).ToList(); + } + + protected override void AppendCustomParameters(OpenApiOperation operation) + { + if (Restriction == null || Restriction.UpdateRestrictions == null) + { + return; + } + + if (Restriction.UpdateRestrictions.CustomHeaders != null) + { + AppendCustomParameters(operation, Restriction.UpdateRestrictions.CustomHeaders, ParameterLocation.Header); + } + + if (Restriction.UpdateRestrictions.CustomQueryOptions != null) + { + AppendCustomParameters(operation, Restriction.UpdateRestrictions.CustomQueryOptions, ParameterLocation.Query); + } + } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs index 3daf36f..9444b6c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System.Collections.Generic; +using System.Linq; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; @@ -99,5 +100,33 @@ namespace Microsoft.OpenApi.OData.Operation base.SetResponses(operation); } + + protected override void SetSecurity(OpenApiOperation operation) + { + if (Restriction == null || Restriction.InsertRestrictions == null) + { + return; + } + + operation.Security = Context.CreateSecurityRequirements(Restriction.InsertRestrictions.Permissions).ToList(); + } + + protected override void AppendCustomParameters(OpenApiOperation operation) + { + if (Restriction == null || Restriction.InsertRestrictions == null) + { + return; + } + + if (Restriction.InsertRestrictions.CustomHeaders != null) + { + AppendCustomParameters(operation, Restriction.InsertRestrictions.CustomHeaders, ParameterLocation.Header); + } + + if (Restriction.InsertRestrictions.CustomQueryOptions != null) + { + AppendCustomParameters(operation, Restriction.InsertRestrictions.CustomQueryOptions, ParameterLocation.Query); + } + } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs index 199b3f8..9355470 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs @@ -167,7 +167,7 @@ namespace Microsoft.OpenApi.OData.Operation /// The parameters. /// The custom parameters. /// The parameter location. - protected static void AppendCustomParameters(IList parameters, IList customParameters, ParameterLocation location) + protected static void AppendCustomParameters(OpenApiOperation operation, IList customParameters, ParameterLocation location) { foreach (var param in customParameters) { @@ -206,7 +206,7 @@ namespace Microsoft.OpenApi.OData.Operation } } - parameters.Add(parameter); + operation.Parameters.Add(parameter); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs index 4d7d658..ac12875 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs @@ -100,14 +100,12 @@ namespace Microsoft.OpenApi.OData.Operation protected override void SetSecurity(OpenApiOperation operation) { ReadRestrictionsType read = Context.Model.GetRecord(Singleton, CapabilitiesConstants.ReadRestrictions); - if (read == null || read.Permission == null) + if (read == null || read.Permissions == null) { return; } - // the Permission should be collection, however current ODL supports the single permission. - // Will update after ODL change. - operation.Security = Context.CreateSecurityRequirements(new[] { read.Permission.Scheme }).ToList(); + operation.Security = Context.CreateSecurityRequirements(read.Permissions).ToList(); } /// @@ -121,12 +119,12 @@ namespace Microsoft.OpenApi.OData.Operation if (read.CustomHeaders != null) { - AppendCustomParameters(operation.Parameters, read.CustomHeaders, ParameterLocation.Header); + AppendCustomParameters(operation, read.CustomHeaders, ParameterLocation.Header); } if (read.CustomQueryOptions != null) { - AppendCustomParameters(operation.Parameters, read.CustomQueryOptions, ParameterLocation.Query); + AppendCustomParameters(operation, read.CustomQueryOptions, ParameterLocation.Query); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs index 9a57aad..34e4d4c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs @@ -84,14 +84,12 @@ namespace Microsoft.OpenApi.OData.Operation protected override void SetSecurity(OpenApiOperation operation) { UpdateRestrictionsType update = Context.Model.GetRecord(Singleton, CapabilitiesConstants.UpdateRestrictions); - if (update == null || update.Permission == null) + if (update == null || update.Permissions == null) { return; } - // the Permission should be collection, however current ODL supports the single permission. - // Will update after ODL change. - operation.Security = Context.CreateSecurityRequirements(new[] { update.Permission }).ToList(); + operation.Security = Context.CreateSecurityRequirements(update.Permissions).ToList(); } /// @@ -105,12 +103,12 @@ namespace Microsoft.OpenApi.OData.Operation if (update.CustomHeaders != null) { - AppendCustomParameters(operation.Parameters, update.CustomHeaders, ParameterLocation.Header); + AppendCustomParameters(operation, update.CustomHeaders, ParameterLocation.Header); } if (update.CustomQueryOptions != null) { - AppendCustomParameters(operation.Parameters, update.CustomQueryOptions, ParameterLocation.Query); + AppendCustomParameters(operation, update.CustomQueryOptions, ParameterLocation.Query); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs index 83c035b..e4c3f5d 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System; +using System.Diagnostics; using System.Linq; using System.Collections.Generic; using Microsoft.OData.Edm; @@ -49,22 +50,33 @@ namespace Microsoft.OpenApi.OData.PathItem target = NavigationSource as IEdmSingleton; } + string navigationPropertyPath = String.Join("/", + Path.Segments.Where(s => !(s is ODataKeySegment || s is ODataNavigationSourceSegment)).Select(e => e.Identifier)); + NavigationRestrictionsType navigation = Context.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); - if (navigation != null && navigation.Navigability != null && navigation.Navigability.Value == NavigationType.None) + NavigationPropertyRestriction restriction = navigation?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty == navigationPropertyPath); + + // verify using individual first + if (restriction != null && restriction.Navigability != null && restriction.Navigability.Value == NavigationType.None) { - // This check should be done when retrieve the path, but, here is for verification. return; } - string navigationPropertyPath = String.Join("/", - Path.Segments.Where(s => !(s is ODataKeySegment || s is ODataNavigationSourceSegment)).Select(e => e.Name)); + if (restriction == null || restriction.Navigability == null) + { + // if the individual has not navigability setting, use the global navigability setting + if (navigation != null && navigation.Navigability != null && navigation.Navigability.Value == NavigationType.None) + { + // Default navigability for all navigation properties of the annotation target. + // Individual navigation properties can override this value via `RestrictedProperties/Navigability`. + return; + } + } + // how about delete? // contaiment: Get / (Post - Collection | Patch - Single) // non-containment: only Get - if (navigation == null || !navigation.IsRestrictedProperty(navigationPropertyPath)) - { - AddOperation(item, OperationType.Get); - } + AddGetOperation(item, restriction); if (NavigationProperty.ContainsTarget) { @@ -73,16 +85,16 @@ namespace Microsoft.OpenApi.OData.PathItem if (LastSegmentIsKeySegment) { // Need to check this scenario is valid or not? - UpdateRestrictionsType update = Context.Model.GetRecord(target, CapabilitiesConstants.UpdateRestrictions); - if (update == null || !update.IsNonUpdatableNavigationProperty(navigationPropertyPath)) + UpdateRestrictionsType update = restriction?.UpdateRestrictions; + if (update == null || update.IsUpdatable) { AddOperation(item, OperationType.Patch); } } else { - InsertRestrictionsType insert = Context.Model.GetRecord(target, CapabilitiesConstants.InsertRestrictions); - if (insert == null || !insert.IsNonInsertableNavigationProperty(navigationPropertyPath)) + InsertRestrictionsType insert = restriction?.InsertRestrictions; + if (insert == null || insert.IsInsertable) { AddOperation(item, OperationType.Post); } @@ -90,8 +102,8 @@ namespace Microsoft.OpenApi.OData.PathItem } else { - UpdateRestrictionsType update = Context.Model.GetRecord(target, CapabilitiesConstants.UpdateRestrictions); - if (update == null || !update.IsNonUpdatableNavigationProperty(navigationPropertyPath)) + UpdateRestrictionsType update = restriction?.UpdateRestrictions; + if (update == null || update.IsUpdatable) { AddOperation(item, OperationType.Patch); } @@ -99,6 +111,52 @@ namespace Microsoft.OpenApi.OData.PathItem } } + private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction) + { + ReadRestrictionsType read = restriction?.ReadRestrictions; + if (read == null) + { + AddOperation(item, OperationType.Get); + return; + } + + if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) + { + if (LastSegmentIsKeySegment) + { + if (read.ReadByKeyRestrictions != null && read.ReadByKeyRestrictions.Readable != null) + { + if (read.ReadByKeyRestrictions.Readable.Value) + { + AddOperation(item, OperationType.Get); + } + } + else + { + if (read.IsReadable) + { + AddOperation(item, OperationType.Get); + } + } + } + else + { + if (read.IsReadable) + { + AddOperation(item, OperationType.Get); + } + } + } + else + { + Debug.Assert(LastSegmentIsKeySegment == false); + if (read.IsReadable) + { + AddOperation(item, OperationType.Get); + } + } + } + /// protected override void Initialize(ODataContext context, ODataPath path) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs index 30618dc..1d2ab38 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs @@ -32,10 +32,20 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// public int? MaxLevels { get; private set; } + /// + /// Gets the Members of collections can be updated via a PATCH request with a `/$filter(...)/$each` segment. + /// + public bool? FilterSegmentSupported { get; private set; } + + /// + /// Gets the Members of collections can be updated via a PATCH request with a type-cast segment and a `/$each` segment. + /// + public bool? TypecastSegmentSupported { get; private set; } + /// /// Gets the required scopes to perform the insert. /// - public PermissionType Permission { get; private set; } + public IList Permissions { get; private set; } /// /// Gets the Supported or required custom headers. @@ -47,6 +57,16 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// public IList CustomQueryOptions { get; private set; } + /// + /// Gets A brief description of the request. + /// + public string Description { get; private set; } + + /// + /// Gets A lengthy description of the request. + /// + public string LongDescription { get; private set; } + /// /// Test the target supports delete. /// @@ -82,14 +102,26 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities // MaxLevels MaxLevels = (int?)record.GetInteger("MaxLevels"); - // Permission - Permission = record.GetRecord("Permission"); + // FilterSegmentSupported + FilterSegmentSupported = record.GetBoolean("FilterSegmentSupported"); + + // TypecastSegmentSupported + TypecastSegmentSupported = record.GetBoolean("TypecastSegmentSupported"); + + // Permissions + Permissions = record.GetCollection("Permissions"); // CustomHeaders CustomHeaders = record.GetCollection("CustomHeaders"); // CustomQueryOptions CustomQueryOptions = record.GetCollection("CustomQueryOptions"); + + // Description + Description = record.GetString("Description"); + + // LongDescription + LongDescription = record.GetString("LongDescription"); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ExpandRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ExpandRestrictionsType.cs index caf5ca5..60b797a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ExpandRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ExpandRestrictionsType.cs @@ -22,6 +22,11 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// public bool? Expandable { get; private set; } + /// + /// Gets the $expand is supported for stream properties and media resources. + /// + public bool? StreamsExpandable { get; private set; } + /// /// Gets the properties which cannot be used in $expand expressions. /// @@ -55,6 +60,9 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities // Expandable Expandable = record.GetBoolean("Expandable"); + // StreamsExpandable + StreamsExpandable = record.GetBoolean("StreamsExpandable"); + // NonExpandableProperties NonExpandableProperties = record.GetCollectionPropertyPath("NonExpandableProperties"); diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/InsertRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/InsertRestrictionsType.cs index 3c5a7a5..aec9d73 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/InsertRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/InsertRestrictionsType.cs @@ -37,10 +37,15 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// public long? MaxLevels { get; private set; } + /// + /// Gets the Entities of a specific derived type can be created by specifying a type-cast segment. + /// + public bool? TypecastSegmentSupported { get; private set; } + /// /// Gets the required scopes to perform the insert. /// - public PermissionType Permission { get; private set; } + public IList Permissions { get; private set; } /// /// Gets the Support for query options with insert requests. @@ -57,6 +62,16 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// public IList CustomQueryOptions { get; private set; } + /// + /// Gets A brief description of the request. + /// + public string Description { get; private set; } + + /// + /// Gets A lengthy description of the request. + /// + public string LongDescription { get; private set; } + /// /// Test the target supports insert. /// @@ -92,8 +107,11 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities // MaxLevels MaxLevels = record.GetInteger("MaxLevels"); - // Permission - Permission = record.GetRecord("Permission"); + // TypecastSegmentSupported + TypecastSegmentSupported = record.GetBoolean("TypecastSegmentSupported"); + + // Permissions + Permissions = record.GetCollection("Permissions"); // QueryOptions QueryOptions = record.GetRecord("QueryOptions"); @@ -103,6 +121,12 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities // CustomHeaders CustomQueryOptions = record.GetCollection("CustomQueryOptions"); + + // Description + Description = record.GetString("Description"); + + // LongDescription + LongDescription = record.GetString("LongDescription"); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionsType.cs similarity index 73% rename from src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionType.cs rename to src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionsType.cs index 22a155b..261cfb5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionsType.cs @@ -11,16 +11,20 @@ using Microsoft.OpenApi.OData.Edm; namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities { /// - /// Complex Type: Org.OData.Capabilities.V1.OperationRestrictionType - /// Be note: in ODL 7.6, it's named as "OperationRestriction", after that, it will be changed as "OperationRestrictionType" + /// Complex Type: Org.OData.Capabilities.V1.OperationRestrictionsType /// [Term("Org.OData.Capabilities.V1.OperationRestrictions")] - internal class OperationRestrictionType : IRecord + internal class OperationRestrictionsType : IRecord { + /// + /// Gets the Bound action or function can be invoked on a collection-valued binding parameter path with a '/$filter(...)' segment. + /// + public bool? FilterSegmentSupported { get; private set; } + /// /// Gets the List of required scopes to invoke an action or function. /// - public PermissionType Permission { get; private set; } + public IList Permissions { get; private set; } /// /// Gets the Supported or required custom headers. @@ -40,8 +44,11 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities { Utils.CheckArgumentNull(record, nameof(record)); - // Permission - Permission = record.GetRecord("Permission"); + // FilterSegmentSupported + FilterSegmentSupported = record.GetBoolean("FilterSegmentSupported"); + + // Permissions + Permissions = record.GetCollection("Permissions"); // CustomHeaders CustomHeaders = record.GetCollection("CustomHeaders"); diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/PermissionType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/PermissionType.cs index bf34363..16b3bcd 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/PermissionType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/PermissionType.cs @@ -3,11 +3,11 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections; using System.Collections.Generic; using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; -using Microsoft.OpenApi.OData.Vocabulary.Authorization; namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities { @@ -17,14 +17,14 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities internal class PermissionType : IRecord { /// - /// Gets the auth flow scheme name. + /// Gets the Authorization flow scheme name. /// - public SecurityScheme Scheme { get; private set; } + public string SchemeName { get; private set; } /// /// Gets the list of scopes that can provide access to the resource. /// - public IEnumerable Scopes { get; private set; } + public IList Scopes { get; private set; } /// /// Init the . @@ -34,8 +34,8 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities { Utils.CheckArgumentNull(record, nameof(record)); - // Scheme - Scheme = record.GetRecord("Scheme"); + // SchemeName + SchemeName = record.GetString("SchemeName"); // Scopes Scopes = record.GetCollection("Scopes"); diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ReadRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ReadRestrictionsType.cs index 65aec22..f4600b7 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ReadRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ReadRestrictionsType.cs @@ -23,7 +23,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// /// Gets the List of required scopes to invoke an action or function /// - public PermissionType Permission { get; private set; } + public IList Permissions { get; private set; } /// /// Gets the Supported or required custom headers. @@ -35,6 +35,16 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// public IList CustomQueryOptions { get; private set; } + /// + /// Gets A brief description of the request. + /// + public string Description { get; private set; } + + /// + /// Gets A lengthy description of the request. + /// + public string LongDescription { get; private set; } + /// /// Test the target supports update. /// @@ -52,14 +62,20 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities // Readable Readable = record.GetBoolean("Readable"); - // Permission - Permission = record.GetRecord("Permission"); + // Permissions + Permissions = record.GetCollection("Permissions"); // CustomHeaders CustomHeaders = record.GetCollection("CustomHeaders"); // CustomQueryOptions CustomQueryOptions = record.GetCollection("CustomQueryOptions"); + + // Description + Description = record.GetString("Description"); + + // LongDescription + LongDescription = record.GetString("LongDescription"); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SelectSupportType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SelectSupportType.cs index 2deff9d..d790954 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SelectSupportType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SelectSupportType.cs @@ -20,6 +20,11 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// public bool? Supported { get; private set; } + /// + /// Gets the Supports instance annotations in $select list. + /// + public bool? InstanceAnnotationsSupported { get; private set; } + /// /// Gets the $expand within $select is supported. /// @@ -71,6 +76,9 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities // Supported Supported = record.GetBoolean("Supported"); + // Expandable + InstanceAnnotationsSupported = record.GetBoolean("InstanceAnnotationsSupported"); + // Expandable Expandable = record.GetBoolean("Expandable"); diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs index e22ac9b..53f6add 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs @@ -23,6 +23,26 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// public bool? Updatable { get; private set; } + /// + /// Gets the value indicating Entities can be upserted. + /// + public bool? Upsertable { get; private set; } + + /// + /// Gets the value indicating Entities can be inserted, updated, and deleted via a PATCH request with a delta payload. + /// + public bool? DeltaUpdateSupported { get; private set; } + + /// + /// Gets the value indicating Members of collections can be updated via a PATCH request with a '/$filter(...)/$each' segment. + /// + public bool? FilterSegmentSupported { get; private set; } + + /// + /// Gets the value indicating Members of collections can be updated via a PATCH request with a type-cast segment and a '/$each' segment. + /// + public bool? TypecastSegmentSupported { get; private set; } + /// /// Gets the navigation properties which do not allow rebinding. /// @@ -35,9 +55,9 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities public long? MaxLevels { get; private set; } /// - /// Gets/sets the required scopes to perform update. + /// Gets the Required permissions. One of the specified sets of scopes is required to perform the update. /// - public PermissionType Permission { get; private set; } + public IList Permissions { get; private set; } /// /// Gets/sets the support for query options with update requests. @@ -54,6 +74,16 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// public IList CustomQueryOptions { get; private set; } + /// + /// Gets A brief description of the request. + /// + public string Description { get; private set; } + + /// + /// Gets A lengthy description of the request. + /// + public string LongDescription { get; private set; } + /// /// Test the target supports update. /// @@ -83,14 +113,26 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities // Updatable Updatable = record.GetBoolean("Updatable"); + // Upsertable + Upsertable = record.GetBoolean("Upsertable"); + + // DeltaUpdateSupported + DeltaUpdateSupported = record.GetBoolean("DeltaUpdateSupported"); + + // FilterSegmentSupported + FilterSegmentSupported = record.GetBoolean("FilterSegmentSupported"); + + // TypecastSegmentSupported + TypecastSegmentSupported = record.GetBoolean("TypecastSegmentSupported"); + // NonUpdatableNavigationProperties NonUpdatableNavigationProperties = record.GetCollectionPropertyPath("NonUpdatableNavigationProperties"); // MaxLevels MaxLevels = record.GetInteger("MaxLevels"); - // Permission - Permission = record.GetRecord("Permission"); + // Permissions + Permissions = record.GetCollection("Permissions"); // QueryOptions QueryOptions = record.GetRecord("QueryOptions"); @@ -100,6 +142,12 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities // CustomQueryOptions CustomQueryOptions = record.GetCollection("CustomQueryOptions"); + + // Description + Description = record.GetString("Description"); + + // LongDescription + LongDescription = record.GetString("LongDescription"); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/TermAttribute.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/TermAttribute.cs index f7fb0f7..cf686fc 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/TermAttribute.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/TermAttribute.cs @@ -14,7 +14,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary internal class TermAttribute : Attribute { /// - /// Initializes a new instance of class. + /// Initializes a new instance of class. /// /// The qualified name of this term. public TermAttribute(string qualifiedName) diff --git a/src/OoasGui/OoasGui.csproj b/src/OoasGui/OoasGui.csproj index 21d3b57..708e739 100644 --- a/src/OoasGui/OoasGui.csproj +++ b/src/OoasGui/OoasGui.csproj @@ -32,11 +32,11 @@ 4 - - ..\..\packages\Microsoft.OData.Edm.7.6.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll + + ..\..\packages\Microsoft.OData.Edm.7.6.1-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll - - ..\..\packages\Microsoft.OpenApi.1.1.2\lib\net46\Microsoft.OpenApi.dll + + ..\..\packages\Microsoft.OpenApi.1.1.4\lib\net46\Microsoft.OpenApi.dll diff --git a/src/OoasGui/Program.cs b/src/OoasGui/Program.cs index e686cbd..7ab918e 100644 --- a/src/OoasGui/Program.cs +++ b/src/OoasGui/Program.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using System.Windows.Forms; namespace OoasGui diff --git a/src/OoasGui/packages.config b/src/OoasGui/packages.config index ac1a6c6..24edad7 100644 --- a/src/OoasGui/packages.config +++ b/src/OoasGui/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Microsoft.OpenAPI.OData.Reader.Tests.csproj b/test/Microsoft.OpenAPI.OData.Reader.Tests/Microsoft.OpenAPI.OData.Reader.Tests.csproj index 301d4c1..8f6c145 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Microsoft.OpenAPI.OData.Reader.Tests.csproj +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Microsoft.OpenAPI.OData.Reader.Tests.csproj @@ -61,7 +61,7 @@ - + all diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmActionImportOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmActionImportOperationHandlerTests.cs index d189a44..ecfac16 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmActionImportOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmActionImportOperationHandlerTests.cs @@ -4,7 +4,10 @@ // ------------------------------------------------------------ using System.Linq; +using System.Xml.Linq; using Microsoft.OData.Edm; +using Microsoft.OData.Edm.Csdl; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.OData.Edm; using Microsoft.OpenApi.OData.Tests; using Xunit; @@ -46,7 +49,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests [Theory] [InlineData(true)] [InlineData(false)] - public void CreateOperationForEdmActionReturnsCorrectOperationId(bool enableOperationId) + public void CreateOperationForEdmActionImportReturnsCorrectOperationId(bool enableOperationId) { // Arrange EdmModel model = new EdmModel(); @@ -84,5 +87,155 @@ namespace Microsoft.OpenApi.OData.Operation.Tests Assert.Null(operation.OperationId); } } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void OperationRestrictionsTermWorksToCreateOperationForEdmActionImport(bool enableAnnotation) + { + string template = @" + + + + + + + {0} + + + + + +"; + + string annotation = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // Arrange + string csdl = string.Format(template, enableAnnotation ? annotation : ""); + + var edmModel = CsdlReader.Parse(XElement.Parse(csdl).CreateReader()); + Assert.NotNull(edmModel); + IEdmOperationImport operationImport = edmModel.EntityContainer.FindOperationImports("ResetDataSource").FirstOrDefault(); + Assert.NotNull(operationImport); + + ODataContext context = new ODataContext(edmModel); + + ODataPath path = new ODataPath(new ODataOperationImportSegment(operationImport)); + + // Act + var operation = _operationHandler.CreateOperation(context, path); + + // Assert + Assert.NotNull(operation); + Assert.NotNull(operation.Security); + + if (enableAnnotation) + { + Assert.Equal(2, operation.Security.Count); + + string json = operation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""Delegated (work or school account)"": [ + ""User.ReadBasic.All"", + ""User.Read.All"", + ""Directory.Read.All"" + ] + }, + { + ""Application"": [ + ""User.Read.All"", + ""Directory.Read.All"" + ] + } + ],".ChangeLineBreaks(), json); + + // with custom query options + Assert.Contains(@" + ""parameters"": [ + { + ""name"": ""odata-debug"", + ""in"": ""query"", + ""description"": ""Debug support for OData services"", + ""schema"": { + ""type"": ""string"" + }, + ""examples"": { + ""example-1"": { + ""description"": ""Service responds with self-contained..."", + ""value"": ""html"" + }, + ""example-2"": { + ""description"": ""Service responds with JSON document..."", + ""value"": ""json"" + } + } + } + ],".ChangeLineBreaks(), json); + + } + else + { + Assert.Empty(operation.Security); + } + } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmActionOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmActionOperationHandlerTests.cs index 101e4b4..f0bbe07 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmActionOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmActionOperationHandlerTests.cs @@ -4,7 +4,10 @@ // ------------------------------------------------------------ using System.Linq; +using System.Xml.Linq; using Microsoft.OData.Edm; +using Microsoft.OData.Edm.Csdl; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.OData.Edm; using Microsoft.OpenApi.OData.Tests; using Xunit; @@ -139,5 +142,116 @@ namespace Microsoft.OpenApi.OData.Operation.Tests Assert.Null(operation.OperationId); } } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void OperationRestrictionsTermWorksToCreateOperationForEdmAction(bool enableAnnotation) + { + string template = @" + + + + + + + {0} + + + + + + + +"; + + string annotation = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // Arrange + string csdl = string.Format(template, enableAnnotation ? annotation : ""); + + var edmModel = CsdlReader.Parse(XElement.Parse(csdl).CreateReader()); + Assert.NotNull(edmModel); + IEdmSingleton me = edmModel.EntityContainer.FindSingleton("me"); + Assert.NotNull(me); + IEdmAction action = edmModel.SchemaElements.OfType().SingleOrDefault(); + Assert.NotNull(action); + Assert.Equal("getMemberGroups", action.Name); + + ODataContext context = new ODataContext(edmModel); + + ODataPath path = new ODataPath(new ODataNavigationSourceSegment(me), + new ODataOperationSegment(action)); + + // Act + var operation = _operationHandler.CreateOperation(context, path); + + // Assert + Assert.NotNull(operation); + Assert.NotNull(operation.Security); + + if (enableAnnotation) + { + Assert.Equal(2, operation.Security.Count); + + string json = operation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""Delegated (work or school account)"": [ + ""User.ReadBasic.All"", + ""User.Read.All"", + ""Directory.Read.All"" + ] + }, + { + ""Application"": [ + ""User.Read.All"", + ""Directory.Read.All"" + ] + } + ],".ChangeLineBreaks(), json); + } + else + { + Assert.Empty(operation.Security); + } + } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmFunctionImportOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmFunctionImportOperationHandlerTests.cs index 79a2b16..d107b00 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmFunctionImportOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmFunctionImportOperationHandlerTests.cs @@ -4,7 +4,10 @@ // ------------------------------------------------------------ using System.Linq; +using System.Xml.Linq; using Microsoft.OData.Edm; +using Microsoft.OData.Edm.Csdl; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.OData.Edm; using Microsoft.OpenApi.OData.Tests; using Xunit; @@ -85,5 +88,133 @@ namespace Microsoft.OpenApi.OData.Operation.Tests Assert.Null(operation.OperationId); } } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void OperationRestrictionsTermWorksToCreateOperationForEdmFunctionImport(bool enableAnnotation) + { + string template = @" + + + + + + + + + + + {0} + + + + + +"; + + string annotation = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // Arrange + string csdl = string.Format(template, enableAnnotation ? annotation : ""); + + var edmModel = CsdlReader.Parse(XElement.Parse(csdl).CreateReader()); + Assert.NotNull(edmModel); + IEdmOperationImport operationImport = edmModel.EntityContainer.FindOperationImports("GetNearestAirport").FirstOrDefault(); + Assert.NotNull(operationImport); + + ODataContext context = new ODataContext(edmModel); + + ODataPath path = new ODataPath(new ODataOperationImportSegment(operationImport)); + + // Act + var operation = _operationHandler.CreateOperation(context, path); + + // Assert + Assert.NotNull(operation); + Assert.NotNull(operation.Security); + + if (enableAnnotation) + { + Assert.Equal(2, operation.Security.Count); + + string json = operation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""Delegated (work or school account)"": [ + ""User.ReadBasic.All"", + ""User.Read.All"", + ""Directory.Read.All"" + ] + }, + { + ""Application"": [ + ""User.Read.All"", + ""Directory.Read.All"" + ] + } + ],".ChangeLineBreaks(), json); + + Assert.Contains(@" + { + ""name"": ""myhead1"", + ""in"": ""header"", + ""required"": true, + ""schema"": { + ""type"": ""string"" + } + } +".ChangeLineBreaks(), json); + } + else + { + Assert.Empty(operation.Security); + } + } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmFunctionOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmFunctionOperationHandlerTests.cs index ff58b91..32c8b05 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmFunctionOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmFunctionOperationHandlerTests.cs @@ -3,12 +3,11 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ -using System.Collections.Generic; using System.Linq; using System.Xml.Linq; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Csdl; -using Microsoft.OData.Edm.Validation; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.OData.Edm; using Microsoft.OpenApi.OData.Tests; using Xunit; @@ -143,5 +142,117 @@ namespace Microsoft.OpenApi.OData.Operation.Tests Assert.Null(operation.OperationId); } } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void OperationRestrictionsTermWorksToCreateOperationForEdmFunction(bool enableAnnotation) + { + string template = @" + + + + + + + + {0} + + + + + + + +"; + + string annotation = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // Arrange + string csdl = string.Format(template, enableAnnotation ? annotation : ""); + + var edmModel = CsdlReader.Parse(XElement.Parse(csdl).CreateReader()); + Assert.NotNull(edmModel); + IEdmSingleton me = edmModel.EntityContainer.FindSingleton("me"); + Assert.NotNull(me); + IEdmFunction function = edmModel.SchemaElements.OfType().SingleOrDefault(); + Assert.NotNull(function); + Assert.Equal("getMemberGroups", function.Name); + + ODataContext context = new ODataContext(edmModel); + + ODataPath path = new ODataPath(new ODataNavigationSourceSegment(me), + new ODataOperationSegment(function)); + + // Act + var operation = _operationHandler.CreateOperation(context, path); + + // Assert + Assert.NotNull(operation); + Assert.NotNull(operation.Security); + + if (enableAnnotation) + { + Assert.Equal(2, operation.Security.Count); + + string json = operation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""Delegated (work or school account)"": [ + ""User.ReadBasic.All"", + ""User.Read.All"", + ""Directory.Read.All"" + ] + }, + { + ""Application"": [ + ""User.Read.All"", + ""Directory.Read.All"" + ] + } + ],".ChangeLineBreaks(), json); + } + else + { + Assert.Empty(operation.Security); + } + } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntityDeleteOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntityDeleteOperationHandlerTests.cs index 64ee68c..baaff3f 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntityDeleteOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntityDeleteOperationHandlerTests.cs @@ -5,7 +5,9 @@ using System.Linq; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.OData.Edm; +using Microsoft.OpenApi.OData.Tests; using Xunit; namespace Microsoft.OpenApi.OData.Operation.Tests @@ -57,5 +59,109 @@ namespace Microsoft.OpenApi.OData.Operation.Tests Assert.Null(delete.OperationId); } } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void CreateEntityDeleteReturnsSecurityForDeleteRestrictions(bool enableAnnotation) + { + string annotation = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // Arrange + IEdmModel model = EntitySetGetOperationHandlerTests.GetEdmModel(enableAnnotation ? annotation : ""); + ODataContext context = new ODataContext(model); + IEdmEntitySet customers = model.EntityContainer.FindEntitySet("Customers"); + Assert.NotNull(customers); // guard + ODataPath path = new ODataPath(new ODataNavigationSourceSegment(customers), new ODataKeySegment(customers.EntityType())); + + // Act + var delete = _operationHandler.CreateOperation(context, path); + + // Assert + Assert.NotNull(delete); + Assert.NotNull(delete.Security); + + if (enableAnnotation) + { + Assert.Equal(2, delete.Security.Count); + + string json = delete.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""Delegated (work or school account)"": [ + ""User.ReadBasic.All"", + ""User.Read.All"" + ] + }, + { + ""Application"": [ + ""User.Read.All"", + ""Directory.Read.All"" + ] + } + ],".ChangeLineBreaks(), json); + + Assert.Contains(delete.Parameters, p => p.Name == "odata-debug" && p.In == Models.ParameterLocation.Query); + } + else + { + Assert.Empty(delete.Security); + } + } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntityGetOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntityGetOperationHandlerTests.cs index 44d60c5..5f1b839 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntityGetOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntityGetOperationHandlerTests.cs @@ -6,7 +6,9 @@ using System; using System.Linq; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.OData.Edm; +using Microsoft.OpenApi.OData.Tests; using Xunit; namespace Microsoft.OpenApi.OData.Operation.Tests @@ -100,6 +102,114 @@ namespace Microsoft.OpenApi.OData.Operation.Tests VerifyParameter(annotation, hasRestriction, navigability == "None" ? false : true, "$select"); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void CreateEntityGetOperationReturnsSecurityForReadRestrictions(bool enableAnnotation) + { + string annotation = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // Arrange + IEdmModel model = EntitySetGetOperationHandlerTests.GetEdmModel(enableAnnotation ? annotation : ""); + ODataContext context = new ODataContext(model); + IEdmEntitySet customers = model.EntityContainer.FindEntitySet("Customers"); + Assert.NotNull(customers); // guard + ODataPath path = new ODataPath(new ODataNavigationSourceSegment(customers), new ODataKeySegment(customers.EntityType())); + + // Act + var get = _operationHandler.CreateOperation(context, path); + + // Assert + Assert.NotNull(get); + Assert.NotNull(get.Security); + + if (enableAnnotation) + { + Assert.Equal(2, get.Security.Count); + + string json = get.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""Delegated (work or school account)"": [ + ""User.ReadBasic.All"", + ""User.Read.All"" + ] + }, + { + ""Application"": [ + ""User.Read.All"", + ""Directory.Read.All"" + ] + } + ],".ChangeLineBreaks(), json); + + Assert.Contains(get.Parameters, p => p.Name == "odata-debug" && p.In == Models.ParameterLocation.Header); + } + else + { + Assert.Empty(get.Security); + } + } + private void VerifyParameter(string annotation, bool hasRestriction, bool supported, string queryOption) { // Arrange diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntityPatchOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntityPatchOperationHandlerTests.cs index 9cac4aa..050aa7d 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntityPatchOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntityPatchOperationHandlerTests.cs @@ -5,7 +5,9 @@ using System.Linq; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.OData.Edm; +using Microsoft.OpenApi.OData.Tests; using Xunit; namespace Microsoft.OpenApi.OData.Operation.Tests @@ -57,5 +59,109 @@ namespace Microsoft.OpenApi.OData.Operation.Tests Assert.Null(patch.OperationId); } } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void CreateEntityPatchReturnsSecurityForUpdateRestrictions(bool enableAnnotation) + { + string annotation = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // Arrange + IEdmModel model = EntitySetGetOperationHandlerTests.GetEdmModel(enableAnnotation ? annotation : ""); + ODataContext context = new ODataContext(model); + IEdmEntitySet customers = model.EntityContainer.FindEntitySet("Customers"); + Assert.NotNull(customers); // guard + ODataPath path = new ODataPath(new ODataNavigationSourceSegment(customers), new ODataKeySegment(customers.EntityType())); + + // Act + var patch = _operationHandler.CreateOperation(context, path); + + // Assert + Assert.NotNull(patch); + Assert.NotNull(patch.Security); + + if (enableAnnotation) + { + Assert.Equal(2, patch.Security.Count); + + string json = patch.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""Delegated (work or school account)"": [ + ""User.ReadBasic.All"", + ""User.Read.All"" + ] + }, + { + ""Application"": [ + ""User.Read.All"", + ""Directory.Read.All"" + ] + } + ],".ChangeLineBreaks(), json); + + Assert.Contains(patch.Parameters, p => p.Name == "odata-debug" && p.In == Models.ParameterLocation.Header); + } + else + { + Assert.Empty(patch.Security); + } + } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntitySetGetOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntitySetGetOperationHandlerTests.cs index 6c50f60..b4076eb 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntitySetGetOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntitySetGetOperationHandlerTests.cs @@ -10,7 +10,9 @@ using System.Xml.Linq; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Csdl; using Microsoft.OData.Edm.Validation; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.OData.Edm; +using Microsoft.OpenApi.OData.Tests; using Xunit; namespace Microsoft.OpenApi.OData.Operation.Tests @@ -206,6 +208,108 @@ namespace Microsoft.OpenApi.OData.Operation.Tests VerifyParameter(annotation, hasRestriction, navigability == "None" ? false : true, "$select", false); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void CreateEntitySetGetOperationReturnsSecurityForReadRestrictions(bool enableAnnotation) + { + string annotation = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // Arrange + IEdmModel model = GetEdmModel(enableAnnotation ? annotation : ""); + ODataContext context = new ODataContext(model); + IEdmEntitySet customers = model.EntityContainer.FindEntitySet("Customers"); + Assert.NotNull(customers); // guard + ODataPath path = new ODataPath(new ODataNavigationSourceSegment(customers)); + + // Act + var get = _operationHandler.CreateOperation(context, path); + + // Assert + Assert.NotNull(get); + Assert.NotNull(get.Security); + + if (enableAnnotation) + { + Assert.Equal(2, get.Security.Count); + + string json = get.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""Delegated (work or school account)"": [ + ""User.ReadBasic.All"", + ""User.Read.All"" + ] + }, + { + ""Application"": [ + ""User.Read.All"", + ""Directory.Read.All"" + ] + } + ],".ChangeLineBreaks(), json); + } + else + { + Assert.Empty(get.Security); + } + } + public static IEdmModel GetEdmModel(string annotation) { const string template = @" diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntitySetPostOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntitySetPostOperationHandlerTests.cs index f29bf2f..ad15568 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntitySetPostOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntitySetPostOperationHandlerTests.cs @@ -4,7 +4,10 @@ // ------------------------------------------------------------ using Microsoft.OData.Edm; +using Microsoft.OpenApi.Extensions; +using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Edm; +using Microsoft.OpenApi.OData.Tests; using Xunit; namespace Microsoft.OpenApi.OData.Operation.Tests @@ -53,5 +56,113 @@ namespace Microsoft.OpenApi.OData.Operation.Tests Assert.Null(post.OperationId); } } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void CreateEntitySetPostReturnsSecurityForInsertRestrictions(bool enableAnnotation) + { + string annotation = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // Arrange + IEdmModel model = EntitySetGetOperationHandlerTests.GetEdmModel(enableAnnotation ? annotation : ""); + ODataContext context = new ODataContext(model); + IEdmEntitySet customers = model.EntityContainer.FindEntitySet("Customers"); + Assert.NotNull(customers); // guard + ODataPath path = new ODataPath(new ODataNavigationSourceSegment(customers)); + + // Act + var post = _operationHandler.CreateOperation(context, path); + + // Assert + Assert.NotNull(post); + Assert.NotNull(post.Security); + + if (enableAnnotation) + { + Assert.Equal(2, post.Security.Count); + + string json = post.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""Delegated (work or school account)"": [ + ""User.ReadBasic.All"", + ""User.Read.All"" + ] + }, + { + ""Application"": [ + ""User.Read.All"", + ""Directory.Read.All"" + ] + } + ],".ChangeLineBreaks(), json); + + // Parameters + Assert.Single(post.Parameters); + + Assert.Equal(ParameterLocation.Header, post.Parameters[0].In); + Assert.Equal("odata-debug", post.Parameters[0].Name); + } + else + { + Assert.Empty(post.Security); + } + } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/NavigationPropertyGetOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/NavigationPropertyGetOperationHandlerTests.cs index 5c16ae4..4b16b05 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/NavigationPropertyGetOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/NavigationPropertyGetOperationHandlerTests.cs @@ -5,7 +5,9 @@ using System.Linq; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.OData.Edm; +using Microsoft.OpenApi.OData.PathItem.Tests; using Microsoft.OpenApi.OData.Tests; using Xunit; @@ -61,5 +63,148 @@ namespace Microsoft.OpenApi.OData.Operation.Tests Assert.Null(operation.OperationId); } } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void CreateNavigationGetOperationReturnsSecurityForReadRestrictions(bool enableAnnotation) + { + string annotation = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // Arrange + IEdmModel edmModel = NavigationPropertyPathItemHandlerTest.GetEdmModel(enableAnnotation ? annotation : ""); + Assert.NotNull(edmModel); + ODataContext context = new ODataContext(edmModel); + IEdmEntitySet entitySet = edmModel.EntityContainer.FindEntitySet("Customers"); + Assert.NotNull(entitySet); // guard + IEdmEntityType entityType = entitySet.EntityType(); + + IEdmNavigationProperty property = entityType.DeclaredNavigationProperties().FirstOrDefault(c => c.Name == "Orders"); + Assert.NotNull(property); + + ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet), + new ODataKeySegment(entityType), + new ODataNavigationPropertySegment(property)); + + // Act + var operation = _operationHandler.CreateOperation(context, path); + + // Assert + Assert.NotNull(operation); + Assert.NotNull(operation.Security); + + if (enableAnnotation) + { + Assert.Equal(2, operation.Security.Count); + + string json = operation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""Delegated (work or school account)"": [ + ""User.ReadBasic.All"", + ""User.Read.All"" + ] + }, + { + ""Application"": [ + ""User.Read.All"", + ""Directory.Read.All"" + ] + } + ],".ChangeLineBreaks(), json); + + // with custom header + Assert.Contains(@" + { + ""name"": ""odata-debug"", + ""in"": ""query"", + ""description"": ""Debug support for OData services"", + ""schema"": { + ""type"": ""string"" + }, + ""examples"": { + ""example-1"": { + ""description"": ""Service responds with self-contained..."", + ""value"": ""html"" + }, + ""example-2"": { + ""description"": ""Service responds with JSON document..."", + ""value"": ""json"" + } + } + }".ChangeLineBreaks(), json); + + } + else + { + Assert.Empty(operation.Security); + } + } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/NavigationPropertyPatchOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/NavigationPropertyPatchOperationHandlerTests.cs index ac90bcf..3746ef9 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/NavigationPropertyPatchOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/NavigationPropertyPatchOperationHandlerTests.cs @@ -4,7 +4,9 @@ // ------------------------------------------------------------ using Microsoft.OData.Edm; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.OData.Edm; +using Microsoft.OpenApi.OData.PathItem.Tests; using Microsoft.OpenApi.OData.Tests; using System.Linq; using Xunit; @@ -62,5 +64,150 @@ namespace Microsoft.OpenApi.OData.Operation.Tests Assert.Null(operation.OperationId); } } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void CreateNavigationPatchOperationReturnsSecurityForUpdateRestrictions(bool enableAnnotation) + { + string annotation = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // Arrange + IEdmModel edmModel = NavigationPropertyPathItemHandlerTest.GetEdmModel(enableAnnotation ? annotation : ""); + Assert.NotNull(edmModel); + ODataContext context = new ODataContext(edmModel); + IEdmEntitySet entitySet = edmModel.EntityContainer.FindEntitySet("Customers"); + Assert.NotNull(entitySet); // guard + IEdmEntityType entityType = entitySet.EntityType(); + + IEdmNavigationProperty property = entityType.DeclaredNavigationProperties().FirstOrDefault(c => c.Name == "Orders"); + Assert.NotNull(property); + + ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet), + new ODataKeySegment(entityType), + new ODataNavigationPropertySegment(property), + new ODataKeySegment(property.DeclaringEntityType())); + + // Act + var operation = _operationHandler.CreateOperation(context, path); + + // Assert + Assert.NotNull(operation); + Assert.NotNull(operation.Security); + + if (enableAnnotation) + { + Assert.Equal(2, operation.Security.Count); + + string json = operation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""Delegated (work or school account)"": [ + ""User.ReadBasic.All"", + ""User.Read.All"" + ] + }, + { + ""Application"": [ + ""User.Read.All"", + ""Directory.Read.All"" + ] + } + ],".ChangeLineBreaks(), json); + + // with custom header + Assert.Contains(@" + { + ""name"": ""odata-debug"", + ""in"": ""header"", + ""description"": ""Debug support for OData services"", + ""schema"": { + ""type"": ""string"" + }, + ""examples"": { + ""example-1"": { + ""description"": ""Service responds with self-contained..."", + ""value"": ""html"" + }, + ""example-2"": { + ""description"": ""Service responds with JSON document..."", + ""value"": ""json"" + } + } + }".ChangeLineBreaks(), json); + + } + else + { + Assert.Empty(operation.Security); + } + } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/NavigationPropertyPostOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/NavigationPropertyPostOperationHandlerTests.cs index 2fa3504..969b8da 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/NavigationPropertyPostOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/NavigationPropertyPostOperationHandlerTests.cs @@ -4,7 +4,9 @@ // ------------------------------------------------------------ using Microsoft.OData.Edm; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.OData.Edm; +using Microsoft.OpenApi.OData.PathItem.Tests; using Microsoft.OpenApi.OData.Tests; using System.Linq; using Xunit; @@ -62,5 +64,149 @@ namespace Microsoft.OpenApi.OData.Operation.Tests Assert.Null(operation.OperationId); } } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void CreateNavigationPostOperationReturnsSecurityForInsertRestrictions(bool enableAnnotation) + { + string annotation = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // Arrange + IEdmModel edmModel = NavigationPropertyPathItemHandlerTest.GetEdmModel(enableAnnotation ? annotation : ""); + Assert.NotNull(edmModel); + ODataContext context = new ODataContext(edmModel); + IEdmEntitySet entitySet = edmModel.EntityContainer.FindEntitySet("Customers"); + Assert.NotNull(entitySet); // guard + IEdmEntityType entityType = entitySet.EntityType(); + + IEdmNavigationProperty property = entityType.DeclaredNavigationProperties().FirstOrDefault(c => c.Name == "Orders"); + Assert.NotNull(property); + + ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet), + new ODataKeySegment(entityType), + new ODataNavigationPropertySegment(property)); + + // Act + var operation = _operationHandler.CreateOperation(context, path); + + // Assert + Assert.NotNull(operation); + Assert.NotNull(operation.Security); + + if (enableAnnotation) + { + Assert.Equal(2, operation.Security.Count); + + string json = operation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""Delegated (work or school account)"": [ + ""User.ReadBasic.All"", + ""User.Read.All"" + ] + }, + { + ""Application"": [ + ""User.Read.All"", + ""Directory.Read.All"" + ] + } + ],".ChangeLineBreaks(), json); + + // with custom header + Assert.Contains(@" + { + ""name"": ""odata-debug"", + ""in"": ""header"", + ""description"": ""Debug support for OData services"", + ""schema"": { + ""type"": ""string"" + }, + ""examples"": { + ""example-1"": { + ""description"": ""Service responds with self-contained..."", + ""value"": ""html"" + }, + ""example-2"": { + ""description"": ""Service responds with JSON document..."", + ""value"": ""json"" + } + } + }".ChangeLineBreaks(), json); + + } + else + { + Assert.Empty(operation.Security); + } + } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/SingletonGetOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/SingletonGetOperationHandlerTests.cs index d290340..0e0e5a6 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/SingletonGetOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/SingletonGetOperationHandlerTests.cs @@ -10,7 +10,9 @@ using System.Xml.Linq; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Csdl; using Microsoft.OData.Edm.Validation; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.OData.Edm; +using Microsoft.OpenApi.OData.Tests; using Xunit; namespace Microsoft.OpenApi.OData.Operation.Tests @@ -105,6 +107,136 @@ namespace Microsoft.OpenApi.OData.Operation.Tests VerifyParameter(annotation, hasRestriction, navigability == "None" ? false : true, "$select"); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ReadRestrictionsTermWorksToCreateOperationForSingletonGetOperation(bool enableAnnotation) + { + string annotation = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // Arrange + var edmModel = GetEdmModel(enableAnnotation ? annotation : ""); + + Assert.NotNull(edmModel); + IEdmSingleton me = edmModel.EntityContainer.FindSingleton("Me"); + Assert.NotNull(me); + + ODataContext context = new ODataContext(edmModel); + + ODataPath path = new ODataPath(new ODataNavigationSourceSegment(me)); + + // Act + var operation = _operationHandler.CreateOperation(context, path); + + // Assert + Assert.NotNull(operation); + Assert.NotNull(operation.Security); + + if (enableAnnotation) + { + Assert.Equal(2, operation.Security.Count); + + string json = operation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""Delegated (work or school account)"": [ + ""User.ReadBasic.All"", + ""User.Read.All"" + ] + }, + { + ""Application"": [ + ""User.Read.All"", + ""Directory.Read.All"" + ] + } + ],".ChangeLineBreaks(), json); + + // with custom header + Assert.Contains(@" + ""parameters"": [ + { + ""name"": ""odata-debug"", + ""in"": ""header"", + ""description"": ""Debug support for OData services"", + ""schema"": { + ""type"": ""string"" + }, + ""examples"": { + ""example-1"": { + ""description"": ""Service responds with self-contained..."", + ""value"": ""html"" + }, + ""example-2"": { + ""description"": ""Service responds with JSON document..."", + ""value"": ""json"" + } + } + }, + {".ChangeLineBreaks(), json); + } + else + { + Assert.Empty(operation.Security); + } + } + public static IEdmModel GetEdmModel(string annotation) { const string template = @" diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/SingletonPatchOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/SingletonPatchOperationHandlerTests.cs index 230fb62..16ac5ee 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/SingletonPatchOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/SingletonPatchOperationHandlerTests.cs @@ -5,9 +5,11 @@ using System.Linq; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Edm; using Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests; +using Microsoft.OpenApi.OData.Tests; using Xunit; namespace Microsoft.OpenApi.OData.Operation.Tests @@ -75,32 +77,24 @@ namespace Microsoft.OpenApi.OData.Operation.Tests - - - - - - - - RequiredScopes1 - RequiredScopes2 - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -207,6 +201,65 @@ namespace Microsoft.OpenApi.OData.Operation.Tests var securityRequirement = Assert.Single(securityRequirements); Assert.Equal("authorizationName", securityRequirement.Key.Reference.Id); Assert.Equal(new[] { "scopeName1", "scopeName2" }, securityRequirement.Value); + + string json = patch.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Contains(@" + ""security"": [ + { + ""authorizationName"": [ + ""scopeName1"", + ""scopeName2"" + ] + } + ],".ChangeLineBreaks(), json); + + // with custom header + Assert.Contains(@" + ""parameters"": [ + { + ""name"": ""HeadName1"", + ""in"": ""header"", + ""description"": ""Description1"", + ""required"": true, + ""schema"": { + ""type"": ""string"" + }, + ""examples"": { + ""example-1"": { + ""description"": ""Description11"", + ""value"": ""value1"" + } + } + }, + { + ""name"": ""HeadName2"", + ""in"": ""header"", + ""description"": ""Description2"", + ""schema"": { + ""type"": ""string"" + }, + ""examples"": { + ""example-1"": { + ""description"": ""Description22"", + ""value"": ""value2"" + } + } + }, + { + ""name"": ""QueryName1"", + ""in"": ""query"", + ""description"": ""Description3"", + ""required"": true, + ""schema"": { + ""type"": ""string"" + }, + ""examples"": { + ""example-1"": { + ""description"": ""Description33"", + ""value"": ""value3"" + } + } + }".ChangeLineBreaks(), json); } else { diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs index 8d5f01b..ced211f 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs @@ -179,17 +179,72 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests } } + [Theory] + [MemberData(nameof(CollectionNavigationPropertyData))] + [MemberData(nameof(SingleNavigationPropertyData))] + public void CreatePathItemForNavigationPropertyAndReadRestrictions(bool hasRestrictions, string navigationPropertyPath) + { + // Arrange + string annotation = String.Format(@" + + + + + + + + + + + + + + + +", navigationPropertyPath); + + IEdmModel model = GetEdmModel(hasRestrictions ? annotation : ""); + ODataContext context = new ODataContext(model); + IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers"); + Assert.NotNull(entitySet); // guard + + ODataPath path = CreatePath(entitySet, navigationPropertyPath, false); + + // Act + var pathItem = _pathItemHandler.CreatePathItem(context, path); + + // Assert + Assert.NotNull(pathItem); + Assert.NotNull(pathItem.Operations); + + if (hasRestrictions) + { + Assert.DoesNotContain(pathItem.Operations, o => o.Key == OperationType.Get); + } + else + { + Assert.Contains(pathItem.Operations, o => o.Key == OperationType.Get); + } + } + [Theory] [MemberData(nameof(CollectionNavigationPropertyData))] public void CreatePathItemForNavigationPropertyAndInsertRestrictions(bool hasRestrictions, string navigationPropertyPath) { // Arrange string annotation = String.Format(@" - + - + - {0} + + + + + + + + @@ -233,11 +288,18 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests { // Arrange string annotation = String.Format(@" - + - + - {0} + + + + + + + + diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/BatchSupportedTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/BatchSupportedTests.cs deleted file mode 100644 index 11d472f..0000000 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/BatchSupportedTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -// ------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. -// ------------------------------------------------------------ - -using Microsoft.OData.Edm; -using Microsoft.OData.Edm.Csdl; -using Microsoft.OData.Edm.Vocabularies; -using Xunit; - -namespace Microsoft.OpenApi.OData.Reader.Capabilities.Tests -{ -#if false - public class BatchSupportedTests - { - [Fact] - public void KindPropertyReturnsBatchSupportedEnumMember() - { - // Arrange & Act - BatchSupported batch = new BatchSupported(); - - // Assert - Assert.Equal(CapabilitesTermKind.BatchSupported, batch.Kind); - } - - [Fact] - public void UnknownAnnotatableTargetReturnsDefaultBatchSupportedValues() - { - // Arrange - BatchSupported batch = new BatchSupported(); - EdmEntityType entityType = new EdmEntityType("NS", "Entity"); - - // Act - bool result = batch.Load(EdmCoreModel.Instance, entityType); - - // Assert - Assert.False(result); - Assert.True(batch.IsSupported); - Assert.Null(batch.Supported); - } - - [Theory] - [InlineData(EdmVocabularyAnnotationSerializationLocation.Inline, true)] - [InlineData(EdmVocabularyAnnotationSerializationLocation.Inline, false)] - [InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine, true)] - [InlineData(EdmVocabularyAnnotationSerializationLocation.OutOfLine, false)] - public void EntitySetContainerReturnsCorrectBatchSupportedValue(EdmVocabularyAnnotationSerializationLocation location, bool support) - { - // Arrange - IEdmModel model = GetEdmModel(location, support); - Assert.NotNull(model); // guard - - // Act - BatchSupported batch = new BatchSupported(); - bool result = batch.Load(model, model.EntityContainer); - - // Assert - Assert.True(result); - Assert.NotNull(batch.Supported); - Assert.Equal(support, batch.Supported.Value); - Assert.Equal(support, batch.IsSupported); - } - - private static IEdmModel GetEdmModel(EdmVocabularyAnnotationSerializationLocation location, bool supported) - { - EdmModel model = new EdmModel(); - EdmEntityContainer container = new EdmEntityContainer("NS", "Default"); - model.AddElement(container); - IEdmTerm term = model.FindTerm(CapabilitiesConstants.BatchSupported); - Assert.NotNull(term); - - IEdmBooleanConstantExpression boolean = new EdmBooleanConstant(supported); - EdmVocabularyAnnotation annotation = new EdmVocabularyAnnotation(container, term, boolean); - annotation.SetSerializationLocation(model, location); - model.SetVocabularyAnnotation(annotation); - return model; - } - } -#endif -} diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/DeleteRestrictionsTypeTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/DeleteRestrictionsTypeTests.cs index 916e97b..e1fd824 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/DeleteRestrictionsTypeTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/DeleteRestrictionsTypeTests.cs @@ -35,8 +35,9 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests new EdmPropertyConstructor("NonDeletableNavigationProperties", new EdmCollectionExpression(new EdmNavigationPropertyPathExpression("abc"), new EdmNavigationPropertyPathExpression("RelatedEvents"))), new EdmPropertyConstructor("MaxLevels", new EdmIntegerConstant(42)), - new EdmPropertyConstructor("Permission", new EdmRecordExpression( - new EdmPropertyConstructor("Scheme", new EdmRecordExpression(new EdmPropertyConstructor("Authorization", new EdmStringConstant("schemeName")))))), + new EdmPropertyConstructor("Permissions", new EdmCollectionExpression( + new EdmRecordExpression( + new EdmPropertyConstructor("SchemeName", new EdmStringConstant("schemeName"))))), new EdmPropertyConstructor("CustomQueryOptions", new EdmCollectionExpression( new EdmRecordExpression( new EdmPropertyConstructor("Name", new EdmStringConstant("odata-debug")), @@ -113,14 +114,12 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests - - - - - - - - + + + + + + @@ -157,8 +156,8 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests Assert.True(delete.IsNonDeletableNavigationProperty("RelatedEvents")); - Assert.NotNull(delete.Permission); - Assert.Equal("schemeName", delete.Permission.Scheme.Authorization); + Assert.NotNull(delete.Permissions); + //Assert.Equal("schemeName", delete.Permissions); Assert.Null(delete.CustomHeaders); diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/InsertRestrictionsTypeTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/InsertRestrictionsTypeTests.cs index c16818c..0cbce5c 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/InsertRestrictionsTypeTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/InsertRestrictionsTypeTests.cs @@ -173,7 +173,7 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests Assert.False(insert.IsNonInsertableNavigationProperty("MyUnknownNavigationProperty")); Assert.Null(insert.QueryOptions); - Assert.Null(insert.Permission); + Assert.Null(insert.Permissions); Assert.Null(insert.CustomHeaders); Assert.NotNull(insert.MaxLevels); diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/KeyAsSegmentSupportedTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/KeyAsSegmentSupportedTests.cs index dc999d8..797f6b8 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/KeyAsSegmentSupportedTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/KeyAsSegmentSupportedTests.cs @@ -6,9 +6,9 @@ using Microsoft.OData.Edm; using Microsoft.OData.Edm.Csdl; using Microsoft.OData.Edm.Vocabularies; -using Xunit; -using Microsoft.OpenApi.OData.Vocabulary.Capabilities; using Microsoft.OpenApi.OData.Edm; +using Microsoft.OpenApi.OData.Vocabulary.Capabilities; +using Xunit; namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests { diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/OperationRestrictionTypeTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/OperationRestrictionsTypeTests.cs similarity index 90% rename from test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/OperationRestrictionTypeTests.cs rename to test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/OperationRestrictionsTypeTests.cs index 80f42f8..f7e94dc 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/OperationRestrictionTypeTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/OperationRestrictionsTypeTests.cs @@ -15,13 +15,13 @@ using Xunit; namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests { - public class OperationRestrictionTypeTests + public class OperationRestrictionsTypeTests { [Fact] public void TermAttributeAttachedOnOperationRestrictionType() { // Arrange & Act - string qualifiedName = Utils.GetTermQualifiedName(); + string qualifiedName = Utils.GetTermQualifiedName(); // Assert Assert.Equal("Org.OData.Capabilities.V1.OperationRestrictions", qualifiedName); @@ -38,12 +38,12 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests new EdmPropertyConstructor("Description", new EdmStringConstant("head desc")), new EdmPropertyConstructor("DocumentationURL", new EdmStringConstant("http://any3")), new EdmPropertyConstructor("Required", new EdmBooleanConstant(true))))) - // Permission + // Permissions // CustomQueryOptions ); // Act - OperationRestrictionType operation = new OperationRestrictionType(); + OperationRestrictionsType operation = new OperationRestrictionsType(); operation.Initialize(record); // Assert @@ -75,7 +75,7 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests Assert.NotNull(edmOperation); // Act - OperationRestrictionType operation = model.GetRecord(edmOperation, "NS.MyOperationRestriction"); + OperationRestrictionsType operation = model.GetRecord(edmOperation, "NS.MyOperationRestriction"); // Assert VerifyOperationRestrictions(operation); @@ -103,11 +103,12 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests return model; } - private static void VerifyOperationRestrictions(OperationRestrictionType operation) + private static void VerifyOperationRestrictions(OperationRestrictionsType operation) { Assert.NotNull(operation); - Assert.Null(operation.Permission); + Assert.Null(operation.FilterSegmentSupported); + Assert.Null(operation.Permissions); Assert.Null(operation.CustomQueryOptions); Assert.NotNull(operation.CustomHeaders); diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/PermissionTypeTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/PermissionTypeTests.cs index f4751a1..8a1dff0 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/PermissionTypeTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/PermissionTypeTests.cs @@ -23,7 +23,7 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests PermissionType permission = new PermissionType(); // Assert - Assert.Null(permission.Scheme); + Assert.Null(permission.SchemeName); Assert.Null(permission.Scopes); } @@ -42,8 +42,7 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests { // Arrange IEdmRecordExpression record = new EdmRecordExpression( - new EdmPropertyConstructor("Scheme", new EdmRecordExpression( - new EdmPropertyConstructor("Authorization", new EdmStringConstant("scheme name")))), + new EdmPropertyConstructor("SchemeName", new EdmStringConstant("scheme name")), new EdmPropertyConstructor("Scopes", new EdmCollectionExpression(new EdmRecordExpression( new EdmPropertyConstructor("Scope", new EdmStringConstant("scope name")))))); @@ -61,11 +60,7 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests // Arrange string annotation = @" - - - - - + @@ -110,9 +105,8 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests { Assert.NotNull(permission); - Assert.NotNull(permission.Scheme); - Assert.Equal("scheme name", permission.Scheme.Authorization); - Assert.Null(permission.Scheme.RequiredScopes); + Assert.NotNull(permission.SchemeName); + Assert.Equal("scheme name", permission.SchemeName); Assert.NotNull(permission.Scopes); ScopeType scope = Assert.Single(permission.Scopes); diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/ReadRestrictionsTypeTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/ReadRestrictionsTypeTests.cs index 32dd06f..ef0025d 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/ReadRestrictionsTypeTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/ReadRestrictionsTypeTests.cs @@ -146,7 +146,7 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests Assert.NotNull(read.Readable); Assert.False(read.Readable.Value); - Assert.Null(read.Permission); + Assert.Null(read.Permissions); Assert.Null(read.CustomHeaders); Assert.NotNull(read.CustomQueryOptions); @@ -160,7 +160,7 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests Assert.NotNull(read.ReadByKeyRestrictions.Readable); Assert.True(read.ReadByKeyRestrictions.Readable.Value); - Assert.Null(read.ReadByKeyRestrictions.Permission); + Assert.Null(read.ReadByKeyRestrictions.Permissions); Assert.Null(read.ReadByKeyRestrictions.CustomQueryOptions); Assert.NotNull(read.ReadByKeyRestrictions.CustomHeaders); diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/UpdateRestrictionsTypeTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/UpdateRestrictionsTypeTests.cs index d9222c8..e86a670 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/UpdateRestrictionsTypeTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Capabilities/UpdateRestrictionsTypeTests.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System; +using System.Data.Odbc; using System.Linq; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Csdl; @@ -100,32 +101,24 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests - - - - - - - - RequiredScopes1 - RequiredScopes2 - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -235,6 +228,12 @@ namespace Microsoft.OpenApi.OData.Reader.Vocabulary.Capabilities.Tests Assert.NotNull(update.MaxLevels); Assert.Equal(8, update.MaxLevels); + // Permissions + Assert.NotNull(update.Permissions); + PermissionType permission = Assert.Single(update.Permissions); + Assert.Equal("authorizationName", permission.SchemeName); + Assert.Equal(2, permission.Scopes.Count); + // QueryOptions Assert.NotNull(update.QueryOptions); Assert.True(update.QueryOptions.ComputeSupported); diff --git a/tool/UpdateDocs/UpdateDocs.csproj b/tool/UpdateDocs/UpdateDocs.csproj index a8fc673..1bd833a 100644 --- a/tool/UpdateDocs/UpdateDocs.csproj +++ b/tool/UpdateDocs/UpdateDocs.csproj @@ -32,11 +32,11 @@ 4 - - packages\Microsoft.OData.Edm.7.6.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll + + packages\Microsoft.OData.Edm.7.6.1-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll - - packages\Microsoft.OpenApi.1.1.2\lib\net46\Microsoft.OpenApi.dll + + packages\Microsoft.OpenApi.1.1.4\lib\net46\Microsoft.OpenApi.dll diff --git a/tool/UpdateDocs/packages.config b/tool/UpdateDocs/packages.config index ac1a6c6..24edad7 100644 --- a/tool/UpdateDocs/packages.config +++ b/tool/UpdateDocs/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file