Update to ODL.Edm 7.6.1.beta: Permission, Custom Heads, etc

This commit is contained in:
Sam Xu 2019-09-24 16:06:15 -07:00
parent f362c34e31
commit 1589b2622a
67 changed files with 2305 additions and 319 deletions

View file

@ -695949,9 +695949,9 @@
},
"microsoft.graph.rgbColor": {
"value": {
"b": 0,
"g": 0,
"r": 0
"b": "AA==",
"g": "AA==",
"r": "AA=="
}
},
"microsoft.graph.mimeContent": {

View file

@ -515204,9 +515204,9 @@
},
"microsoft.graph.rgbColor": {
"value": {
"b": 0,
"g": 0,
"r": 0
"b": "AA==",
"g": "AA==",
"r": "AA=="
}
},
"microsoft.graph.deviceCategory": {

View file

@ -515204,9 +515204,9 @@
},
"microsoft.graph.rgbColor": {
"value": {
"b": 0,
"g": 0,
"r": 0
"b": "AA==",
"g": "AA==",
"r": "AA=="
}
},
"microsoft.graph.deviceCategory": {

View file

@ -32,7 +32,7 @@ namespace Microsoft.OpenApi.OData.Edm
public override ODataSegmentKind Kind => ODataSegmentKind.Key;
/// <inheritdoc />
public override string Name
public override string Identifier
{
get
{

View file

@ -34,7 +34,7 @@ namespace Microsoft.OpenApi.OData.Edm
public override ODataSegmentKind Kind => ODataSegmentKind.NavigationProperty;
/// <inheritdoc />
public override string Name { get => NavigationProperty.Name; }
public override string Identifier { get => NavigationProperty.Name; }
/// <inheritdoc />
public override string GetPathItemName(OpenApiConvertSettings settings) => NavigationProperty.Name;

View file

@ -31,7 +31,7 @@ namespace Microsoft.OpenApi.OData.Edm
public override IEdmEntityType EntityType => NavigationSource.EntityType();
/// <inheritdoc />
public override string Name { get => NavigationSource.Name; }
public override string Identifier { get => NavigationSource.Name; }
/// <inheritdoc />
public override ODataSegmentKind Kind => ODataSegmentKind.NavigationSource;

View file

@ -34,7 +34,7 @@ namespace Microsoft.OpenApi.OData.Edm
public override ODataSegmentKind Kind => ODataSegmentKind.OperationImport;
/// <inheritdoc />
public override string Name { get => OperationImport.Name; }
public override string Identifier { get => OperationImport.Name; }
/// <inheritdoc />
public override string GetPathItemName(OpenApiConvertSettings settings)

View file

@ -34,7 +34,7 @@ namespace Microsoft.OpenApi.OData.Edm
public override ODataSegmentKind Kind => ODataSegmentKind.Operation;
/// <inheritdoc />
public override string Name { get => Operation.Name; }
public override string Identifier { get => Operation.Name; }
/// <inheritdoc />
public override string GetPathItemName(OpenApiConvertSettings settings)

View file

@ -60,9 +60,9 @@ namespace Microsoft.OpenApi.OData.Edm
public abstract ODataSegmentKind Kind { get; }
/// <summary>
/// Gets the name of this segment.
/// Gets the identifier of this segment.
/// </summary>
public abstract string Name { get; }
public abstract string Identifier { get; }
/// <summary>
/// Gets the path item name for this segment.

View file

@ -29,7 +29,7 @@ namespace Microsoft.OpenApi.OData.Edm
public override ODataSegmentKind Kind => ODataSegmentKind.TypeCast;
/// <inheritdoc />
public override string Name { get => EntityType.FullTypeName(); }
public override string Identifier { get => EntityType.FullTypeName(); }
/// <inheritdoc />
public override string GetPathItemName(OpenApiConvertSettings settings) => EntityType.FullTypeName();

View file

@ -20,7 +20,7 @@ namespace Microsoft.OpenApi.OData
public static class EdmModelOpenApiExtensions
{
/// <summary>
/// Convert <see cref="IEdmModel"/> to <see cref="OpenApiDocument"/>.
/// Convert <see cref="IEdmModel"/> to <see cref="OpenApiDocument"/> using default settings.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <returns>The converted Open API document object, <see cref="OpenApiDocument"/>.</returns>

View file

@ -73,7 +73,7 @@ namespace Microsoft.OpenApi.OData.Generator
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = permission.Scheme.Authorization
Id = permission.SchemeName
}
}
] = new List<string>(permission.Scopes?.Select(c => c.Scope) ?? new List<string>())

View file

@ -20,8 +20,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.OData.Edm" Version="7.6.0" />
<PackageReference Include="Microsoft.OpenApi" Version="1.1.2" />
<PackageReference Include="Microsoft.OData.Edm" Version="7.6.1-beta" />
<PackageReference Include="Microsoft.OpenApi" Version="1.1.4" />
</ItemGroup>
<ItemGroup>

View file

@ -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);
}
}
/// <inheritdoc/>

View file

