diff --git a/CommunityToolkit.Net.Graph/CommunityToolkit.Net.Graph.csproj b/CommunityToolkit.Net.Graph/CommunityToolkit.Net.Graph.csproj index 98339a9..3a60504 100644 --- a/CommunityToolkit.Net.Graph/CommunityToolkit.Net.Graph.csproj +++ b/CommunityToolkit.Net.Graph/CommunityToolkit.Net.Graph.csproj @@ -18,7 +18,7 @@ - + diff --git a/CommunityToolkit.Net.Graph/Extensions/GraphExtensions.People.cs b/CommunityToolkit.Net.Graph/Extensions/GraphExtensions.People.cs new file mode 100644 index 0000000..ccc990d --- /dev/null +++ b/CommunityToolkit.Net.Graph/Extensions/GraphExtensions.People.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.Graph; + +namespace CommunityToolkit.Net.Graph.Extensions +{ + /// + /// People focused extension methods to the Graph SDK used by the controls and helpers. + /// + public static partial class GraphExtensions + { + /// + /// Shortcut to perform a person query. + /// + /// Instance of the . + /// User to search for. + /// collection of . + public static async Task FindPersonAsync(this GraphServiceClient graph, string query) + { + try + { + return await graph + .Me + .People + .Request() + .Search(query) + .WithScopes(new string[] { "people.read" }) + .GetAsync(); + } + catch + { + } + + return new UserPeopleCollectionPage(); + } + } +} diff --git a/CommunityToolkit.Net.Graph/Extensions/GraphExtensions.Users.cs b/CommunityToolkit.Net.Graph/Extensions/GraphExtensions.Users.cs new file mode 100644 index 0000000..ddee7f5 --- /dev/null +++ b/CommunityToolkit.Net.Graph/Extensions/GraphExtensions.Users.cs @@ -0,0 +1,126 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Threading.Tasks; +using Microsoft.Graph; + +namespace CommunityToolkit.Net.Graph.Extensions +{ + /// + /// User focused extension methods to the Graph SDK used by the controls and helpers. + /// + public static partial class GraphExtensions + { + /// + /// Retrieve the curernt user. + /// + /// Instance of the . + /// A representing the asynchronous operation. + public static async Task GetMeAsync(this GraphServiceClient graph) + { + try + { + return await graph.Me.Request().GetAsync(); + } + catch + { + } + + return null; + } + + /// + /// Retrieve a user by id. + /// + /// Instance of the . + /// The is of the user to retrieve. + /// A representing the asynchronous operation. + public static async Task GetUserAsync(this GraphServiceClient graph, string userId) + { + try + { + return await graph.Users[userId].Request().GetAsync(); + } + catch + { + } + + return null; + } + + /// + /// Shortcut to perform a user query. + /// + /// Instance of the . + /// User to search for. + /// collection of . + public static async Task FindUserAsync(this GraphServiceClient graph, string query) + { + try + { + return await graph + .Users + .Request() + .Filter($"startswith(displayName, '{query}') or startswith(givenName, '{query}') or startswith(surname, '{query}') or startswith(mail, '{query}') or startswith(userPrincipalName, '{query}')") + .WithScopes(new string[] { "user.readbasic.all" }) + .GetAsync(); + } + catch + { + } + + return new GraphServiceUsersCollectionPage(); + } + + /// + /// Helper to get the photo of a particular user. + /// + /// Instance of the . + /// UserID. + /// Stream with user photo or null. + public static async Task GetUserPhoto(this GraphServiceClient graph, string userId) + { + try + { + return await graph + .Users[userId] + .Photo + .Content + .Request() + .WithScopes(new string[] { "user.readbasic.all" }) + .GetAsync(); + } + catch + { + } + + return null; + } + + /// + /// Get the photo of the current user. + /// + /// Instance of the . + /// Stream with user photo or null. + public static async Task GetMyPhotoAsync(this GraphServiceClient graph) + { + try + { + return await graph + .Me + .Photo + .Content + .Request() + .WithScopes(new string[] { "user.read" }) + .GetAsync(); + } + catch + { + } + + return null; + } + } +} diff --git a/CommunityToolkit.Net.Graph/Extensions/GraphExtensions.cs b/CommunityToolkit.Net.Graph/Extensions/GraphExtensions.cs index 77d8637..c14d22d 100644 --- a/CommunityToolkit.Net.Graph/Extensions/GraphExtensions.cs +++ b/CommunityToolkit.Net.Graph/Extensions/GraphExtensions.cs @@ -2,16 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.IO; -using System.Threading.Tasks; using Microsoft.Graph; namespace CommunityToolkit.Net.Graph.Extensions { /// - /// Extension methods to the Graph SDK used by the Microsoft.Toolkit.Graph.Controls. + /// Extension methods to the Graph SDK used by the controls and helpers. /// - public static class GraphExtensions + public static partial class GraphExtensions { /// /// Simple method to convert a to a with basic common properties like , , , , and intact. @@ -28,9 +26,9 @@ public static Person ToPerson(this User user) // Standard User Info DisplayName = user.DisplayName, - EmailAddresses = new RankedEmailAddress[] + ScoredEmailAddresses = new ScoredEmailAddress[] { - new RankedEmailAddress() + new ScoredEmailAddress() { Address = user.Mail ?? user.UserPrincipalName, }, @@ -41,85 +39,11 @@ public static Person ToPerson(this User user) // Company Information CompanyName = user.CompanyName, Department = user.Department, - Title = user.JobTitle, + JobTitle = user.JobTitle, OfficeLocation = user.OfficeLocation, }; } - /// - /// Shortcut to perform a person query. - /// - /// Instance of the . - /// User to search for. - /// collection of . - public static async Task FindPersonAsync(this GraphServiceClient graph, string query) - { - try - { - return await graph - .Me - .People - .Request() - .Search(query) - .WithScopes(new string[] { "people.read" }) - .GetAsync(); - } - catch - { - } - - return new UserPeopleCollectionPage(); - } - - /// - /// Shortcut to perform a user query. - /// - /// Instance of the . - /// User to search for. - /// collection of . - public static async Task FindUserAsync(this GraphServiceClient graph, string query) - { - try - { - return await graph - .Users - .Request() - .Filter($"startswith(displayName, '{query}') or startswith(givenName, '{query}') or startswith(surname, '{query}') or startswith(mail, '{query}') or startswith(userPrincipalName, '{query}')") - .WithScopes(new string[] { "user.readbasic.all" }) - .GetAsync(); - } - catch - { - } - - return new GraphServiceUsersCollectionPage(); - } - - /// - /// Helper to get the photo of a particular user. - /// - /// Instance of the . - /// UserID. - /// Stream with user photo or null. - public static async Task GetUserPhoto(this GraphServiceClient graph, string userid) - { - try - { - return await graph - .Users[userid] - .Photo - .Content - .Request() - .WithScopes(new string[] { "user.readbasic.all" }) - .GetAsync(); - } - catch - { - } - - return null; - } - /// /// Extension to provider Searching on OData Requests. /// diff --git a/CommunityToolkit.Net.Graph/Extensions/ProviderExtensions.cs b/CommunityToolkit.Net.Graph/Extensions/ProviderExtensions.cs index 5af1a2b..2826a81 100644 --- a/CommunityToolkit.Net.Graph/Extensions/ProviderExtensions.cs +++ b/CommunityToolkit.Net.Graph/Extensions/ProviderExtensions.cs @@ -13,6 +13,7 @@ namespace CommunityToolkit.Net.Graph.Extensions public static class ProviderExtensions { private static GraphServiceClient _client; + private static GraphServiceClient _betaClient; static ProviderExtensions() { @@ -46,5 +47,24 @@ public static GraphServiceClient Graph(this IProvider provider) return _client; } + + /// + /// Lazily gets a GraphServiceClient instance based on the current GlobalProvider, but configured for the beta endpoint. + /// The beta client instance is cleared whenever the GlobalProvider changes. + /// + /// The provider for authenticating Graph calls. + /// A GraphServiceClient instance configured for the beta endpoint. + public static GraphServiceClient BetaGraph(this IProvider provider) + { + if (_betaClient == null && provider?.State == ProviderState.SignedIn) + { + _betaClient = new GraphServiceClient("https://graph.microsoft.com/beta", new DelegateAuthenticationProvider(async (requestMessage) => + { + await provider.AuthenticateRequestAsync(requestMessage); + })); + } + + return _betaClient; + } } } diff --git a/CommunityToolkit.Uwp.Graph.Controls/CommunityToolkit.Uwp.Graph.Controls.csproj b/CommunityToolkit.Uwp.Graph.Controls/CommunityToolkit.Uwp.Graph.Controls.csproj index 4c79a34..ecff297 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/CommunityToolkit.Uwp.Graph.Controls.csproj +++ b/CommunityToolkit.Uwp.Graph.Controls/CommunityToolkit.Uwp.Graph.Controls.csproj @@ -26,6 +26,7 @@ + @@ -35,7 +36,6 @@ - diff --git a/CommunityToolkit.Uwp.Graph.Controls/Controls/GraphPresenter/GraphPresenter.cs b/CommunityToolkit.Uwp.Graph.Controls/Controls/GraphPresenter/GraphPresenter.cs index be65053..2f0d08d 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Controls/GraphPresenter/GraphPresenter.cs +++ b/CommunityToolkit.Uwp.Graph.Controls/Controls/GraphPresenter/GraphPresenter.cs @@ -113,4 +113,4 @@ private async void GraphPresenter_Loaded(object sender, RoutedEventArgs e) } } } -} +} \ No newline at end of file diff --git a/CommunityToolkit.Uwp.Graph.Controls/Controls/LoginButton/LoginButton.cs b/CommunityToolkit.Uwp.Graph.Controls/Controls/LoginButton/LoginButton.cs index ebe5f79..5b220e3 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Controls/LoginButton/LoginButton.cs +++ b/CommunityToolkit.Uwp.Graph.Controls/Controls/LoginButton/LoginButton.cs @@ -115,7 +115,7 @@ private async void LoadData() { // https://github.com/microsoftgraph/microsoft-graph-toolkit/blob/master/src/components/mgt-login/mgt-login.ts#L139 // TODO: Batch with photo request later? https://github.com/microsoftgraph/msgraph-sdk-dotnet-core/issues/29 - UserDetails = await provider.Graph().Me.Request().GetAsync(); + UserDetails = await provider.Graph().GetMeAsync(); } catch (Exception e) { diff --git a/CommunityToolkit.Uwp.Graph.Controls/Controls/PersonView/PersonView.cs b/CommunityToolkit.Uwp.Graph.Controls/Controls/PersonView/PersonView.cs index 4e1199e..f4f387b 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Controls/PersonView/PersonView.cs +++ b/CommunityToolkit.Uwp.Graph.Controls/Controls/PersonView/PersonView.cs @@ -27,8 +27,6 @@ public partial class PersonView : Control /// public const string PersonQueryMe = "me"; - private static readonly string[] RequiredScopes = new string[] { "user.readbasic.all" }; - private string _photoId = null; private string _defaultImageSource = "ms-appx:///Microsoft.Toolkit.Graph.Controls/Assets/person.png"; @@ -138,7 +136,7 @@ private async void LoadData() // TODO: Batch when API easier https://github.com/microsoftgraph/msgraph-sdk-dotnet-core/issues/29 try { - user = await provider.Graph().Users[UserId].Request().GetAsync(); + user = await provider.Graph().GetUserAsync(UserId); } catch { @@ -147,7 +145,7 @@ private async void LoadData() try { // TODO: Move to LoadImage based on previous call? - await DecodeStreamAsync(await provider.Graph().Users[UserId].Photo.Content.Request().GetAsync()); + await DecodeStreamAsync(await provider.BetaGraph().GetUserPhoto(UserId)); _photoId = UserId; } catch @@ -158,7 +156,7 @@ private async void LoadData() { try { - user = await provider.Graph().Me.Request().GetAsync(); + user = await provider.Graph().GetMeAsync(); } catch { @@ -166,7 +164,7 @@ private async void LoadData() try { - await DecodeStreamAsync(await provider.Graph().Me.Photo.Content.Request().GetAsync()); + await DecodeStreamAsync(await provider.BetaGraph().GetMyPhotoAsync()); _photoId = user.Id; } catch @@ -196,14 +194,14 @@ private async Task LoadImageAsync(Person person) try { // TODO: Better guarding - var graph = ProviderManager.Instance.GlobalProvider.Graph(); + var graph = ProviderManager.Instance.GlobalProvider.BetaGraph(); if (!string.IsNullOrWhiteSpace(person.UserPrincipalName)) { await DecodeStreamAsync(await graph.GetUserPhoto(person.UserPrincipalName)); _photoId = person.Id; // TODO: Only set on success for photo? } - else if (!string.IsNullOrWhiteSpace(person.EmailAddresses.First().Address)) + else if (!string.IsNullOrWhiteSpace(person.ScoredEmailAddresses.First().Address)) { // TODO https://github.com/microsoftgraph/microsoft-graph-toolkit/blob/master/src/components/mgt-person/mgt-person.ts#L174 } diff --git a/CommunityToolkit.Uwp.Graph.Controls/Controls/PersonView/PersonView.xaml b/CommunityToolkit.Uwp.Graph.Controls/Controls/PersonView/PersonView.xaml index 260d054..5f8bda1 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Controls/PersonView/PersonView.xaml +++ b/CommunityToolkit.Uwp.Graph.Controls/Controls/PersonView/PersonView.xaml @@ -65,7 +65,7 @@ Visibility="{Binding ShowName, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BoolToVisibilityConverter}}" />