Skip to content

Commit

Permalink
Merge pull request #1546 from microsoftgraph/dev
Browse files Browse the repository at this point in the history
Merges dev into master
  • Loading branch information
irvinesunday committed May 10, 2023
2 parents 0911a2d + 609ac6b commit 46a228e
Show file tree
Hide file tree
Showing 15 changed files with 114 additions and 49 deletions.
8 changes: 4 additions & 4 deletions CodeSnippetsReflection.OpenAPI.Test/PhpGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public async Task GeneratesTheCorrectFluentApiPathForIndexedCollections()
new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/me/messages/{{message-id}}");
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1TreeNode());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("->me()->messagesById('message-id')", result);
Assert.Contains("->me()->messages()->byMessageId('message-id')", result);
}

[Fact]
Expand All @@ -63,7 +63,7 @@ public async Task GeneratesCorrectLongPaths()
new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/users/{{user-id}}/messages");
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1TreeNode());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("->usersById('user-id')->messages()->get();", result);
Assert.Contains("->users()->byUserId('user-id')->messages()->get();", result);
}

[Fact]
Expand Down Expand Up @@ -120,7 +120,7 @@ public async Task DoesntFailOnTerminalSlash()
var snippetModel = new SnippetModel(requestPayload, ServiceRootBetaUrl, await GetBetaTreeNode());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains(
"$graphServiceClient->me()->messagesById('message-id')->get($requestConfiguration)",
"$graphServiceClient->me()->messages()->byMessageId('message-id')->get($requestConfiguration)",
result);
}

Expand Down Expand Up @@ -184,7 +184,7 @@ public async Task GeneratesDeleteRequest()
new HttpRequestMessage(HttpMethod.Delete, $"{ServiceRootUrl}/me/messages/{{id}}");
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1TreeNode());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("$graphServiceClient->me()->messagesById('message-id')->delete()", result);
Assert.Contains("$graphServiceClient->me()->messages()->byMessageId('message-id')->delete()", result);
}

[Fact]
Expand Down
10 changes: 10 additions & 0 deletions CodeSnippetsReflection.OpenAPI.Test/PowerShellGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ public async Task GeneratesSnippetForRequestWithSelectQueryOption()
Assert.Contains("-Property \"displayName,id\"", result);
}

[Fact]
public async Task GeneratesNoneEncodedSnippetForRequestWithFilterQueryOptionAndEncodedPayloads()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/users?$filter=displayName+eq+'Megan+Bowen'");
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1TreeNode());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("-Filter \"displayName eq 'Megan Bowen'\"", result);
}