@ -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);
}
/// <inheritdoc/>
protected override void SetSecurity(OpenApiOperation operation)
{
OperationRestrictionsType restriction = Context.Model.GetRecord<OperationRestrictionsType>(EdmOperationImport, CapabilitiesConstants.OperationRestrictions);
if (restriction == null || restriction.Permissions == null)
{
return;
}
operation.Security = Context.CreateSecurityRequirements(restriction.Permissions).ToList();
}
/// <inheritdoc/>
protected override void AppendCustomParameters(OpenApiOperation operation)
{
OperationRestrictionsType restriction = Context.Model.GetRecord<OperationRestrictionsType>(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);
}
}
/// <inheritdoc/>
protected override void SetTags(OpenApiOperation operation)
{

View file

@ -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
/// <inheritdoc/>
protected override void SetSecurity(OpenApiOperation operation)
{
IEnumerable<OperationRestrictionType> restrictions = Context.Model.GetCollection<OperationRestrictionType>(EdmOperation, CapabilitiesConstants.OperationRestrictions);
if (restrictions == null || !restrictions.Any())
OperationRestrictionsType restriction = Context.Model.GetRecord<OperationRestrictionsType>(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();
}
/// <inheritdoc/>
protected override void AppendCustomParameters(OpenApiOperation operation)
{
IEnumerable<OperationRestrictionType> restrictions = Context.Model.GetCollection<OperationRestrictionType>(EdmOperation, CapabilitiesConstants.OperationRestrictions);
if (restrictions == null || !restrictions.Any())
OperationRestrictionsType restriction = Context.Model.GetRecord<OperationRestrictionsType>(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);
}
}
}

View file

@ -71,14 +71,12 @@ namespace Microsoft.OpenApi.OData.Operation
protected override void SetSecurity(OpenApiOperation operation)
{
DeleteRestrictionsType delete = Context.Model.GetRecord<DeleteRestrictionsType>(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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -83,14 +83,12 @@ namespace Microsoft.OpenApi.OData.Operation
protected override void SetSecurity(OpenApiOperation operation)
{
UpdateRestrictionsType update = Context.Model.GetRecord<UpdateRestrictionsType>(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);
}
}
}

View file

@ -165,14 +165,12 @@ namespace Microsoft.OpenApi.OData.Operation
protected override void SetSecurity(OpenApiOperation operation)
{
ReadRestrictionsType read = Context.Model.GetRecord<ReadRestrictionsType>(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);
}
}
}

View file

@ -109,14 +109,12 @@ namespace Microsoft.OpenApi.OData.Operation
protected override void SetSecurity(OpenApiOperation operation)
{
InsertRestrictionsType insert = Context.Model.GetRecord<InsertRestrictionsType>(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);
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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
/// </summary>
protected string NavigationPropertyPath { get; private set; }
/// <summary>
/// Gets the navigation restriction.
/// </summary>
protected NavigationPropertyRestriction Restriction { get; private set; }
/// <summary>
/// Gets a bool value indicating whether the last segment is a key segment.
/// </summary>
@ -56,10 +62,25 @@ namespace Microsoft.OpenApi.OData.Operation
NavigationProperty = npSegment.NavigationProperty;
NavigationPropertyPath = string.Join("/",
path.Segments.OfType<ODataNavigationPropertySegment>().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<NavigationRestrictionsType>(entitySet, CapabilitiesConstants.NavigationRestrictions);
}
else
{
navigation = Context.Model.GetRecord<NavigationRestrictionsType>(singleton, CapabilitiesConstants.NavigationRestrictions);
}
if (navigation != null && navigation.RestrictedProperties != null)
{
Restriction = navigation.RestrictedProperties.FirstOrDefault(r => r.NavigationProperty != null && r.NavigationProperty == NavigationPropertyPath);
}
}
/// <inheritdoc/>

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -167,7 +167,7 @@ namespace Microsoft.OpenApi.OData.Operation
/// <param name="parameters">The parameters.</param>
/// <param name="customParameters">The custom parameters.</param>
/// <param name="location">The parameter location.</param>
protected static void AppendCustomParameters(IList<OpenApiParameter> parameters, IList<CustomParameter> customParameters, ParameterLocation location)
protected static void AppendCustomParameters(OpenApiOperation operation, IList<CustomParameter> customParameters, ParameterLocation location)
{
foreach (var param in customParameters)
{
@ -206,7 +206,7 @@ namespace Microsoft.OpenApi.OData.Operation
}
}
parameters.Add(parameter);
operation.Parameters.Add(parameter);
}
}
}

View file

@ -100,14 +100,12 @@ namespace Microsoft.OpenApi.OData.Operation
protected override void SetSecurity(OpenApiOperation operation)
{
ReadRestrictionsType read = Context.Model.GetRecord<ReadRestrictionsType>(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();
}
/// <inheritdoc/>
@ -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);
}
}
}

View file

@ -84,14 +84,12 @@ namespace Microsoft.OpenApi.OData.Operation
protected override void SetSecurity(OpenApiOperation operation)
{
UpdateRestrictionsType update = Context.Model.GetRecord<UpdateRestrictionsType>(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();
}
/// <inheritdoc/>
@ -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);
}
}
}

View file

