Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ private void RetrieveMediaEntityStreamPaths(IEdmEntityType entityType, ODataPath
Debug.Assert(currentPath != null);

bool createValuePath = true;
foreach (IEdmStructuralProperty sp in entityType.DeclaredStructuralProperties())
foreach (IEdmStructuralProperty sp in entityType.StructuralProperties())
{
if (sp.Type.AsPrimitive().IsStream())
{
Expand All @@ -228,7 +228,7 @@ private void RetrieveMediaEntityStreamPaths(IEdmEntityType entityType, ODataPath
currentPath.Pop();
}

if (sp.Name.Equals("content", System.StringComparison.OrdinalIgnoreCase))
if (sp.Name.Equals("content", StringComparison.OrdinalIgnoreCase))
{
createValuePath = false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,9 @@ internal class MediaEntityGetOperationHandler : MediaEntityOperationalHandler
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
if (IsNavigationPropertyPath)
{
operation.Summary = $"Get media content for the navigation property {NavigationProperty.Name} from {NavigationSource.Name}";
}
else
{
IEdmEntityType entityType = EntitySet.EntityType();
operation.Summary = $"Get media content for {entityType.Name} from {EntitySet.Name}";
}
operation.Summary = IsNavigationPropertyPath
? $"Get media content for the navigation property {NavigationProperty.Name} from {NavigationSource.Name}"
: $"Get media content for {NavigationSourceSegment.EntityType.Name} from {NavigationSourceSegment.Identifier}";

// Description
IEdmVocabularyAnnotatable annotatableElement = GetAnnotatableElement();
Expand Down Expand Up @@ -73,9 +67,8 @@ protected override void SetResponses(OpenApiOperation operation)
/// <inheritdoc/>
protected override void SetSecurity(OpenApiOperation operation)
{
ReadRestrictionsType read = EntitySet != null
? Context.Model.GetRecord<ReadRestrictionsType>(EntitySet, CapabilitiesConstants.ReadRestrictions)
: Context.Model.GetRecord<ReadRestrictionsType>(Singleton, CapabilitiesConstants.ReadRestrictions);
IEdmVocabularyAnnotatable annotatableNavigationSource = (IEdmVocabularyAnnotatable)NavigationSourceSegment.NavigationSource;
ReadRestrictionsType read = Context.Model.GetRecord<ReadRestrictionsType>(annotatableNavigationSource, CapabilitiesConstants.ReadRestrictions);
if (read == null)
{
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,9 @@ namespace Microsoft.OpenApi.OData.Operation
internal abstract class MediaEntityOperationalHandler : NavigationPropertyOperationHandler
{
/// <summary>
/// Gets/sets the <see cref="IEdmEntitySet"/>.
/// Gets/Sets the NavigationSource segment
/// </summary>
protected IEdmEntitySet EntitySet { get; private set; }

/// <summary>
/// Gets the <see cref="IEdmSingleton"/>.
/// </summary>
protected IEdmSingleton Singleton { get; private set; }
protected ODataNavigationSourceSegment NavigationSourceSegment { get; private set; }

/// <summary>
/// Gets/Sets flag indicating whether path is navigation property path
Expand All @@ -39,13 +34,7 @@ internal abstract class MediaEntityOperationalHandler : NavigationPropertyOperat
protected override void Initialize(ODataContext context, ODataPath path)
{
// The first segment will either be an EntitySet navigation source or a Singleton navigation source
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
EntitySet = navigationSourceSegment.NavigationSource as IEdmEntitySet;

if (EntitySet == null)
{
Singleton = navigationSourceSegment.NavigationSource as IEdmSingleton;
}
NavigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;

// Check whether path is a navigation property path
IsNavigationPropertyPath = Path.Segments.Contains(
Expand All @@ -67,9 +56,9 @@ protected override void SetTags(OpenApiOperation operation)
}
else
{
string tagIdentifier = EntitySet.Name + "." + EntitySet.EntityType().Name;
string tagIdentifier = NavigationSourceSegment.Identifier + "." + NavigationSourceSegment.EntityType.Name;

OpenApiTag tag = new OpenApiTag
OpenApiTag tag = new()
{
Name = tagIdentifier
};
Expand Down Expand Up @@ -102,7 +91,7 @@ protected string GetOperationId(string prefix, string identifier)

IList<string> items = new List<string>
{
EntitySet?.Name ?? Singleton.Name
NavigationSourceSegment.Identifier
};

ODataSegment lastSegment = Path.Segments.Last(c => c is ODataStreamContentSegment || c is ODataStreamPropertySegment);
Expand All @@ -112,7 +101,7 @@ protected string GetOperationId(string prefix, string identifier)
{
if (!IsNavigationPropertyPath)
{
string typeName = EntitySet?.EntityType().Name ?? Singleton.EntityType().Name;
string typeName = NavigationSourceSegment.EntityType.Name;
items.Add(typeName);
items.Add(prefix + Utils.UpperFirstChar(identifier));
}
Expand Down Expand Up @@ -185,7 +174,7 @@ protected IDictionary<string, OpenApiMediaType> GetContentDescription()
/// <returns>The annotable element.</returns>
protected IEdmVocabularyAnnotatable GetAnnotatableElement()
{
IEdmEntityType entityType = EntitySet != null ? EntitySet.EntityType() : Singleton.EntityType();
IEdmEntityType entityType = NavigationSourceSegment.EntityType;
ODataSegment lastSegmentProp = Path.Segments.LastOrDefault(c => c is ODataStreamPropertySegment);

if (lastSegmentProp == null)
Expand Down Expand Up @@ -214,7 +203,7 @@ protected IEdmVocabularyAnnotatable GetAnnotatableElement()

private IEdmStructuralProperty GetStructuralProperty(IEdmEntityType entityType, string identifier)
{
return entityType.DeclaredStructuralProperties().FirstOrDefault(x => x.Name.Equals(identifier));
return entityType.StructuralProperties().FirstOrDefault(x => x.Name.Equals(identifier));
}

private IEdmNavigationProperty GetNavigationProperty(IEdmEntityType entityType, string identifier)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,9 @@ internal class MediaEntityPutOperationHandler : MediaEntityOperationalHandler
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
if (IsNavigationPropertyPath)
{
operation.Summary = $"Update media content for the navigation property {NavigationProperty.Name} in {NavigationSource.Name}";
}
else
{
string typeName = EntitySet.EntityType().Name;
operation.Summary = $"Update media content for {typeName} in {EntitySet.Name}";
}
operation.Summary = IsNavigationPropertyPath
? $"Update media content for the navigation property {NavigationProperty.Name} in {NavigationSource.Name}"
: $"Update media content for {NavigationSourceSegment.EntityType.Name} in {NavigationSourceSegment.Identifier}";

// Description
IEdmVocabularyAnnotatable annotatableElement = GetAnnotatableElement();
Expand Down Expand Up @@ -79,9 +73,8 @@ protected override void SetResponses(OpenApiOperation operation)
/// <inheritdoc/>
protected override void SetSecurity(OpenApiOperation operation)
{
UpdateRestrictionsType update = EntitySet != null
? Context.Model.GetRecord<UpdateRestrictionsType>(EntitySet, CapabilitiesConstants.UpdateRestrictions)
: Context.Model.GetRecord<UpdateRestrictionsType>(Singleton, CapabilitiesConstants.UpdateRestrictions);
IEdmVocabularyAnnotatable annotatableNavigationSource = (IEdmVocabularyAnnotatable)NavigationSourceSegment.NavigationSource;
UpdateRestrictionsType update = Context.Model.GetRecord<UpdateRestrictionsType>(annotatableNavigationSource, CapabilitiesConstants.UpdateRestrictions);
if (update == null || update.Permissions == null)
{
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -450,41 +450,52 @@ public void GetPathsWithContainedNavigationPropertyWorks()
}

[Theory]
[InlineData(true, "Logo")]
[InlineData(false, "Logo")]
[InlineData(true, "Content")]
[InlineData(false, "Content")]
[InlineData(true, "logo")]
[InlineData(false, "logo")]
[InlineData(true, "content")]
[InlineData(false, "content")]
public void GetPathsWithStreamPropertyAndWithEntityHasStreamWorks(bool hasStream, string streamPropName)
{
// Arrange
IEdmModel model = GetEdmModel(hasStream, streamPropName);
ODataPathProvider provider = new ODataPathProvider();
var settings = new OpenApiConvertSettings();
const string TodosContentPath = "/todos({id})/content";
const string TodosValuePath = "/todos({id})/$value";
const string TodosLogoPath = "/todos({id})/logo";

// Act
var paths = provider.GetPaths(model,settings);
var paths = provider.GetPaths(model, settings);

// Assert
Assert.NotNull(paths);
Assert.Contains("/catalog/content", paths.Select(p => p.GetPathItemName()));
Assert.Contains("/catalog/thumbnailPhoto", paths.Select(p => p.GetPathItemName()));
Assert.Contains("/me/photo/$value", paths.Select(p => p.GetPathItemName()));

if (hasStream && !streamPropName.Equals("Content", StringComparison.OrdinalIgnoreCase))
{
Assert.Equal(7, paths.Count());
Assert.Equal(new[] { "/me", "/me/photo", "/me/photo/$value", "/Todos", "/Todos({Id})", "/Todos({Id})/$value", "/Todos({Id})/Logo" },
paths.Select(p => p.GetPathItemName()));
}
else if ((hasStream && streamPropName.Equals("Content", StringComparison.OrdinalIgnoreCase)) ||
(!hasStream && streamPropName.Equals("Content", StringComparison.OrdinalIgnoreCase)))
if (streamPropName.Equals("logo"))
{
Assert.Equal(6, paths.Count());
Assert.Equal(new[] { "/me", "/me/photo", "/me/photo/$value", "/Todos", "/Todos({Id})", "/Todos({Id})/Content" },
paths.Select(p => p.GetPathItemName()));
if (hasStream)
{
Assert.Equal(12, paths.Count());
Assert.Contains(TodosValuePath, paths.Select(p => p.GetPathItemName()));
Assert.Contains(TodosLogoPath, paths.Select(p => p.GetPathItemName()));
Assert.DoesNotContain(TodosContentPath, paths.Select(p => p.GetPathItemName()));
}
else
{
Assert.Equal(11, paths.Count());
Assert.Contains(TodosLogoPath, paths.Select(p => p.GetPathItemName()));
Assert.DoesNotContain(TodosContentPath, paths.Select(p => p.GetPathItemName()));
Assert.DoesNotContain(TodosValuePath, paths.Select(p => p.GetPathItemName()));
}
}
else // !hasStream && !streamPropName.Equals("Content")
else if (streamPropName.Equals("content"))
{
Assert.Equal(6, paths.Count());
Assert.Equal(new[] { "/me", "/me/photo", "/me/photo/$value", "/Todos", "/Todos({Id})", "/Todos({Id})/Logo"},
paths.Select(p => p.GetPathItemName()));
Assert.Equal(11, paths.Count());
Assert.Contains(TodosContentPath, paths.Select(p => p.GetPathItemName()));
Assert.DoesNotContain(TodosLogoPath, paths.Select(p => p.GetPathItemName()));
Assert.DoesNotContain(TodosValuePath, paths.Select(p => p.GetPathItemName()));
}
}

Expand Down Expand Up @@ -576,13 +587,13 @@ private static IEdmModel GetEdmModel(bool hasStream, string streamPropName)
string template = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""microsoft.graph"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityType Name=""Todo"" HasStream=""{0}"">
<EntityType Name=""todo"" HasStream=""{0}"">
<Key>
<PropertyRef Name=""Id"" />
<PropertyRef Name=""id"" />
</Key>
<Property Name=""Id"" Type=""Edm.Int32"" Nullable=""false"" />
<Property Name=""id"" Type=""Edm.Int32"" Nullable=""false"" />
<Property Name=""{1}"" Type=""Edm.Stream""/>
<Property Name = ""Description"" Type = ""Edm.String"" />
<Property Name = ""description"" Type = ""Edm.String"" />
</EntityType>
<EntityType Name=""user"" OpenType=""true"">
<NavigationProperty Name = ""photo"" Type = ""microsoft.graph.profilePhoto"" ContainsTarget = ""true"" />
Expand All @@ -591,9 +602,17 @@ private static IEdmModel GetEdmModel(bool hasStream, string streamPropName)
<Property Name = ""height"" Type = ""Edm.Int32"" />
<Property Name = ""width"" Type = ""Edm.Int32"" />
</EntityType >
<EntityType Name=""document"">
<Property Name=""content"" Type=""Edm.Stream""/>
<Property Name=""thumbnailPhoto"" Type=""Edm.Stream""/>
</EntityType>
<EntityType Name=""catalog"" BaseType=""microsoft.graph.document"">
<NavigationProperty Name=""reports"" Type = ""Collection(microsoft.graph.report)"" />
</EntityType>
<EntityContainer Name =""GraphService"">
<EntitySet Name=""Todos"" EntityType=""microsoft.graph.Todo"" />
<EntitySet Name=""todos"" EntityType=""microsoft.graph.todo"" />
<Singleton Name=""me"" Type=""microsoft.graph.user"" />
<Singleton Name=""catalog"" Type=""microsoft.graph.catalog"" />
</EntityContainer>
</Schema>
</edmx:DataServices>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ private void VerifyMediaEntityGetOperation(string annotation, bool enableOperati
Assert.NotNull(me);

IEdmEntityType todo = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Todo");
IEdmStructuralProperty sp = todo.DeclaredStructuralProperties().First(c => c.Name == "Logo");
IEdmStructuralProperty sp = todo.StructuralProperties().First(c => c.Name == "Logo");
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(todos),
new ODataKeySegment(todos.EntityType()),
new ODataStreamPropertySegment(sp.Name));

IEdmEntityType user = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "user");
IEdmNavigationProperty navProperty = user.DeclaredNavigationProperties().First(c => c.Name == "photo");
IEdmNavigationProperty navProperty = user.NavigationProperties().First(c => c.Name == "photo");
ODataPath path2 = new ODataPath(new ODataNavigationSourceSegment(me),
new ODataNavigationPropertySegment(navProperty),
new ODataStreamContentSegment());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ private void VerifyMediaEntityPutOperation(string annotation, bool enableOperati
Assert.NotNull(todos);

IEdmEntityType todo = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Todo");
IEdmStructuralProperty sp = todo.DeclaredStructuralProperties().First(c => c.Name == "Logo");
IEdmStructuralProperty sp = todo.StructuralProperties().First(c => c.Name == "Logo");
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(todos),
new ODataKeySegment(todos.EntityType()),
new ODataStreamPropertySegment(sp.Name));

IEdmEntityType user = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "user");
IEdmNavigationProperty navProperty = user.DeclaredNavigationProperties().First(c => c.Name == "photo");
IEdmNavigationProperty navProperty = user.NavigationProperties().First(c => c.Name == "photo");
ODataPath path2 = new ODataPath(new ODataNavigationSourceSegment(me),
new ODataNavigationPropertySegment(navProperty),
new ODataStreamContentSegment());
Expand Down