[Fact]
public async Task GeneratesSnippetForRequestWithFilterQueryOption()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.21.0" />
<PackageReference Include="Microsoft.OpenApi.Readers" Version="1.6.3" />
<PackageReference Include="Microsoft.OpenApi.Readers" Version="1.6.4" />
<PackageReference Include="System.Text.Json" Version="7.0.2" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ public string GenerateCodeSnippet(SnippetModel snippetModel)
{
var indentManager = new IndentManager();
var codeGraph = new SnippetCodeGraph(snippetModel);
var snippetBuilder = new StringBuilder($"var {ClientVarName} = new {ClientVarType}({HttpCoreVarName});{Environment.NewLine}{Environment.NewLine}");
var snippetBuilder = new StringBuilder($"// Code snippets are only available for the latest version. Current version is 5.x{Environment.NewLine}{Environment.NewLine}" +
$"var {ClientVarName} = new {ClientVarType}({HttpCoreVarName});{Environment.NewLine}{Environment.NewLine}");

WriteRequestPayloadAndVariableName(codeGraph, snippetBuilder, indentManager);
WriteRequestExecutionPath(codeGraph, snippetBuilder, indentManager);
Expand Down Expand Up @@ -108,7 +109,7 @@ private static void WriteRequestQueryParameters(SnippetCodeGraph snippetCodeGrap
{
if (!snippetCodeGraph.HasParameters())
return;

indentManager.Indent();
foreach(var queryParam in snippetCodeGraph.Parameters)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public string GenerateCodeSnippet(SnippetModel snippetModel)
if (snippetModel == null) throw new ArgumentNullException("Argument snippetModel cannot be null");

var codeGraph = new SnippetCodeGraph(snippetModel);
var snippetBuilder = new StringBuilder("//THE GO SDK IS IN PREVIEW. NON-PRODUCTION USE ONLY");
var snippetBuilder = new StringBuilder();
snippetBuilder.AppendLine("");

writeImportStatements(codeGraph, snippetBuilder);
Expand Down
32 changes: 22 additions & 10 deletions CodeSnippetsReflection.OpenAPI/LanguageGenerators/PhpGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using CodeSnippetsReflection.OpenAPI.ModelGraph;
using CodeSnippetsReflection.StringExtensions;
using Microsoft.ApplicationInsights.Metrics.Extensibility;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Services;
Expand Down Expand Up @@ -339,17 +341,27 @@ private static string GetFluentApiPath(IEnumerable<OpenApiUrlTreeNode> nodes)
return $"ById{x.Segment.Replace("{", "('").Replace("}", "')")}";
if (x.Segment.IsFunction())
return x.Segment.Split('.')
.Select(static s => s.ToFirstCharacterUpperCase())
.Aggregate(static (a, b) => $"{a}{b}").ToFirstCharacterLowerCase() + "()";
return x.Segment.ToFirstCharacterLowerCase()+"()";
})
.Aggregate(static (x, y) =>
.Select(static s => s.ToFirstCharacterUpperCase())
.Aggregate(static (a, b) => $"{a}{b}").ToFirstCharacterLowerCase() + "()";
return x.Segment.ToFirstCharacterLowerCase() + "()";
}).Aggregate(new List<String>(), (current, next) =>
{
var dot = y.StartsWith("ById") ? string.Empty : "->";
return $"{x.Trim('$')}{dot}{y.Trim('$')}";
}).Replace("()ById(", "ById(")
.Replace("()()->", "()->");

if (next.StartsWith("ById"))
{
var prev = current.Last();
var inBrackets = next[4..];
if (prev.EndsWith("s()"))
{
prev = prev[..^3];
}
next = $"by{prev.ToFirstCharacterUpperCase()}Id{inBrackets}";
}
current.Add(next);
return current;
}).Aggregate(static (x, y) => $"{x.Trim('$')}->{y.Trim('$')}")
.Replace("()()->", "()->");