@ -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<NavigationRestrictionsType>(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<UpdateRestrictionsType>(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<InsertRestrictionsType>(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<UpdateRestrictionsType>(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);
}
}
}
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{

View file

@ -32,10 +32,20 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
/// </summary>
public int? MaxLevels { get; private set; }
/// <summary>
/// Gets the Members of collections can be updated via a PATCH request with a `/$filter(...)/$each` segment.
/// </summary>
public bool? FilterSegmentSupported { get; private set; }
/// <summary>
/// Gets the Members of collections can be updated via a PATCH request with a type-cast segment and a `/$each` segment.
/// </summary>
public bool? TypecastSegmentSupported { get; private set; }
/// <summary>
/// Gets the required scopes to perform the insert.
/// </summary>
public PermissionType Permission { get; private set; }
public IList<PermissionType> Permissions { get; private set; }
/// <summary>
/// Gets the Supported or required custom headers.
@ -47,6 +57,16 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
/// </summary>
public IList<CustomParameter> CustomQueryOptions { get; private set; }
/// <summary>
/// Gets A brief description of the request.
/// </summary>
public string Description { get; private set; }
/// <summary>
/// Gets A lengthy description of the request.
/// </summary>
public string LongDescription { get; private set; }
/// <summary>
/// Test the target supports delete.
/// </summary>
@ -82,14 +102,26 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
// MaxLevels
MaxLevels = (int?)record.GetInteger("MaxLevels");
// Permission
Permission = record.GetRecord<PermissionType>("Permission");
// FilterSegmentSupported
FilterSegmentSupported = record.GetBoolean("FilterSegmentSupported");
// TypecastSegmentSupported
TypecastSegmentSupported = record.GetBoolean("TypecastSegmentSupported");
// Permissions
Permissions = record.GetCollection<PermissionType>("Permissions");
// CustomHeaders
CustomHeaders = record.GetCollection<CustomParameter>("CustomHeaders");
// CustomQueryOptions
CustomQueryOptions = record.GetCollection<CustomParameter>("CustomQueryOptions");
// Description
Description = record.GetString("Description");
// LongDescription
LongDescription = record.GetString("LongDescription");
}
}
}

View file

@ -22,6 +22,11 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
/// </summary>
public bool? Expandable { get; private set; }
/// <summary>
/// Gets the $expand is supported for stream properties and media resources.
/// </summary>
public bool? StreamsExpandable { get; private set; }
/// <summary>
/// Gets the properties which cannot be used in $expand expressions.
/// </summary>
@ -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");

View file

@ -37,10 +37,15 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
/// </summary>
public long? MaxLevels { get; private set; }
/// <summary>
/// Gets the Entities of a specific derived type can be created by specifying a type-cast segment.
/// </summary>
public bool? TypecastSegmentSupported { get; private set; }
/// <summary>
/// Gets the required scopes to perform the insert.
/// </summary>
public PermissionType Permission { get; private set; }
public IList<PermissionType> Permissions { get; private set; }
/// <summary>
/// Gets the Support for query options with insert requests.
@ -57,6 +62,16 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
/// </summary>
public IList<CustomParameter> CustomQueryOptions { get; private set; }
/// <summary>
/// Gets A brief description of the request.
/// </summary>
public string Description { get; private set; }
/// <summary>
/// Gets A lengthy description of the request.
/// </summary>
public string LongDescription { get; private set; }
/// <summary>
/// Test the target supports insert.
/// </summary>
@ -92,8 +107,11 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
// MaxLevels
MaxLevels = record.GetInteger("MaxLevels");
// Permission
Permission = record.GetRecord<PermissionType>("Permission");
// TypecastSegmentSupported
TypecastSegmentSupported = record.GetBoolean("TypecastSegmentSupported");
// Permissions
Permissions = record.GetCollection<PermissionType>("Permissions");
// QueryOptions
QueryOptions = record.GetRecord<ModificationQueryOptionsType>("QueryOptions");
@ -103,6 +121,12 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
// CustomHeaders
CustomQueryOptions = record.GetCollection<CustomParameter>("CustomQueryOptions");
// Description
Description = record.GetString("Description");
// LongDescription
LongDescription = record.GetString("LongDescription");
}
}
}

View file

@ -11,16 +11,20 @@ using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
{
/// <summary>
/// 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
/// </summary>
[Term("Org.OData.Capabilities.V1.OperationRestrictions")]
internal class OperationRestrictionType : IRecord
internal class OperationRestrictionsType : IRecord
{
/// <summary>
/// Gets the Bound action or function can be invoked on a collection-valued binding parameter path with a '/$filter(...)' segment.
/// </summary>
public bool? FilterSegmentSupported { get; private set; }
/// <summary>
/// Gets the List of required scopes to invoke an action or function.
/// </summary>
public PermissionType Permission { get; private set; }
public IList<PermissionType> Permissions { get; private set; }
/// <summary>
/// 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<PermissionType>("Permission");
// FilterSegmentSupported
FilterSegmentSupported = record.GetBoolean("FilterSegmentSupported");
// Permissions
Permissions = record.GetCollection<PermissionType>("Permissions");
// CustomHeaders
CustomHeaders = record.GetCollection<CustomParameter>("CustomHeaders");

View file

@ -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
{
/// <summary>
/// Gets the auth flow scheme name.
/// Gets the Authorization flow scheme name.
/// </summary>
public SecurityScheme Scheme { get; private set; }
public string SchemeName { get; private set; }
/// <summary>
/// Gets the list of scopes that can provide access to the resource.
/// </summary>
public IEnumerable<ScopeType> Scopes { get; private set; }
public IList<ScopeType> Scopes { get; private set; }
/// <summary>
/// Init the <see cref="PermissionType"/>.
@ -34,8 +34,8 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
{
Utils.CheckArgumentNull(record, nameof(record));
// Scheme
Scheme = record.GetRecord<SecurityScheme>("Scheme");
// SchemeName
SchemeName = record.GetString("SchemeName");
// Scopes
Scopes = record.GetCollection<ScopeType>("Scopes");

View file

@ -23,7 +23,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
/// <summary>
/// Gets the List of required scopes to invoke an action or function
/// </summary>
public PermissionType Permission { get; private set; }
public IList<PermissionType> Permissions { get; private set; }
/// <summary>
/// Gets the Supported or required custom headers.
@ -35,6 +35,16 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
/// </summary>
public IList<CustomParameter> CustomQueryOptions { get; private set; }
/// <summary>
/// Gets A brief description of the request.
/// </summary>
public string Description { get; private set; }
/// <summary>
/// Gets A lengthy description of the request.
/// </summary>
public string LongDescription { get; private set; }
/// <summary>
/// Test the target supports update.
/// </summary>
@ -52,14 +62,20 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
// Readable
Readable = record.GetBoolean("Readable");
// Permission
Permission = record.GetRecord<PermissionType>("Permission");
// Permissions
Permissions = record.GetCollection<PermissionType>("Permissions");
// CustomHeaders
CustomHeaders = record.GetCollection<CustomParameter>("CustomHeaders");
// CustomQueryOptions
CustomQueryOptions = record.GetCollection<CustomParameter>("CustomQueryOptions");
// Description
Description = record.GetString("Description");
// LongDescription
LongDescription = record.GetString("LongDescription");
}
}

View file

@ -20,6 +20,11 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
/// </summary>
public bool? Supported { get; private set; }
/// <summary>
/// Gets the Supports instance annotations in $select list.
/// </summary>
public bool? InstanceAnnotationsSupported { get; private set; }
/// <summary>
/// Gets the $expand within $select is supported.
/// </summary>
@ -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");

View file

@ -23,6 +23,26 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
/// </summary>
public bool? Updatable { get; private set; }
/// <summary>
/// Gets the value indicating Entities can be upserted.
/// </summary>
public bool? Upsertable { get; private set; }
/// <summary>
/// Gets the value indicating Entities can be inserted, updated, and deleted via a PATCH request with a delta payload.
/// </summary>
public bool? DeltaUpdateSupported { get; private set; }
/// <summary>
/// Gets the value indicating Members of collections can be updated via a PATCH request with a '/$filter(...)/$each' segment.
/// </summary>
public bool? FilterSegmentSupported { get; private set; }
/// <summary>
/// Gets the value indicating Members of collections can be updated via a PATCH request with a type-cast segment and a '/$each' segment.
/// </summary>
public bool? TypecastSegmentSupported { get; private set; }
/// <summary>
/// Gets the navigation properties which do not allow rebinding.
/// </summary>
@ -35,9 +55,9 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
public long? MaxLevels { get; private set; }
/// <summary>
/// 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.
/// </summary>
public PermissionType Permission { get; private set; }
public IList<PermissionType> Permissions { get; private set; }
/// <summary>
/// Gets/sets the support for query options with update requests.
@ -54,6 +74,16 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
/// </summary>
public IList<CustomParameter> CustomQueryOptions { get; private set; }
/// <summary>
/// Gets A brief description of the request.
/// </summary>
public string Description { get; private set; }
/// <summary>
/// Gets A lengthy description of the request.
/// </summary>
public string LongDescription { get; private set; }
/// <summary>
/// Test the target supports update.
/// </summary>
@ -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<PermissionType>("Permission");
// Permissions
Permissions = record.GetCollection<PermissionType>("Permissions");
// QueryOptions
QueryOptions = record.GetRecord<ModificationQueryOptionsType>("QueryOptions");
@ -100,6 +142,12 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
// CustomQueryOptions
CustomQueryOptions = record.GetCollection<CustomParameter>("CustomQueryOptions");
// Description
Description = record.GetString("Description");
// LongDescription
LongDescription = record.GetString("LongDescription");
}
}
}

View file

@ -14,7 +14,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary
internal class TermAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of <see cref="ODataPath"/> class.
/// Initializes a new instance of <see cref="TermAttribute"/> class.
/// </summary>
/// <param name="qualifiedName">The qualified name of this term.</param>
public TermAttribute(string qualifiedName)

View file

@ -32,11 +32,11 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.OData.Edm, Version=7.6.0.30605, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.OData.Edm.7.6.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll</HintPath>
<Reference Include="Microsoft.OData.Edm, Version=7.6.1.30918, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.OData.Edm.7.6.1-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll</HintPath>
</Reference>
<Reference Include="Microsoft.OpenApi, Version=1.1.2.0, Culture=neutral, PublicKeyToken=3f5743946376f042, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.OpenApi.1.1.2\lib\net46\Microsoft.OpenApi.dll</HintPath>
<Reference Include="Microsoft.OpenApi, Version=1.1.4.0, Culture=neutral, PublicKeyToken=3f5743946376f042, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.OpenApi.1.1.4\lib\net46\Microsoft.OpenApi.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