return result.EndsWith("()()") ? result[..^2] : result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class PowerShellGenerator : ILanguageGenerator<SnippetModel, OpenApiUrlTr
LazyThreadSafetyMode.PublicationOnly
);
private static readonly Regex meSegmentRegex = new("^/me($|(?=/))", RegexOptions.Compiled, TimeSpan.FromSeconds(5));
private static readonly Regex encodedQueryParamsPayLoad = new(@"\w*\+", RegexOptions.Compiled, TimeSpan.FromSeconds(5));
public string GenerateCodeSnippet(SnippetModel snippetModel)
{
var indentManager = new IndentManager();
Expand Down Expand Up @@ -94,7 +95,7 @@ private static string GetCommandParameters(SnippetModel snippetModel, string pay

var queryParamsPayload = GetRequestQueryParameters(snippetModel);
if (!string.IsNullOrEmpty(queryParamsPayload))
payloadSB.Append($" {queryParamsPayload}");
payloadSB.Append($" {ReturnCleanParamsPayload(queryParamsPayload)}");

var parameterList = GetActionParametersList(payloadVarName);
if (!string.IsNullOrEmpty(parameterList))
Expand All @@ -105,6 +106,12 @@ private static string GetCommandParameters(SnippetModel snippetModel, string pay
payloadSB.Append(requestHeadersPayload);
return payloadSB.ToString();
}
public static string ReturnCleanParamsPayload(string queryParamsPayload)
{
if(encodedQueryParamsPayLoad.IsMatch(queryParamsPayload))
return queryParamsPayload.Replace("+", " ");
return queryParamsPayload;
}

private static (string, string) SubstituteMeSegment(bool isMeSegment, string path)
{
Expand Down
10 changes: 8 additions & 2 deletions GraphWebApi/Common/RequestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,14 @@ internal static string GetPreferredLocaleLanguage(HttpRequest request)
.OrderByDescending(s => s.Quality.GetValueOrDefault(1));

localeLanguage = languages.FirstOrDefault()?.ToString();
var localeSegments = localeLanguage.Split("-");
localeLanguage = $"{localeSegments[0]}-{localeSegments[1].ToUpper(CultureInfo.InvariantCulture)}";
if (localeLanguage != null)
{
var localeSegments = localeLanguage.Split("-");
if (localeSegments.Length >= 2)
{
localeLanguage = $"{localeSegments[0]}-{localeSegments[1].ToUpper(CultureInfo.InvariantCulture)}";
}
}
}

return localeLanguage;
Expand Down
2 changes: 1 addition & 1 deletion GraphWebApi/GraphWebApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.21.0" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.21.0" />
<PackageReference Include="Microsoft.ApplicationInsights.PerfCounterCollector" Version="2.21.0" />
<PackageReference Include="Microsoft.ApplicationInsights.SnapshotCollector" Version="1.4.3" />
<PackageReference Include="Microsoft.ApplicationInsights.SnapshotCollector" Version="1.4.4" />
<PackageReference Include="Microsoft.ApplicationInsights.Web" Version="2.21.0" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.9" />
<PackageReference Include="Microsoft.AspNetCore.ApplicationInsights.HostingStartup" Version="2.2.0" />
Expand Down
4 changes: 2 additions & 2 deletions OpenAPIService.Test/OpenAPIService.Test.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
Expand Down Expand Up @@ -27,7 +27,7 @@
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Microsoft.OpenApi" Version="1.6.3" />
<PackageReference Include="Microsoft.OpenApi" Version="1.6.4" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
Expand Down
8 changes: 4 additions & 4 deletions OpenAPIService/OpenAPIService.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
Expand All @@ -10,9 +10,9 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
<PackageReference Include="Microsoft.OData.Edm" Version="7.15.0" />
<PackageReference Include="Microsoft.OpenApi" Version="1.6.3" />
<PackageReference Include="Microsoft.OpenApi.OData" Version="1.3.0" />
<PackageReference Include="Microsoft.OpenApi.Readers" Version="1.6.3" />
<PackageReference Include="Microsoft.OpenApi" Version="1.6.4" />
<PackageReference Include="Microsoft.OpenApi.OData" Version="1.4.0" />
<PackageReference Include="Microsoft.OpenApi.Readers" Version="1.6.4" />
</ItemGroup>

<ItemGroup>
Expand Down
16 changes: 11 additions & 5 deletions OpenAPIService/PowershellFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ public PowershellFormatter(bool singularizeOperationIds)
_singularizeOperationIds = singularizeOperationIds;
}

static PowershellFormatter()
{
Vocabularies.Default.AddSingular("(drive)s$", "$1"); // drives does not properly singularize to drive.
Vocabularies.Default.AddSingular("(data)$", "$1"); // exclude the following from singularization.
Vocabularies.Default.AddSingular("(delta)$", "$1");
Vocabularies.Default.AddSingular("(quota)$", "$1");
Vocabularies.Default.AddSingular("(statistics)$", "$1");
}

/// <summary>
/// Accesses the individual OpenAPI operations for a particular OpenApiPathItem.
/// </summary>
Expand Down Expand Up @@ -229,11 +238,6 @@ private static string SingularizeAndDeduplicateOperationId(string operationId)
if (string.IsNullOrEmpty(operationId))
return operationId;

// drives does not properly singularize to drive.
Vocabularies.Default.AddSingular("(drive)s$", "$1");
// exclude the following from singularization.
Vocabularies.Default.AddSingular("(data)$", "$1");

var segments = operationId.Split('.').ToList();
var segmentsCount = segments.Count;
var lastSegmentIndex = segmentsCount - 1;
Expand All @@ -247,8 +251,10 @@ private static string SingularizeAndDeduplicateOperationId(string operationId)
// The last segment is ignored as a rule.
if ((x > 0 && x < lastSegmentIndex) && singularizedSegments.Last().Equals(segment, StringComparison.OrdinalIgnoreCase))
continue;

singularizedSegments.Add(segment);
}

return string.Join(".", singularizedSegments);
}
}
Expand Down
6 changes: 3 additions & 3 deletions PermissionsService.Test/PermissionsStoreShould.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ public async Task GetLeastPrivilegePermissionScopesGivenAnExistingRequestUrl()
}