View file

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace OoasGui

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.OData.Edm" version="7.6.0" targetFramework="net461" />
<package id="Microsoft.OpenApi" version="1.1.2" targetFramework="net461" />
<package id="Microsoft.OData.Edm" version="7.6.1-beta" targetFramework="net461" />
<package id="Microsoft.OpenApi" version="1.1.4" targetFramework="net461" />
</packages>

View file

@ -61,7 +61,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="Microsoft.OpenApi" Version="1.1.2" />
<PackageReference Include="Microsoft.OpenApi" Version="1.1.4" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>

View file

@ -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 = @"<?xml version=""1.0"" encoding=""utf-8""?>
<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<Action Name=""ResetDataSource"" />
<EntityContainer Name=""GraphService"">
<ActionImport Name=""ResetDataSource"" Action=""NS.ResetDataSource"" >
{0}
</ActionImport>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
";
string annotation = @"<Annotation Term=""Org.OData.Capabilities.V1.OperationRestrictions"">
<Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""SchemeName"" String=""Application"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""CustomQueryOptions"">
<Collection>
<Record>
<PropertyValue Property=""Name"" String=""odata-debug"" />
<PropertyValue Property=""Description"" String=""Debug support for OData services"" />
<PropertyValue Property=""Required"" Bool=""false"" />
<PropertyValue Property=""ExampleValues"">
<Collection>
<Record>
<PropertyValue Property=""Value"" String=""html"" />
<PropertyValue Property=""Description"" String=""Service responds with self-contained..."" />
</Record>
<Record>
<PropertyValue Property=""Value"" String=""json"" />
<PropertyValue Property=""Description"" String=""Service responds with JSON document..."" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</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);
}
}
}
}

View file

@ -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 = @"<?xml version=""1.0"" encoding=""utf-8""?>
<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityType Name=""user"" />
<Action Name=""getMemberGroups"" IsBound=""true"">
<Parameter Name=""bindingParameter"" Type=""NS.user"" Nullable=""false"" />
{0}
</Action>
<EntityContainer Name=""GraphService"">
<Singleton Name=""me"" Type=""NS.user"" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
";
string annotation = @"<Annotation Term=""Org.OData.Capabilities.V1.OperationRestrictions"">
<Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""SchemeName"" String=""Application"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</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<IEdmAction>().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);
}
}
}
}

View file

@ -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 = @"<?xml version=""1.0"" encoding=""utf-8""?>
<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<Function Name=""GetNearestAirport"">
<Parameter Name=""lat"" Type=""Edm.Double"" Nullable=""false"" />
<Parameter Name=""lon"" Type=""Edm.Double"" Nullable=""false"" />
<ReturnType Type=""Edm.String"" />
</Function>
<EntityContainer Name=""GraphService"">
<FunctionImport Name=""GetNearestAirport"" Function=""NS.GetNearestAirport"" >
{0}
</FunctionImport>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
";
string annotation = @"<Annotation Term=""Org.OData.Capabilities.V1.OperationRestrictions"">
<Record>
<PropertyValue Property=""CustomHeaders"">
<Collection>
<Record>
<PropertyValue Property=""Name"" String=""myhead1"" />
<PropertyValue Property=""Required"" Bool=""true"" />
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""SchemeName"" String=""Application"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</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);
}
}
}
}

View file

@ -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 = @"<?xml version=""1.0"" encoding=""utf-8""?>
<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityType Name=""user"" />
<Function Name=""getMemberGroups"" IsBound=""true"">
<Parameter Name=""bindingParameter"" Type=""NS.user"" Nullable=""false"" />
<ReturnType Type=""Edm.String"" Nullable=""false"" />
{0}
</Function>
<EntityContainer Name=""GraphService"">
<Singleton Name=""me"" Type=""NS.user"" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
";
string annotation = @"<Annotation Term=""Org.OData.Capabilities.V1.OperationRestrictions"">
<Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""SchemeName"" String=""Application"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</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<IEdmFunction>().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);
}
}
}
}

View file

@ -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 = @"<Annotation Term=""Org.OData.Capabilities.V1.DeleteRestrictions"">
<Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""SchemeName"" String=""Application"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""CustomQueryOptions"">
<Collection>
<Record>
<PropertyValue Property=""Name"" String=""odata-debug"" />
<PropertyValue Property=""Description"" String=""Debug support for OData services"" />
<PropertyValue Property=""Required"" Bool=""false"" />
<PropertyValue Property=""ExampleValues"">
<Collection>
<Record>
<PropertyValue Property=""Value"" String=""html"" />
<PropertyValue Property=""Description"" String=""Service responds with self-contained..."" />
</Record>
<Record>
<PropertyValue Property=""Value"" String=""json"" />
<PropertyValue Property=""Description"" String=""Service responds with JSON document..."" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</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);
}
}
}
}

View file

@ -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 = @"<Annotation Term=""Org.OData.Capabilities.V1.ReadRestrictions"">
<Record>
<PropertyValue Property=""ReadByKeyRestrictions"">
<Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""SchemeName"" String=""Application"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""CustomHeaders"">
<Collection>
<Record>
<PropertyValue Property=""Name"" String=""odata-debug"" />
<PropertyValue Property=""Description"" String=""Debug support for OData services"" />
<PropertyValue Property=""Required"" Bool=""false"" />
<PropertyValue Property=""ExampleValues"">
<Collection>
<Record>
<PropertyValue Property=""Value"" String=""html"" />
<PropertyValue Property=""Description"" String=""Service responds with self-contained..."" />
</Record>
<Record>
<PropertyValue Property=""Value"" String=""json"" />
<PropertyValue Property=""Description"" String=""Service responds with JSON document..."" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</PropertyValue>
</Record>
</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

View file

@ -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 = @"<Annotation Term=""Org.OData.Capabilities.V1.UpdateRestrictions"">
<Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""SchemeName"" String=""Application"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""CustomHeaders"">
<Collection>
<Record>
<PropertyValue Property=""Name"" String=""odata-debug"" />
<PropertyValue Property=""Description"" String=""Debug support for OData services"" />
<PropertyValue Property=""Required"" Bool=""false"" />
<PropertyValue Property=""ExampleValues"">
<Collection>
<Record>
<PropertyValue Property=""Value"" String=""html"" />
<PropertyValue Property=""Description"" String=""Service responds with self-contained..."" />
</Record>
<Record>
<PropertyValue Property=""Value"" String=""json"" />
<PropertyValue Property=""Description"" String=""Service responds with JSON document..."" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</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);
}
}
}
}

View file

@ -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 = @"<Annotation Term=""Org.OData.Capabilities.V1.ReadRestrictions"">
<Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""SchemeName"" String=""Application"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""CustomHeaders"">
<Collection>
<Record>
<PropertyValue Property=""Name"" String=""odata-debug"" />
<PropertyValue Property=""Description"" String=""Debug support for OData services"" />
<PropertyValue Property=""Required"" Bool=""false"" />
<PropertyValue Property=""ExampleValues"">
<Collection>
<Record>
<PropertyValue Property=""Value"" String=""html"" />
<PropertyValue Property=""Description"" String=""Service responds with self-contained..."" />
</Record>
<Record>
<PropertyValue Property=""Value"" String=""json"" />
<PropertyValue Property=""Description"" String=""Service responds with JSON document..."" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</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 = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">

View file

@ -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 = @"<Annotation Term=""Org.OData.Capabilities.V1.InsertRestrictions"">
<Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""SchemeName"" String=""Application"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""CustomHeaders"">
<Collection>
<Record>
<PropertyValue Property=""Name"" String=""odata-debug"" />
<PropertyValue Property=""Description"" String=""Debug support for OData services"" />
<PropertyValue Property=""Required"" Bool=""false"" />
<PropertyValue Property=""ExampleValues"">
<Collection>
<Record>
<PropertyValue Property=""Value"" String=""html"" />
<PropertyValue Property=""Description"" String=""Service responds with self-contained..."" />
</Record>
<Record>
<PropertyValue Property=""Value"" String=""json"" />
<PropertyValue Property=""Description"" String=""Service responds with JSON document..."" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</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);
}
}
}
}

View file

@ -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 = @"<Annotation Term=""Org.OData.Capabilities.V1.NavigationRestrictions"">
<Record>
<PropertyValue Property=""RestrictedProperties"" >
<Collection>
<Record>
<PropertyValue Property=""NavigationProperty"" NavigationPropertyPath=""Orders"" />
<PropertyValue Property=""ReadRestrictions"" >
<Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""SchemeName"" String=""Application"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""CustomQueryOptions"">
<Collection>
<Record>
<PropertyValue Property=""Name"" String=""odata-debug"" />
<PropertyValue Property=""Description"" String=""Debug support for OData services"" />
<PropertyValue Property=""Required"" Bool=""false"" />
<PropertyValue Property=""ExampleValues"">
<Collection>
<Record>
<PropertyValue Property=""Value"" String=""html"" />
<PropertyValue Property=""Description"" String=""Service responds with self-contained..."" />
</Record>
<Record>
<PropertyValue Property=""Value"" String=""json"" />
<PropertyValue Property=""Description"" String=""Service responds with JSON document..."" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</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);
}
}
}
}

View file

@ -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 = @"<Annotation Term=""Org.OData.Capabilities.V1.NavigationRestrictions"">
<Record>
<PropertyValue Property=""RestrictedProperties"" >
<Collection>
<Record>
<PropertyValue Property=""NavigationProperty"" NavigationPropertyPath=""Orders"" />
<PropertyValue Property=""UpdateRestrictions"" >
<Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""SchemeName"" String=""Application"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""Description"" String=""A brief description of GET '/me' request."" />
<PropertyValue Property=""CustomHeaders"">
<Collection>
<Record>
<PropertyValue Property=""Name"" String=""odata-debug"" />
<PropertyValue Property=""Description"" String=""Debug support for OData services"" />
<PropertyValue Property=""Required"" Bool=""false"" />
<PropertyValue Property=""ExampleValues"">
<Collection>
<Record>
<PropertyValue Property=""Value"" String=""html"" />
<PropertyValue Property=""Description"" String=""Service responds with self-contained..."" />
</Record>
<Record>
<PropertyValue Property=""Value"" String=""json"" />
<PropertyValue Property=""Description"" String=""Service responds with JSON document..."" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</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);
}
}
}
}