[Theory]
[InlineData(ScopeType.DelegatedWork, 292)]
[InlineData(ScopeType.DelegatedPersonal, 38)]
[InlineData(ScopeType.DelegatedWork, 311)]
[InlineData(ScopeType.DelegatedPersonal, 113)]
[InlineData(ScopeType.Application, 279)]
public async Task GetAllPermissionScopesGivenNoRequestUrlFilteredByScopeType(ScopeType scopeType, int expectedCount)
{
Expand All @@ -188,7 +188,7 @@ public async Task GetAllPermissionScopesGivenNoRequestUrl()

// Assert
Assert.NotEmpty(result.Results);
Assert.Equal(609, result.Results.Count);
Assert.Equal(625, result.Results.Count);
}

[Fact]
Expand Down
47 changes: 35 additions & 12 deletions PermissionsService/Services/PermissionsStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -321,9 +321,11 @@ private async Task<string> FetchHttpSourceDocument(string sourceUri)
var scopes = new List<ScopeInformation>();
var errors = new List<PermissionError>();

bool getAllScopes = false;
if (requests == null || !requests.Any())
{
// Get all scopes if no request URLs are provided
getAllScopes = true;
var allScopes = await GetAllScopesAsync(scopeType);
scopes.AddRange(allScopes);
}
Expand Down Expand Up @@ -380,7 +382,9 @@ private async Task<string> FetchHttpSourceDocument(string sourceUri)
// Get consent display name and description
var scopesInfo = GetAdditionalScopesInformation(
scopesInformationDictionary,
scopes.DistinctBy(static x => $"{x.ScopeName}{x.ScopeType}", StringComparer.OrdinalIgnoreCase).ToList());
scopes.DistinctBy(static x => $"{x.ScopeName}{x.ScopeType}", StringComparer.OrdinalIgnoreCase).ToList(),
scopeType,
getAllScopes);

// exclude hidden permissions unless stated otherwise
scopesInfo = scopesInfo.Where(x => includeHidden || !x.IsHidden).ToList();
Expand Down Expand Up @@ -509,7 +513,7 @@ private static string CleanRequestUrl(string requestUrl)
/// <returns>A list of <see cref="ScopeInformation"/>.</returns>
/// <exception cref="ArgumentNullException"></exception>
private List<ScopeInformation> GetAdditionalScopesInformation(IDictionary<string, IDictionary<string, ScopeInformation>> scopesInformationDictionary,
List<ScopeInformation> scopes)
List<ScopeInformation> scopes, ScopeType? scopeType = null, bool getAllPermissions = false)
{
if (scopesInformationDictionary is null)
{
Expand All @@ -521,17 +525,12 @@ private static string CleanRequestUrl(string requestUrl)
throw new ArgumentNullException(nameof(scopes));
}

var schemeKeys = permissionDescriptionGroups.Values.Distinct().ToList();
schemeKeys.ForEach(key =>
var descriptionGroups = permissionDescriptionGroups.Values.Distinct().Except(scopesInformationDictionary.Keys);
foreach (var group in descriptionGroups)
{
if (scopesInformationDictionary[key].Values.Any())
{
var errMsg = $"{nameof(scopesInformationDictionary)}:[{key}] has no values.";
_telemetryClient?.TrackTrace(errMsg,
SeverityLevel.Error,
_permissionsTraceProperties);
}
});
var errMsg = $"{nameof(scopesInformationDictionary)} does not contain a dictionary for {group} scopes.";
_telemetryClient?.TrackTrace(errMsg, SeverityLevel.Error, _permissionsTraceProperties);
}

var scopesInfo = scopes.Select(scope =>
{
Expand All @@ -551,6 +550,30 @@ private static string CleanRequestUrl(string requestUrl)
}
return scope;
}).ToList();

if (getAllPermissions)
{
foreach (var key in permissionDescriptionGroups.Keys)
{
if (scopeType != null && key != scopeType)
continue;

scopesInfo.AddRange(
scopesInformationDictionary[permissionDescriptionGroups[key]].Values
.Where(info => !scopesInfo.Exists(x => x.ScopeName.Equals(info.ScopeName, StringComparison.OrdinalIgnoreCase)))
.Select(scope =>
{
return new ScopeInformation()
{
ScopeName = scope.ScopeName,
DisplayName = scope.DisplayName,
IsAdmin = scope.IsAdmin,
Description = scope.Description,
ScopeType = key
};
}));
}
}
return scopesInfo;
}

Expand Down
2 changes: 1 addition & 1 deletion apidoctor

0 comments on commit 46a228e

Please sign in to comment.