View file

@ -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 = @"<Annotation Term=""Org.OData.Capabilities.V1.NavigationRestrictions"">
<Record>
<PropertyValue Property=""RestrictedProperties"" >
<Collection>
<Record>
<PropertyValue Property=""NavigationProperty"" NavigationPropertyPath=""Orders"" />
<PropertyValue Property=""InsertRestrictions"" >
<Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""SchemeName"" String=""Application"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""Description"" String=""A brief description of GET '/me' request."" />
<PropertyValue Property=""CustomHeaders"">
<Collection>
<Record>
<PropertyValue Property=""Name"" String=""odata-debug"" />
<PropertyValue Property=""Description"" String=""Debug support for OData services"" />
<PropertyValue Property=""Required"" Bool=""false"" />
<PropertyValue Property=""ExampleValues"">
<Collection>
<Record>
<PropertyValue Property=""Value"" String=""html"" />
<PropertyValue Property=""Description"" String=""Service responds with self-contained..."" />
</Record>
<Record>
<PropertyValue Property=""Value"" String=""json"" />
<PropertyValue Property=""Description"" String=""Service responds with JSON document..."" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</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);
}
}
}
}

View file

@ -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 = @"<Annotation Term=""Org.OData.Capabilities.V1.ReadRestrictions"">
<Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property=""SchemeName"" String=""Application"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
<PropertyValue Property=""Scope"" String=""User.Read.All"" />
</Record>
<Record>
<PropertyValue Property=""Scope"" String=""Directory.Read.All"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""Description"" String=""A brief description of GET '/me' request."" />
<PropertyValue Property=""CustomHeaders"">
<Collection>
<Record>
<PropertyValue Property=""Name"" String=""odata-debug"" />
<PropertyValue Property=""Description"" String=""Debug support for OData services"" />
<PropertyValue Property=""Required"" Bool=""false"" />
<PropertyValue Property=""ExampleValues"">
<Collection>
<Record>
<PropertyValue Property=""Value"" String=""html"" />
<PropertyValue Property=""Description"" String=""Service responds with self-contained..."" />
</Record>
<Record>
<PropertyValue Property=""Value"" String=""json"" />
<PropertyValue Property=""Description"" String=""Service responds with JSON document..."" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</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 = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">

View file

@ -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
</Collection>
</PropertyValue>
<PropertyValue Property=""MaxLevels"" Int=""8"" />
<PropertyValue Property=""Permission"">
<Record Type=""Org.OData.Capabilities.V1.PermissionType"">
<PropertyValue Property=""Scheme"">
<Record Type=""Org.OData.Authorization.V1.SecurityScheme"">
<PropertyValue Property=""Authorization"" String=""authorizationName"" />
<PropertyValue Property=""RequiredScopes"">
<Collection>
<String>RequiredScopes1</String>
<String>RequiredScopes2</String>
</Collection>
</PropertyValue>
</Record>
</PropertyValue>
<PropertyValue Property=""Scopes"">
<Collection>
<Record Type=""Org.OData.Capabilities.V1.ScopeType"">
<PropertyValue Property=""Scope"" String=""scopeName1"" />
<PropertyValue Property=""RestrictedProperties"" String=""p1,p2"" />
</Record>
<Record Type=""Org.OData.Capabilities.V1.ScopeType"">
<PropertyValue Property=""Scope"" String=""scopeName2"" />
<PropertyValue Property=""RestrictedProperties"" String=""p3,p4"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record Type=""Org.OData.Capabilities.V1.PermissionType"">
<PropertyValue Property=""SchemeName"" String=""authorizationName"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record Type=""Org.OData.Capabilities.V1.ScopeType"">
<PropertyValue Property=""Scope"" String=""scopeName1"" />
<PropertyValue Property=""RestrictedProperties"" String=""p1,p2"" />
</Record>
<Record Type=""Org.OData.Capabilities.V1.ScopeType"">
<PropertyValue Property=""Scope"" String=""scopeName2"" />
<PropertyValue Property=""RestrictedProperties"" String=""p3,p4"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""QueryOptions"">
<Record>
@ -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
{

View file

@ -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(@"
<Annotation Term=""Org.OData.Capabilities.V1.NavigationRestrictions"">
<Record>
<PropertyValue Property=""RestrictedProperties"" >
<Collection>
<Record>
<PropertyValue Property=""NavigationProperty"" NavigationPropertyPath=""{0}"" />
<PropertyValue Property=""ReadRestrictions"" >
<Record>
<PropertyValue Property=""Readable"" Bool=""false"" />
</Record>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>", 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(@"
<Annotation Term=""Org.OData.Capabilities.V1.InsertRestrictions"">
<Annotation Term=""Org.OData.Capabilities.V1.NavigationRestrictions"">
<Record>
<PropertyValue Property=""NonInsertableNavigationProperties"" >
<PropertyValue Property=""RestrictedProperties"" >
<Collection>
<NavigationPropertyPath>{0}</NavigationPropertyPath>
<Record>
<PropertyValue Property=""NavigationProperty"" NavigationPropertyPath=""{0}"" />
<PropertyValue Property=""InsertRestrictions"" >
<Record>
<PropertyValue Property=""Insertable"" Bool=""false"" />
</Record>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
@ -233,11 +288,18 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests
{
// Arrange
string annotation = String.Format(@"
<Annotation Term=""Org.OData.Capabilities.V1.UpdateRestrictions"">
<Annotation Term=""Org.OData.Capabilities.V1.NavigationRestrictions"">
<Record>
<PropertyValue Property=""NonUpdatableNavigationProperties"" >
<PropertyValue Property=""RestrictedProperties"" >
<Collection>
<NavigationPropertyPath>{0}</NavigationPropertyPath>
<Record>
<PropertyValue Property=""NavigationProperty"" NavigationPropertyPath=""{0}"" />
<PropertyValue Property=""UpdateRestrictions"" >
<Record>
<PropertyValue Property=""Updatable"" Bool=""false"" />
</Record>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>

View file

@ -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
}

View file

@ -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
</Collection>
</PropertyValue>
<PropertyValue Property=""MaxLevels"" Int=""42"" />
<PropertyValue Property=""Permission"">
<Record>
<PropertyValue Property=""Scheme"" >
<Record>
<PropertyValue Property=""Authorization"" String=""schemeName"" />
</Record>
</PropertyValue>
</Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record>
<PropertyValue Property=""SchemeName"" String=""schemeName"" />
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""CustomQueryOptions"" >
<Collection>
@ -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);

View file

@ -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);

View file

@ -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
{

View file

@ -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<OperationRestrictionType>();
string qualifiedName = Utils.GetTermQualifiedName<OperationRestrictionsType>();
// 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<OperationRestrictionType>(edmOperation, "NS.MyOperationRestriction");
OperationRestrictionsType operation = model.GetRecord<OperationRestrictionsType>(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);

View file

@ -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 = @"<Annotation Term=""NS.MyTerm"">
<Record>
<PropertyValue Property=""Scheme"">
<Record>
<PropertyValue Property=""Authorization"" String=""scheme name"" />
</Record>
</PropertyValue>
<PropertyValue Property=""SchemeName"" String=""scheme name"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record>
@ -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);

View file

@ -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);

View file

@ -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
</Collection>
</PropertyValue>
<PropertyValue Property=""MaxLevels"" Int=""8"" />
<PropertyValue Property=""Permission"">
<Record Type=""Org.OData.Capabilities.V1.PermissionType"">
<PropertyValue Property=""Scheme"">
<Record Type=""Org.OData.Authorization.V1.SecurityScheme"">
<PropertyValue Property=""Authorization"" String=""authorizationName"" />
<PropertyValue Property=""RequiredScopes"">
<Collection>
<String>RequiredScopes1</String>
<String>RequiredScopes2</String>
</Collection>
</PropertyValue>
</Record>
</PropertyValue>
<PropertyValue Property=""Scopes"">
<Collection>
<Record Type=""Org.OData.Capabilities.V1.ScopeType"">
<PropertyValue Property=""Scope"" String=""scopeName1"" />
<PropertyValue Property=""RestrictedProperties"" String=""p1,p2"" />
</Record>
<Record Type=""Org.OData.Capabilities.V1.ScopeType"">
<PropertyValue Property=""Scope"" String=""scopeName2"" />
<PropertyValue Property=""RestrictedProperties"" String=""p3,p4"" />
</Record>
</Collection>
</PropertyValue>
</Record>
<PropertyValue Property=""Permissions"">
<Collection>
<Record Type=""Org.OData.Capabilities.V1.PermissionType"">
<PropertyValue Property=""SchemeName"" String=""authorizationName"" />
<PropertyValue Property=""Scopes"">
<Collection>
<Record Type=""Org.OData.Capabilities.V1.ScopeType"">
<PropertyValue Property=""Scope"" String=""scopeName1"" />
<PropertyValue Property=""RestrictedProperties"" String=""p1,p2"" />
</Record>
<Record Type=""Org.OData.Capabilities.V1.ScopeType"">
<PropertyValue Property=""Scope"" String=""scopeName2"" />
<PropertyValue Property=""RestrictedProperties"" String=""p3,p4"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
<PropertyValue Property=""QueryOptions"">
<Record>
@ -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);

View file

@ -32,11 +32,11 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.OData.Edm, Version=7.6.0.30605, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.OData.Edm.7.6.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll</HintPath>
<Reference Include="Microsoft.OData.Edm, Version=7.6.1.30918, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.OData.Edm.7.6.1-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll</HintPath>
</Reference>
<Reference Include="Microsoft.OpenApi, Version=1.1.2.0, Culture=neutral, PublicKeyToken=3f5743946376f042, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.OpenApi.1.1.2\lib\net46\Microsoft.OpenApi.dll</HintPath>
<Reference Include="Microsoft.OpenApi, Version=1.1.4.0, Culture=neutral, PublicKeyToken=3f5743946376f042, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.OpenApi.1.1.4\lib\net46\Microsoft.OpenApi.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.OData.Edm" version="7.6.0" targetFramework="net461" />
<package id="Microsoft.OpenApi" version="1.1.2" targetFramework="net461" />
<package id="Microsoft.OData.Edm" version="7.6.1-beta" targetFramework="net461" />
<package id="Microsoft.OpenApi" version="1.1.4" targetFramework="net461" />
</packages>