├── MicrosoftGraphBot ├── Global.asax ├── Models │ ├── EntityType.cs │ ├── ItemType.cs │ ├── File.cs │ ├── Mail.cs │ ├── Plan.cs │ ├── Bucket.cs │ ├── ItemBase.cs │ ├── OperationType.cs │ ├── BaseEntity.cs │ ├── Group.cs │ ├── PlanTask.cs │ ├── User.cs │ └── QueryOperation.cs ├── default.htm ├── Dialog │ ├── ResourceTypes │ │ ├── PhotoDialog.cs │ │ ├── DirectReportsDialog.cs │ │ ├── MembersDialog.cs │ │ ├── ManagerDialog.cs │ │ ├── FilesDialog.cs │ │ └── TasksDialog.cs │ ├── PlanLookupDialog.cs │ ├── BucketLookupDialog.cs │ ├── AuthDialog.cs │ ├── UserLookupDialog.cs │ ├── GroupLookupDialog.cs │ ├── EntityLookupDialog.cs │ └── GraphDialog.cs ├── Global.asax.cs ├── Web.Debug.config ├── Web.Release.config ├── App_Start │ └── WebApiConfig.cs ├── Properties │ └── AssemblyInfo.cs ├── Controllers │ └── MessagesController.cs ├── packages.config ├── Web.config ├── Resource.resx ├── Resource.Designer.cs ├── MicrosoftGraphBot.csproj └── Extensions.cs ├── MicrosoftGraphBot.Tests ├── MailTests.cs ├── EventsTests.cs ├── FilesTests.cs ├── GroupsTests.cs ├── ManagerTests.cs ├── MembersTests.cs ├── PeopleTests.cs ├── PersonTests.cs ├── PhotoTests.cs ├── PlansTests.cs ├── TasksTests.cs ├── ContactsTests.cs ├── NotebooksTests.cs ├── TrendingTests.cs ├── WorkingWithTests.cs ├── DirectReportsTests.cs ├── Properties │ └── AssemblyInfo.cs └── MicrosoftGraphBot.Tests.csproj ├── botframework-csharp-graph-explorer.yml ├── README.md ├── LICENSE ├── MicrosoftGraphBot.sln ├── SECURITY.md └── .gitignore /MicrosoftGraphBot/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="MicrosoftGraphBot.WebApiApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /MicrosoftGraphBot/Models/EntityType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MicrosoftGraphBot.Models 4 | { 5 | [Serializable] 6 | public enum EntityType 7 | { 8 | Me, 9 | User, 10 | Group, 11 | Plan 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/MailTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class MailTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/EventsTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class EventsTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/FilesTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class FilesTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/GroupsTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class GroupsTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/ManagerTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class ManagerTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/MembersTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class MembersTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/PeopleTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class PeopleTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/PersonTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class PersonTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/PhotoTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class PhotoTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/PlansTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class PlansTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/TasksTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class TasksTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/ContactsTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class ContactsTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/NotebooksTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class NotebooksTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/TrendingTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class TrendingTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/WorkingWithTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class WorkingWithTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot.Tests/DirectReportsTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace MicrosoftGraphBot.Tests 5 | { 6 | [TestClass] 7 | public class DirectReportsTests 8 | { 9 | [TestMethod] 10 | public void TestMethod1() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MicrosoftGraphBot/Models/ItemType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MicrosoftGraphBot.Models 4 | { 5 | [Serializable] 6 | public enum ItemType 7 | { 8 | File, 9 | Folder, 10 | Mail, 11 | Event, 12 | Contact, 13 | Person, 14 | Group, 15 | NavNext, 16 | NavPrevious, 17 | NavUp, 18 | Cancel, 19 | Plan, 20 | Bucket, 21 | Task 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /botframework-csharp-graph-explorer.yml: -------------------------------------------------------------------------------- 1 | page_type: sample 2 | products: 3 | - ms-graph 4 | languages: 5 | - csharp 6 | extensions: 7 | contentType: tools 8 | technologies: 9 | - Microsoft Graph 10 | - Microsoft Bot Framework 11 | createdDate: '7/20/2016 10:34:50 PM' 12 | title: botframework-csharp-graph-explorer 13 | description: The Microsoft Graph Bot is a bot built with the Microsoft Bot Framework that allows interactive exploration of Microsoft Graph. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BotFramework-CSharp-Graph-Explorer 2 | Repository for the Microsoft Graph Bot, which is a Bot for exploring the information contained in the Microsoft cloud. 3 | 4 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /MicrosoftGraphBot/default.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |Describe your bot here and your terms of use etc.
10 |Visit Bot Framework to register your bot. When you register it, remember to set your bot's endpoint to
https://your_bots_hostname/api/messages
11 |
12 |
13 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Models/File.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MicrosoftGraphBot.Models
8 | {
9 | [Serializable]
10 | public class File : ItemBase
11 | {
12 | public File() : base() { }
13 | public File(string text, string endpoint, ItemType type) : base(text, endpoint, type) { }
14 |
15 | public int size { get; set; }
16 | public string webUrl { get; set; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Models/Mail.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MicrosoftGraphBot.Models
8 | {
9 | [Serializable]
10 | public class Mail : ItemBase
11 | {
12 | public Mail() : base() { }
13 | public Mail(string text, string endpoint, ItemType type) : base(text, endpoint, type) { }
14 |
15 | public string importance { get; set; }
16 | public string senderName { get; set; }
17 | public string senderEmail { get; set; }
18 | public DateTime sentDate { get; set; }
19 | public bool isRead { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Models/Plan.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Newtonsoft.Json;
3 |
4 | namespace MicrosoftGraphBot.Models
5 | {
6 | [Serializable]
7 | public class Plan : ItemBase
8 | {
9 | [JsonProperty("@odata.etag")]
10 | public string ETag { get; set; }
11 |
12 | public string Id
13 | {
14 | get { return id; }
15 | set
16 | {
17 | id = value;
18 | navEndpoint = $"/tasks/{value}";
19 | }
20 | }
21 |
22 | public string Title
23 | {
24 | get { return text; }
25 | set
26 | {
27 | text = value;
28 | }
29 | }
30 |
31 | public string Owner { get; set; }
32 |
33 | public string CreatedBy { get; set; }
34 |
35 | public Plan()
36 | : base(null, null, ItemType.Plan)
37 | {
38 |
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Models/Bucket.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Newtonsoft.Json;
3 |
4 | namespace MicrosoftGraphBot.Models
5 | {
6 | [Serializable]
7 | public class Bucket : ItemBase
8 | {
9 | [JsonProperty("@odata.etag")]
10 | public string ETag { get; set; }
11 |
12 | public string Id
13 | {
14 | get { return id; }
15 | set
16 | {
17 | id = value;
18 | navEndpoint = $"/tasks/{value}";
19 | }
20 | }
21 |
22 | public string Name
23 | {
24 | get { return text; }
25 | set
26 | {
27 | text = value;
28 | }
29 | }
30 |
31 | public string PlanId { get; set; }
32 |
33 | public string OrderHint { get; set; }
34 |
35 | public Bucket()
36 | : base(null, null, ItemType.Bucket)
37 | {
38 |
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Models/ItemBase.cs:
--------------------------------------------------------------------------------
1 | using MicrosoftGraphBot.Dialog;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace MicrosoftGraphBot.Models
11 | {
12 | [Serializable]
13 | public class ItemBase
14 | {
15 | public ItemBase() { }
16 | public ItemBase(string text, string endpoint, ItemType type)
17 | {
18 | this.text = text;
19 | this.navEndpoint = endpoint;
20 | this.itemType = type;
21 | }
22 |
23 | public string id { get; set; }
24 | public string text { get; set; }
25 | public string navEndpoint { get; set; }
26 | public ItemType itemType { get; set; }
27 |
28 | public override string ToString()
29 | {
30 | return this.text;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Models/OperationType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MicrosoftGraphBot.Models
8 | {
9 | [Serializable]
10 | public enum OperationType
11 | {
12 | Manager,
13 | DirectReports,
14 | Photo,
15 | Files,
16 | Mail,
17 | Events,
18 | Contacts,
19 | Groups,
20 | WorkingWith,
21 | TrendingAround,
22 | People,
23 | Notebooks,
24 | Tasks,
25 | Plans,
26 | Members,
27 | Conversations,
28 |
29 | //Navigation choices
30 | Next,
31 | Previous,
32 | Up,
33 | StartOver,
34 | ChangeDialogEntity,
35 | ShowOperations,
36 | Create,
37 | Delete,
38 | Download,
39 | Upload,
40 | Folder,
41 | InProgress,
42 | Complete
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Models/BaseEntity.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MicrosoftGraphBot.Models
4 | {
5 | [Serializable]
6 | public class BaseEntity
7 | {
8 | public BaseEntity() { }
9 | public BaseEntity(User user, EntityType type)
10 | {
11 | this.id = user.id;
12 | this.text = user.ToString();
13 | this.entityType = type;
14 | }
15 |
16 | public BaseEntity(Group group)
17 | {
18 | this.id = group.id;
19 | this.text = group.ToString();
20 | this.entityType = EntityType.Group;
21 | }
22 |
23 | public BaseEntity(Plan plan)
24 | {
25 | this.id = plan.id;
26 | this.text = plan.Title;
27 | this.entityType = EntityType.Plan;
28 | }
29 |
30 | public string id { get; set; }
31 | public string text { get; set; }
32 | public EntityType entityType { get; set; }
33 |
34 | public override string ToString()
35 | {
36 | return this.text;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Dialog/ResourceTypes/PhotoDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MicrosoftGraphBot.Dialog.ResourceTypes
10 | {
11 | public class PhotoDialog : IDialog
12 | {
13 | ///
14 | /// Called to start a dialog
15 | ///
16 | /// IDialogContext
17 | ///
18 | public async Task StartAsync(IDialogContext context)
19 | {
20 | context.Wait(MessageReceivedAsync);
21 | }
22 |
23 | ///
24 | /// Processes messages received on new thread
25 | ///
26 | /// IDialogContext
27 | /// Awaitable IMessageActivity
28 | /// Task
29 | public async Task MessageReceivedAsync(IDialogContext context, IAwaitable item)
30 | {
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Microsoft. All rights reserved.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Global.asax.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Web;
6 | using System.Web.Http;
7 | using System.Web.Routing;
8 |
9 | namespace MicrosoftGraphBot
10 | {
11 | public class WebApiApplication : System.Web.HttpApplication
12 | {
13 | protected void Application_Start()
14 | {
15 | GlobalConfiguration.Configure(WebApiConfig.Register);
16 |
17 | AuthBot.Models.AuthSettings.Mode = ConfigurationManager.AppSettings["ActiveDirectory.Mode"];
18 | AuthBot.Models.AuthSettings.EndpointUrl = ConfigurationManager.AppSettings["ActiveDirectory.EndpointUrl"];
19 | AuthBot.Models.AuthSettings.Tenant = ConfigurationManager.AppSettings["ActiveDirectory.Tenant"];
20 | AuthBot.Models.AuthSettings.RedirectUrl = ConfigurationManager.AppSettings["ActiveDirectory.RedirectUrl"];
21 | AuthBot.Models.AuthSettings.ClientId = ConfigurationManager.AppSettings["ActiveDirectory.ClientId"];
22 | AuthBot.Models.AuthSettings.ClientSecret = ConfigurationManager.AppSettings["ActiveDirectory.ClientSecret"];
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Dialog/PlanLookupDialog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Microsoft.Bot.Builder.Dialogs;
4 | using MicrosoftGraphBot.Models;
5 | using Newtonsoft.Json.Linq;
6 |
7 | namespace MicrosoftGraphBot.Dialog
8 | {
9 | [Serializable]
10 | public class PlanLookupDialog : EntityLookupDialog
11 | {
12 | public override string LookupPrompt => "Which plan are you interested in (lookup by full/partial name)?";
13 |
14 | public override string NoLookupPrompt => "Which plan are you interested in?";
15 |
16 | public override string NoChoicesPrompt => "No choices found... do you want to try again?";
17 |
18 | public override string MultipleChoicesPrompt => "Multiple choices found... which plan would you like to choose?";
19 |
20 | public override string GetRequestUri(IDialogContext dialogContext)
21 | {
22 | var user = dialogContext.ConversationData.Get("Me");
23 | return $"https://graph.microsoft.com/beta/users/{user.id}/plans";
24 | }
25 |
26 | public override List DeserializeArray(JArray array)
27 | {
28 | return array.ToPlanList();
29 | }
30 |
31 | public override bool FilterEntity(Plan entity, string query)
32 | {
33 | return entity.Title.ToLower().Contains(query);
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Web.Debug.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
29 |
30 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Dialog/BucketLookupDialog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Microsoft.Bot.Builder.Dialogs;
4 | using MicrosoftGraphBot.Models;
5 | using Newtonsoft.Json.Linq;
6 |
7 | namespace MicrosoftGraphBot.Dialog
8 | {
9 | [Serializable]
10 | public class BucketLookupDialog : EntityLookupDialog
11 | {
12 | public override string LookupPrompt => "Which bucket are you interested in (lookup by full/partial name)?";
13 |
14 | public override string NoLookupPrompt => "Which bucket are you interested in?";
15 |
16 | public override string NoChoicesPrompt => "No choices found... do you want to try again?";
17 |
18 | public override string MultipleChoicesPrompt => "Multiple choices found... which bucket would you like to choose?";
19 |
20 | public override string GetRequestUri(IDialogContext dialogContext)
21 | {
22 | var plan = dialogContext.ConversationData.Get("Plan");
23 | return $"https://graph.microsoft.com/beta/plans/{plan.id}/buckets";
24 | }
25 |
26 | public override List DeserializeArray(JArray array)
27 | {
28 | return array.ToBucketList();
29 | }
30 |
31 | public override bool FilterEntity(Bucket entity, string query)
32 | {
33 | return entity.Name.ToLower().Contains(query);
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Web.Release.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
19 |
30 |
31 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/App_Start/WebApiConfig.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Serialization;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Web.Http;
7 |
8 | namespace MicrosoftGraphBot
9 | {
10 | public static class WebApiConfig
11 | {
12 | public static void Register(HttpConfiguration config)
13 | {
14 | // Json settings
15 | config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
16 | config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
17 | config.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
18 | JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
19 | {
20 | ContractResolver = new CamelCasePropertyNamesContractResolver(),
21 | Formatting = Newtonsoft.Json.Formatting.Indented,
22 | NullValueHandling = NullValueHandling.Ignore,
23 | };
24 |
25 | // Web API configuration and services
26 |
27 | // Web API routes
28 | config.MapHttpAttributeRoutes();
29 |
30 | config.Routes.MapHttpRoute(
31 | name: "DefaultApi",
32 | routeTemplate: "api/{controller}/{id}",
33 | defaults: new { id = RouteParameter.Optional }
34 | );
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("MicrosoftGraphBot")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("MicrosoftGraphBot")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("a8ba1066-5695-4d71-abb4-65e5a5e0c3d4")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Revision and Build Numbers
33 | // by using the '*' as shown below:
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
36 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("MicrosoftGraphBot.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("MicrosoftGraphBot.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("fabe0c7e-0b52-4148-a4ce-d8d3de79876d")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Controllers/MessagesController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Net;
4 | using System.Net.Http;
5 | using System.Threading.Tasks;
6 | using System.Web.Http;
7 | using System.Web.Http.Description;
8 | using Microsoft.Bot.Connector;
9 | using Newtonsoft.Json;
10 | using Microsoft.Bot.Builder.Dialogs;
11 | using MicrosoftGraphBot.Dialog;
12 |
13 | namespace MicrosoftGraphBot
14 | {
15 | [BotAuthentication]
16 | public class MessagesController : ApiController
17 | {
18 | ///
19 | /// POST: api/Messages
20 | /// Receive a message from a user and reply to it
21 | ///
22 | [BotAuthentication]
23 | public virtual async Task Post([FromBody]Activity activity)
24 | {
25 | if (activity != null && activity.GetActivityType() == ActivityTypes.Message)
26 | {
27 | await Conversation.SendAsync(activity, () => new AuthDialog());
28 | }
29 | else
30 | {
31 | this.HandleSystemMessage(activity);
32 | }
33 | return new HttpResponseMessage(System.Net.HttpStatusCode.Accepted);
34 | }
35 |
36 | private Activity HandleSystemMessage(Activity message)
37 | {
38 | if (message.Type == ActivityTypes.Ping)
39 | {
40 | Activity reply = message.CreateReply();
41 | reply.Type = ActivityTypes.Ping;
42 | return reply;
43 | }
44 |
45 | return null;
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Models/Group.cs:
--------------------------------------------------------------------------------
1 | using AuthBot;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Net.Http;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using MicrosoftGraphBot.Dialog;
9 | using System.Text.RegularExpressions;
10 | using Newtonsoft.Json.Linq;
11 | using Microsoft.Bot.Builder.Dialogs;
12 | using Microsoft.Bot.Builder.Luis.Models;
13 |
14 | namespace MicrosoftGraphBot.Models
15 | {
16 | [Serializable]
17 | public class Group : ItemBase
18 | {
19 | public Group() : base() { }
20 | public Group(string text, string endpoint, ItemType type) : base(text, endpoint, type) { }
21 | public string description { get; set; }
22 | public string mail { get; set; }
23 | public string[] groupTypes { get; set; }
24 | public string visibility { get; set; }
25 |
26 | public override string ToString()
27 | {
28 | return this.text;
29 | }
30 |
31 | public static async Task> Lookup(string token, string searchPhrase)
32 | {
33 | List groups = new List();
34 | HttpClient client = new HttpClient();
35 |
36 | //search for the user
37 | var endpoint = String.Format("https://graph.microsoft.com/v1.0/groups?$filter=startswith(displayName,'{0}')%20or%20startswith(mail,'{0}')", searchPhrase);
38 | var json = await client.MSGraphGET(token, endpoint);
39 | groups = ((JArray)json["value"]).ToGroupList();
40 |
41 | return groups;
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25123.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MicrosoftGraphBot", "MicrosoftGraphBot\MicrosoftGraphBot.csproj", "{A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MicrosoftGraphBot.Tests", "MicrosoftGraphBot.Tests\MicrosoftGraphBot.Tests.csproj", "{FABE0C7E-0B52-4148-A4CE-D8D3DE79876D}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {FABE0C7E-0B52-4148-A4CE-D8D3DE79876D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {FABE0C7E-0B52-4148-A4CE-D8D3DE79876D}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {FABE0C7E-0B52-4148-A4CE-D8D3DE79876D}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {FABE0C7E-0B52-4148-A4CE-D8D3DE79876D}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Models/PlanTask.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Newtonsoft.Json;
3 |
4 | namespace MicrosoftGraphBot.Models
5 | {
6 | [Serializable]
7 | public class PlanTask : ItemBase
8 | {
9 | [JsonProperty("@odata.etag")]
10 | public string ETag { get; set; }
11 |
12 | public string Id
13 | {
14 | get { return id; }
15 | set
16 | {
17 | id = value;
18 | navEndpoint = $"/tasks/{value}";
19 | }
20 | }
21 |
22 | public string PlanId { get; set; }
23 |
24 | public string BucketId { get; set; }
25 |
26 | public string Title
27 | {
28 | get { return text; }
29 | set
30 | {
31 | text = value;
32 | }
33 | }
34 |
35 | public string CreatedBy { get; set; }
36 |
37 | public string AssignedTo { get; set; }
38 |
39 | public string OrderHint { get; set; }
40 |
41 | public string AssigneePriority { get; set; }
42 |
43 | public int PercentComplete { get; set; }
44 |
45 | public string StartDateTime { get; set; }
46 |
47 | public string AssignedDateTime { get; set; }
48 |
49 | public string CreatedDateTime { get; set; }
50 |
51 | public string AssignedBy { get; set; }
52 |
53 | public string DueDateTime { get; set; }
54 |
55 | public string PreviewType { get; set; }
56 |
57 | public string CompletedDateTime { get; set; }
58 |
59 | public string ConversationThreadId { get; set; }
60 |
61 | public PlanTask()
62 | : base(null, null, ItemType.Task)
63 | {
64 |
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Dialog/AuthDialog.cs:
--------------------------------------------------------------------------------
1 | using AuthBot;
2 | using AuthBot.Dialogs;
3 | using Microsoft.Bot.Builder.Dialogs;
4 | using Microsoft.Bot.Connector;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 |
12 | namespace MicrosoftGraphBot.Dialog
13 | {
14 | [Serializable]
15 | public class AuthDialog : IDialog
16 | {
17 | public async Task StartAsync(IDialogContext context)
18 | {
19 | context.Wait(MessageReceivedAsync);
20 | }
21 |
22 | public async Task MessageReceivedAsync(IDialogContext context, IAwaitable item)
23 | {
24 | //original message if we need to resume
25 | var message = await item;
26 |
27 | //try to get access token
28 | var token = await context.GetAccessToken("https://graph.microsoft.com/");
29 | if (string.IsNullOrEmpty(token))
30 | {
31 | //invoke the AuthBot to help get authenticated
32 | await context.Forward(new AzureAuthDialog("https://graph.microsoft.com/"), this.resumeAfterAuth, message, CancellationToken.None);
33 | }
34 | else
35 | {
36 | //token exists...forward to GraphDialog
37 | await context.Forward(new GraphDialog(), null, message, CancellationToken.None);
38 | }
39 | }
40 |
41 | private async Task resumeAfterAuth(IDialogContext context, IAwaitable result)
42 | {
43 | //post the response message and then go back into the MessageReceivedAsync flow
44 | var message = await result;
45 | await context.PostAsync(message);
46 |
47 | //now that token exists...forward to GraphDialog
48 | await context.Forward(new GraphDialog(), null, message, CancellationToken.None);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Models/User.cs:
--------------------------------------------------------------------------------
1 | using AuthBot;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Net.Http;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using MicrosoftGraphBot.Dialog;
9 | using System.Text.RegularExpressions;
10 | using Newtonsoft.Json.Linq;
11 | using Microsoft.Bot.Builder.Dialogs;
12 | using Microsoft.Bot.Builder.Luis.Models;
13 |
14 | namespace MicrosoftGraphBot.Models
15 | {
16 | [Serializable]
17 | public class User : ItemBase
18 | {
19 | public User() : base() { }
20 | public User(string text, string endpoint, ItemType type) : base(text, endpoint, type) { }
21 | public bool isMe { get; set; }
22 | public string givenName { get; set; }
23 | public string surname { get; set; }
24 | public string jobTitle { get; set; }
25 | public string mail { get; set; }
26 | public string userPrincipalName { get; set; }
27 | public string mobilePhone { get; set; }
28 | public string officeLocation { get; set; }
29 |
30 | public override string ToString()
31 | {
32 | return this.text;
33 | }
34 |
35 |
36 | public static async Task Me(string token)
37 | {
38 | HttpClient client = new HttpClient();
39 |
40 | //return the current user
41 | var json = await client.MSGraphGET(token, "https://graph.microsoft.com/v1.0/me");
42 | return json.ToUser();
43 | }
44 |
45 | public static async Task> Lookup(string token, string searchPhrase)
46 | {
47 | List users = new List();
48 | HttpClient client = new HttpClient();
49 |
50 | //search for the user
51 | var endpoint = String.Format("https://graph.microsoft.com/v1.0/users?$filter=startswith(givenName,'{0}')%20or%20startswith(surname,'{0}')%20or%20startswith(displayName,'{0}')%20or%20startswith(userPrincipalName,'{0}')", searchPhrase);
52 | var json = await client.MSGraphGET(token, endpoint);
53 | users = ((JArray)json["value"]).ToUserList();
54 |
55 | return users;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Dialog/UserLookupDialog.cs:
--------------------------------------------------------------------------------
1 | using AuthBot;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using Microsoft.Bot.Connector;
4 | using MicrosoftGraphBot.Models;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace MicrosoftGraphBot.Dialog
12 | {
13 | [Serializable]
14 | public class UserLookupDialog : IDialog
15 | {
16 | public async Task StartAsync(IDialogContext context)
17 | {
18 | context.Wait(MessageReceivedAsync);
19 | }
20 |
21 | public async Task MessageReceivedAsync(IDialogContext context, IAwaitable item)
22 | {
23 | //don't await the message...we won't use it
24 | PromptDialog.Text(context, async (IDialogContext textContext, IAwaitable textResult) =>
25 | {
26 | //get the result and perform the user lookup
27 | var searchText = await textResult;
28 | var token = await textContext.GetAccessToken("https://graph.microsoft.com");
29 | var matches = await User.Lookup(token, searchText);
30 |
31 | //check the number of matches and respond accordingly
32 | if (matches.Count == 0)
33 | {
34 | //no matches...allow retry
35 | PromptDialog.Confirm(textContext, async (IDialogContext retryContext, IAwaitable retryResult) =>
36 | {
37 | //check retry result and handle accordingly
38 | var retry = await retryResult;
39 | if (retry)
40 | await MessageReceivedAsync(retryContext, null); //retry
41 | else
42 | retryContext.Done(null); //return null
43 | }, "No matches found...want to try again?");
44 | }
45 | else if (matches.Count == 1)
46 | {
47 | //resolve the exact match
48 | textContext.Done(matches[0]);
49 | }
50 | else
51 | {
52 | //multiple matches...give choice
53 | PromptDialog.Choice(textContext, async (IDialogContext choiceContext, IAwaitable choiceResult) =>
54 | {
55 | var selection = await choiceResult;
56 | choiceContext.Done(selection);
57 | }, matches, "Multiple matches found...which user would you like to explore?");
58 | }
59 | }, "What user are you interested in (you can lookup by full/partial name or alias)?");
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Dialog/GroupLookupDialog.cs:
--------------------------------------------------------------------------------
1 | using AuthBot;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using Microsoft.Bot.Connector;
4 | using MicrosoftGraphBot.Models;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace MicrosoftGraphBot.Dialog
12 | {
13 | [Serializable]
14 | public class GroupLookupDialog : IDialog
15 | {
16 | public async Task StartAsync(IDialogContext context)
17 | {
18 | context.Wait(MessageReceivedAsync);
19 | }
20 |
21 | public async Task MessageReceivedAsync(IDialogContext context, IAwaitable item)
22 | {
23 | //don't await the message...we won't use it
24 | PromptDialog.Text(context, async (IDialogContext textContext, IAwaitable textResult) =>
25 | {
26 | //get the result and perform the group lookup
27 | var searchText = await textResult;
28 | var token = await textContext.GetAccessToken("https://graph.microsoft.com");
29 | var matches = await Group.Lookup(token, searchText);
30 |
31 | //check the number of matches and respond accordingly
32 | if (matches.Count == 0)
33 | {
34 | //no matches...allow retry
35 | PromptDialog.Confirm(textContext, async (IDialogContext retryContext, IAwaitable retryResult) =>
36 | {
37 | //check retry result and handle accordingly
38 | var retry = await retryResult;
39 | if (retry)
40 | await MessageReceivedAsync(retryContext, null); //retry
41 | else
42 | retryContext.Done(null); //return null
43 | }, "No matches found...want to try again?");
44 | }
45 | else if (matches.Count == 1)
46 | {
47 | //resolve the exact match
48 | textContext.Done(matches[0]);
49 | }
50 | else
51 | {
52 | //multiple matches...give choice
53 | PromptDialog.Choice(textContext, async (IDialogContext choiceContext, IAwaitable choiceResult) =>
54 | {
55 | var selection = await choiceResult;
56 | choiceContext.Done(selection);
57 | }, matches, "Multiple matches found...which user would you like to explore?");
58 | }
59 | }, "What group are you interested in (you can lookup by full/partial name or alias)?");
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Models/QueryOperation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Newtonsoft.Json.Linq;
7 |
8 | namespace MicrosoftGraphBot.Models
9 | {
10 | [Serializable]
11 | public class QueryOperation
12 | {
13 | public string Text { get; set; }
14 | public OperationType Type { get; set; }
15 | public string Endpoint { get; set; }
16 | public object ContextObject { get; set; }
17 |
18 | public override string ToString()
19 | {
20 | return Text;
21 | }
22 |
23 | public T GetContextObjectAs() where T : class
24 | {
25 | if (ContextObject is T)
26 | {
27 | return (T)ContextObject;
28 | }
29 | if (ContextObject is JObject)
30 | {
31 | return ((JObject)ContextObject).ToObject();
32 | }
33 | return null;
34 | }
35 |
36 | public static List GetEntityResourceTypes(EntityType entityType)
37 | {
38 | if (entityType == EntityType.Me)
39 | return meResourceTypes.ToQueryOperations();
40 | else if (entityType == EntityType.User)
41 | return userResourceTypes.ToQueryOperations();
42 | else if (entityType == EntityType.Group)
43 | return groupResourceTypes.ToQueryOperations();
44 | else
45 | return null;
46 | }
47 |
48 | private static List meResourceTypes = new List() {
49 | OperationType.Manager,
50 | OperationType.DirectReports,
51 | OperationType.Photo,
52 | OperationType.Files,
53 | OperationType.Mail,
54 | OperationType.Events,
55 | OperationType.Contacts,
56 | OperationType.Groups,
57 | OperationType.WorkingWith,
58 | OperationType.TrendingAround,
59 | OperationType.People,
60 | OperationType.Notebooks,
61 | OperationType.Tasks,
62 | OperationType.Plans
63 | };
64 | private static List userResourceTypes = new List() {
65 | OperationType.Manager,
66 | OperationType.DirectReports,
67 | OperationType.Photo,
68 | OperationType.Files,
69 | OperationType.Groups,
70 | OperationType.WorkingWith,
71 | OperationType.TrendingAround,
72 | OperationType.People,
73 | OperationType.Notebooks,
74 | OperationType.Tasks,
75 | OperationType.Plans
76 | };
77 | private static List groupResourceTypes = new List() {
78 | OperationType.Members,
79 | OperationType.Files,
80 | OperationType.Conversations,
81 | OperationType.Events,
82 | OperationType.Photo,
83 | OperationType.Notebooks
84 | };
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Dialog/ResourceTypes/DirectReportsDialog.cs:
--------------------------------------------------------------------------------
1 | using MicrosoftGraphBot;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using Microsoft.Bot.Connector;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Net.Http;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using Newtonsoft.Json.Linq;
11 |
12 | namespace MicrosoftGraphBot.Dialog.ResourceTypes
13 | {
14 | public class DirectReportsDialog : IDialog
15 | {
16 | ///
17 | /// Called to start a dialog
18 | ///
19 | /// IDialogContext
20 | ///
21 | public async Task StartAsync(IDialogContext context)
22 | {
23 | context.Wait(MessageReceivedAsync);
24 | }
25 |
26 | ///
27 | /// Processes messages received on new thread
28 | ///
29 | /// IDialogContext
30 | /// Awaitable IMessageActivity
31 | /// Task
32 | public async Task MessageReceivedAsync(IDialogContext context, IAwaitable item)
33 | {
34 | var entity = context.ConversationData.GetDialogEntity();
35 | var directReports = await getDirectReports(context);
36 |
37 | //build a list of valid operations the user can take
38 | List operations = new List();
39 | foreach (var report in directReports)
40 | operations.Add(new Models.QueryOperation() { Text = report.text, Type = Models.OperationType.ChangeDialogEntity, ContextObject = report });
41 | operations.Add(new Models.QueryOperation() { Text = String.Format("(Other {0} queries)", entity.ToString()), Type = Models.OperationType.ShowOperations });
42 | operations.Add(new Models.QueryOperation() { Text = "(Start over)", Type = Models.OperationType.StartOver });
43 |
44 | //prepare the message
45 | var msg = String.Format("{0} does not have direct reports lists. What would you like to do next:", entity.text);
46 | if (directReports.Count == 0)
47 | msg = String.Format("{0} has the following direct reports. What would you like to do next:", entity.text);
48 |
49 | //Allow the user to select next path
50 | PromptDialog.Choice(context, async (IDialogContext choiceContext, IAwaitable choiceResult) =>
51 | {
52 | var option = await choiceResult;
53 |
54 | switch (option.Type)
55 | {
56 | case Models.OperationType.ChangeDialogEntity:
57 | var user = (Models.User)option.ContextObject;
58 | var eType = (user.IsMe(choiceContext)) ? Models.EntityType.Me : Models.EntityType.User;
59 | choiceContext.ConversationData.SaveDialogEntity(new Models.BaseEntity(user, eType));
60 | choiceContext.Done(false); //return to parent WITHOUT start over
61 | break;
62 | case Models.OperationType.ShowOperations:
63 | choiceContext.Done(false); //return to parent WITHOUT start over
64 | break;
65 | case Models.OperationType.StartOver:
66 | choiceContext.Done(true); //return to parent WITH start over
67 | break;
68 | }
69 | }, operations, msg);
70 | }
71 |
72 | private async Task> getDirectReports(IDialogContext context)
73 | {
74 | //Get the manager for the DialogEntity
75 | var entity = context.ConversationData.GetDialogEntity();
76 | HttpClient client = new HttpClient();
77 | var token = await context.GetAccessToken();
78 | var results = await client.MSGraphGET(token, String.Format("https://graph.microsoft.com/v1.0/users/{0}/directReports", entity.id));
79 | return ((JArray)results["value"]).ToUserList();
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Web.config:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
32 |
33 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Dialog/EntityLookupDialog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net.Http;
5 | using System.Threading.Tasks;
6 | using Microsoft.Bot.Builder.Dialogs;
7 | using Microsoft.Bot.Connector;
8 | using MicrosoftGraphBot.Models;
9 | using Newtonsoft.Json.Linq;
10 |
11 | namespace MicrosoftGraphBot.Dialog
12 | {
13 | [Serializable]
14 | public abstract class EntityLookupDialog : IDialog
15 | {
16 | private List _entities;
17 |
18 | public abstract string LookupPrompt { get; }
19 |
20 | public abstract string NoLookupPrompt { get; }
21 |
22 | public abstract string NoChoicesPrompt { get; }
23 |
24 | public abstract string MultipleChoicesPrompt { get; }
25 |
26 | public abstract string GetRequestUri(IDialogContext dialogContext);
27 |
28 | public abstract List DeserializeArray(JArray array);
29 |
30 | public abstract bool FilterEntity(T entity, string query);
31 |
32 | #pragma warning disable 1998
33 | public async Task StartAsync(IDialogContext context)
34 | #pragma warning restore 1998
35 | {
36 | context.Wait(ShowTextDialogAsync);
37 | }
38 |
39 | #pragma warning disable 1998
40 | public async Task ShowTextDialogAsync(IDialogContext context, IAwaitable item)
41 | #pragma warning restore 1998
42 | {
43 | // Get entities.
44 | var accessToken = await context.GetAccessToken();
45 | _entities = await GetEntitesAsync(context, accessToken);
46 |
47 | // No matches, retry.
48 | if (_entities.Count == 0)
49 | {
50 | Retry(context);
51 | }
52 | else
53 | {
54 | // If the entities are below five, let the user pick
55 | // one right away. If not, let the user do a lookup.
56 | if (_entities.Count <= 5)
57 | {
58 | ShowChoices(context, _entities, true);
59 | }
60 | else
61 | {
62 | PromptDialog.Text(context, OnTextDialogResumeAsync, LookupPrompt);
63 | }
64 | }
65 | }
66 |
67 | public async Task> GetEntitesAsync(IDialogContext context, string accessToken)
68 | {
69 | // Create HTTP Client and get the response.
70 | var httpClient = new HttpClient();
71 | var requestUri = GetRequestUri(context);
72 | var json = await httpClient.MSGraphGET(accessToken, requestUri);
73 |
74 | // Deserialize the response.
75 | var response = DeserializeArray((JArray)json["value"]);
76 | return response;
77 | }
78 |
79 | private async Task OnTextDialogResumeAsync(IDialogContext context, IAwaitable result)
80 | {
81 | // Filter the entities..
82 | var query = (await result).ToLower();
83 | var matches = _entities.Where(e => FilterEntity(e, query))
84 | .Take(5)
85 | .ToList();
86 |
87 | // Check the number of matches.
88 | switch (matches.Count)
89 | {
90 | case 0:
91 | // No matches, retry.
92 | Retry(context);
93 | break;
94 | case 1:
95 | // Resolve the exact match.
96 | context.Done(matches[0]);
97 | break;
98 | default:
99 | ShowChoices(context, matches, false);
100 | break;
101 | }
102 | }
103 |
104 | private void Retry(IDialogContext context)
105 | {
106 | PromptDialog.Confirm(context, async (retryContext, retryResult) =>
107 | {
108 | // Check retry result.
109 | var retry = await retryResult;
110 | if (retry)
111 | {
112 | await ShowTextDialogAsync(retryContext, null);
113 | }
114 | else
115 | {
116 | retryContext.Done(null);
117 | }
118 | }, NoChoicesPrompt);
119 | }
120 |
121 | private void ShowChoices(IDialogContext context, IEnumerable choices, bool firstPrompt)
122 | {
123 | PromptDialog.Choice(context, async (choiceContext, choiceResult) =>
124 | {
125 | var selection = await choiceResult;
126 | choiceContext.Done(selection);
127 | }, choices, firstPrompt ? NoLookupPrompt : MultipleChoicesPrompt);
128 | }
129 | }
130 | }
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Dialog/ResourceTypes/MembersDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Net.Http;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace MicrosoftGraphBot.Dialog.ResourceTypes
12 | {
13 | [Serializable]
14 | public class MembersDialog : IDialog
15 | {
16 | ///
17 | /// Called to start a dialog
18 | ///
19 | /// IDialogContext
20 | ///
21 | public async Task StartAsync(IDialogContext context)
22 | {
23 | context.Wait(MessageReceivedAsync);
24 | }
25 |
26 | ///
27 | /// Processes messages received on new thread
28 | ///
29 | /// IDialogContext
30 | /// Awaitable IMessageActivity
31 | /// Task
32 | public async Task MessageReceivedAsync(IDialogContext context, IAwaitable item)
33 | {
34 | var entity = context.ConversationData.GetDialogEntity();
35 | await processMembers(context, String.Format("https://graph.microsoft.com/v1.0/groups/{0}/members?$top=5", entity.id));
36 |
37 | }
38 |
39 | private async Task processMembers(IDialogContext context, string endpoint)
40 | {
41 | //save the current endpoint and retrieve the Dialog Entity
42 | context.SaveNavCurrent(endpoint);
43 | var entity = context.ConversationData.GetDialogEntity();
44 | var token = await context.GetAccessToken();
45 |
46 | //get the members from the database based on provided endpoint
47 | HttpClient client = new HttpClient();
48 | var json = await client.MSGraphGET(token, endpoint);
49 | var members = ((JArray)json["value"]).ToUserList();
50 |
51 | //convert to operations
52 | List operations = new List();
53 | foreach (var m in members)
54 | operations.Add(new Models.QueryOperation() { Text = m.text, Type = Models.OperationType.People, Endpoint = String.Format("https://graph.microsoft.com/v1.0/users/{0}", m.id) });
55 |
56 | //add paging
57 | operations.InitializePaging(context, json);
58 |
59 | //add other operations and start over
60 | operations.Add(new Models.QueryOperation() { Text = String.Format("(Other {0} queries)", entity.ToString()), Type = Models.OperationType.ShowOperations });
61 | operations.Add(new Models.QueryOperation() { Text = "(Start over)", Type = Models.OperationType.StartOver });
62 |
63 | //prompt the next selection
64 | PromptDialog.Choice(context, async (IDialogContext choiceContext, IAwaitable choiceResult) =>
65 | {
66 | var operation = await choiceResult;
67 | switch (operation.Type)
68 | {
69 | case Models.OperationType.People:
70 | //change the dialog entity and return without start over
71 | HttpClient c = new HttpClient();
72 | var t = await choiceContext.GetAccessToken();
73 | var j = await c.MSGraphGET(t, operation.Endpoint);
74 | var newEntity = j.ToUser();
75 | var etype = (newEntity.IsMe(choiceContext)) ? Models.EntityType.Me : Models.EntityType.User;
76 | choiceContext.ConversationData.SaveDialogEntity(new Models.BaseEntity(newEntity, etype));
77 | choiceContext.Done(false); //return with false to stick with same user
78 | break;
79 | case Models.OperationType.Next:
80 | choiceContext.NavPushItem(choiceContext.GetNavCurrent());
81 | await processMembers(choiceContext, operation.Endpoint);
82 | break;
83 | case Models.OperationType.Previous:
84 | choiceContext.NavPopItem();
85 | await processMembers(choiceContext, operation.Endpoint);
86 | break;
87 | case Models.OperationType.ShowOperations:
88 | choiceContext.Done(false); //return with false to stick with same user
89 | break;
90 | case Models.OperationType.StartOver:
91 | choiceContext.Done(true); //return with true to start over
92 | break;
93 | }
94 | }, operations, String.Format("{0} has the following members:", entity.text));
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot.Tests/MicrosoftGraphBot.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {FABE0C7E-0B52-4148-A4CE-D8D3DE79876D}
7 | Library
8 | Properties
9 | MicrosoftGraphBot.Tests
10 | MicrosoftGraphBot.Tests
11 | v4.5.2
12 | 512
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 10.0
15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
17 | False
18 | UnitTest
19 |
20 |
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | False
76 |
77 |
78 | False
79 |
80 |
81 | False
82 |
83 |
84 | False
85 |
86 |
87 |
88 |
89 |
90 |
91 |
98 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Dialog/ResourceTypes/ManagerDialog.cs:
--------------------------------------------------------------------------------
1 | using AuthBot;
2 | using MicrosoftGraphBot;
3 | using Microsoft.Bot.Builder.Dialogs;
4 | using Microsoft.Bot.Connector;
5 | using Microsoft.Identity.Client;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using System.Net.Http;
12 | using System.Threading;
13 |
14 | namespace MicrosoftGraphBot.Dialog.ResourceTypes
15 | {
16 | [Serializable]
17 | public class ManagerDialog : IDialog
18 | {
19 | ///
20 | /// Called to start a dialog
21 | ///
22 | /// IDialogContext
23 | ///
24 | public async Task StartAsync(IDialogContext context)
25 | {
26 | context.Wait(MessageReceivedAsync);
27 | }
28 |
29 | ///
30 | /// Processes messages received on new thread
31 | ///
32 | /// IDialogContext
33 | /// Awaitable IMessageActivity
34 | /// Task
35 | public async Task MessageReceivedAsync(IDialogContext context, IAwaitable item)
36 | {
37 | var entity = context.ConversationData.GetDialogEntity();
38 | var manager = await getManager(context);
39 |
40 | //build a list of valid operations the user can take
41 | List operations = new List();
42 | if (manager != null)
43 | {
44 | operations.Add(new Models.QueryOperation() { Text = String.Format("{0}'s photo", manager.ToString()), Type = Models.OperationType.Photo });
45 | operations.Add(new Models.QueryOperation() { Text = String.Format("{0}'s manager", manager.ToString()), Type = Models.OperationType.Manager });
46 | operations.Add(new Models.QueryOperation() { Text = String.Format("{0}'s direct reports", manager.ToString()), Type = Models.OperationType.DirectReports });
47 | operations.Add(new Models.QueryOperation() { Text = String.Format("(Other {0} queries)", manager.ToString()), Type = Models.OperationType.ChangeDialogEntity });
48 | }
49 | operations.Add(new Models.QueryOperation() { Text = String.Format("(Other {0} queries)", entity.ToString()), Type = Models.OperationType.ShowOperations });
50 | operations.Add(new Models.QueryOperation() { Text = "(Start over)", Type = Models.OperationType.StartOver });
51 |
52 | //prepare the message
53 | string msg = String.Format("{0} doesn't have a manager listed. What would you like to do next:", entity.text);
54 | if (manager != null)
55 | msg = String.Format("{0}'s manager is {1}. What would you like to do next:", entity.text, manager.ToString());
56 |
57 | //Allow the user to select next path
58 | PromptDialog.Choice(context, async (IDialogContext choiceContext, IAwaitable choiceResult) =>
59 | {
60 | var option = await choiceResult;
61 |
62 | switch (option.Type)
63 | {
64 | case Models.OperationType.Manager:
65 | case Models.OperationType.DirectReports:
66 | case Models.OperationType.ChangeDialogEntity:
67 | //change the dialog entity to the manager
68 | var newEntity = await getManager(choiceContext);
69 | var eType = (newEntity.IsMe(choiceContext)) ? Models.EntityType.Me : Models.EntityType.User;
70 | choiceContext.ConversationData.SaveDialogEntity(new Models.BaseEntity(newEntity, eType));
71 |
72 | //proceed based on selection
73 | if (option.Type == Models.OperationType.DirectReports)
74 | //forward to the PhotoDialog
75 | await choiceContext.Forward(new PhotoDialog(), async (IDialogContext drContext, IAwaitable drResult) =>
76 | {
77 | var startOver = await drResult;
78 | drContext.Done(startOver); //return to parent based on child start over value
79 | }, true, CancellationToken.None);
80 | else if (option.Type == Models.OperationType.Manager)
81 | await MessageReceivedAsync(choiceContext, null); //call back into this dialog to go up a level
82 | else if (option.Type == Models.OperationType.DirectReports)
83 | //forward to the DirectReportsDialog
84 | await choiceContext.Forward(new DirectReportsDialog(), async (IDialogContext drContext, IAwaitable drResult) =>
85 | {
86 | var startOver = await drResult;
87 | drContext.Done(startOver); //return to parent based on child start over value
88 | }, true, CancellationToken.None);
89 | else if (option.Type == Models.OperationType.ChangeDialogEntity)
90 | choiceContext.Done(false); //return to partent WITHOUT start over
91 | break;
92 | case Models.OperationType.ShowOperations:
93 | choiceContext.Done(false); //return to parent WITHOUT start over
94 | break;
95 | case Models.OperationType.StartOver:
96 | choiceContext.Done(true); //return to parent WITH start over
97 | break;
98 | }
99 | }, operations, msg);
100 | }
101 |
102 | ///
103 | /// Performs the MS Graph query for a manager
104 | ///
105 | /// IDialogContext
106 | /// User
107 | private async Task getManager(IDialogContext context)
108 | {
109 | //Get the manager for the DialogEntity
110 | var entity = context.ConversationData.GetDialogEntity();
111 | HttpClient client = new HttpClient();
112 | var token = await context.GetAccessToken();
113 | var results = await client.MSGraphGET(token, String.Format("https://graph.microsoft.com/v1.0/users/{0}/manager", entity.id));
114 | return results.ToUser();
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Dialog/GraphDialog.cs:
--------------------------------------------------------------------------------
1 | using AuthBot;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using Microsoft.Bot.Connector;
4 | using MicrosoftGraphBot.Models;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 | using MicrosoftGraphBot.Dialog.ResourceTypes;
12 |
13 | namespace MicrosoftGraphBot.Dialog
14 | {
15 | [Serializable]
16 | public class GraphDialog : IDialog
17 | {
18 | ///
19 | /// Called to start a dialog
20 | ///
21 | /// IDialogContext
22 | ///
23 | public async Task StartAsync(IDialogContext context)
24 | {
25 | context.Wait(MessageReceivedAsync);
26 | }
27 |
28 | ///
29 | /// Processes messages received on new thread
30 | ///
31 | /// IDialogContext
32 | /// Awaitable IMessageActivity
33 | /// Task
34 | public async Task MessageReceivedAsync(IDialogContext context, IAwaitable item)
35 | {
36 | //start by having the user select the entity type to query
37 | await context.Initialize();
38 | PromptDialog.Choice(context, this.EntityTypeSelected, Enum.GetNames(typeof(EntityType)).Where(e => e != EntityType.Plan.ToString()), "Where do you want to start exploring?");
39 | }
40 |
41 | ///
42 | /// Resume from user selecting the type of entity they want to query
43 | ///
44 | /// IDialogContext
45 | /// Awaitable string
46 | /// Task
47 | public async Task EntityTypeSelected(IDialogContext context, IAwaitable item)
48 | {
49 | EntityType intent = (EntityType)Enum.Parse(typeof(EntityType), await item);
50 | switch (intent)
51 | {
52 | case EntityType.Me:
53 | //get me
54 | var me = context.ConversationData.Me();
55 |
56 | //save the entity and show available operations
57 | context.ConversationData.SaveDialogEntity(new BaseEntity(me, EntityType.Me));
58 | await routeOperation(context);
59 | break;
60 | case EntityType.User:
61 | //prompt for user
62 | await context.Forward(new UserLookupDialog(), async (IDialogContext lookupContext, IAwaitable lookupResult) =>
63 | {
64 | var user = await lookupResult;
65 |
66 | //save the entity and show available operations
67 | lookupContext.ConversationData.SaveDialogEntity(new BaseEntity(user, EntityType.User));
68 | await routeOperation(lookupContext);
69 | }, new User(), CancellationToken.None);
70 | break;
71 | case EntityType.Group:
72 | //prompt for group
73 | await context.Forward(new GroupLookupDialog(), async (IDialogContext lookupContext, IAwaitable lookupResult) =>
74 | {
75 | var group = await lookupResult;
76 |
77 | //save the entity and show available operations
78 | lookupContext.ConversationData.SaveDialogEntity(new BaseEntity(group));
79 | await routeOperation(lookupContext);
80 | }, new Group(), CancellationToken.None);
81 | break;
82 | }
83 | }
84 |
85 | ///
86 | /// Prompts the user to chose an operation and routes it to the appropriate dialog
87 | ///
88 | /// IDialogContext
89 | /// Task
90 | private async Task routeOperation(IDialogContext context)
91 | {
92 | //initialize a new operation on the context
93 | context.NewOperation();
94 |
95 | //check the entity type to determine the valid operations
96 | var entity = context.ConversationData.GetDialogEntity();
97 | List operations = QueryOperation.GetEntityResourceTypes(entity.entityType);
98 |
99 | //prepare the prompt
100 | string prompt = "What would like to lookup for you?";
101 | if (entity.entityType != EntityType.Me)
102 | prompt = String.Format("What would like to lookup for {0}?", entity.text);
103 |
104 | //add start over
105 | operations.Add(new Models.QueryOperation() { Text = "(Start over)", Type = Models.OperationType.StartOver });
106 |
107 | //let the user select an operation
108 | PromptDialog.Choice(context, async (IDialogContext opContext, IAwaitable opResult) =>
109 | {
110 | //check the operation selected and route appropriately
111 | var operation = await opResult;
112 | switch (operation.Type)
113 | {
114 | case OperationType.StartOver:
115 | await this.MessageReceivedAsync(opContext, null);
116 | break;
117 | case OperationType.Manager:
118 | await opContext.Forward(new ResourceTypes.ManagerDialog(), OperationComplete, true, CancellationToken.None);
119 | break;
120 | case OperationType.DirectReports:
121 | await opContext.Forward(new ResourceTypes.DirectReportsDialog(), OperationComplete, true, CancellationToken.None);
122 | break;
123 | case OperationType.Files:
124 | await opContext.Forward(new ResourceTypes.FilesDialog(), OperationComplete, true, CancellationToken.None);
125 | break;
126 | case OperationType.Members:
127 | await opContext.Forward(new ResourceTypes.MembersDialog(), OperationComplete, true, CancellationToken.None);
128 | break;
129 | case OperationType.Contacts:
130 | case OperationType.Conversations:
131 | case OperationType.Events:
132 | case OperationType.Groups:
133 | case OperationType.Mail:
134 | case OperationType.Notebooks:
135 | case OperationType.People:
136 | case OperationType.Photo:
137 | case OperationType.Plans:
138 | await opContext.Forward(new PlanLookupDialog(), OnPlanLookupDialogResumeAsync, new Plan(), CancellationToken.None);
139 | break;
140 | case OperationType.Tasks:
141 | await opContext.Forward(new TasksDialog(), OperationComplete, true, CancellationToken.None);
142 | break;
143 | case OperationType.TrendingAround:
144 | case OperationType.WorkingWith:
145 | await opContext.PostAsync("Operation not yet implemented");
146 | opContext.Wait(MessageReceivedAsync);
147 | break;
148 | }
149 |
150 | }, operations, prompt);
151 | }
152 |
153 | private async Task OnPlanLookupDialogResumeAsync(IDialogContext context, IAwaitable result)
154 | {
155 | var plan = await result;
156 |
157 | context.ConversationData.SaveDialogEntity(new BaseEntity(plan));
158 | await context.Forward(new TasksDialog(), OperationComplete, true, CancellationToken.None);
159 | }
160 |
161 | ///
162 | /// The resume from performing a Graph operation
163 | /// Allows the user to start over or select a different operation
164 | ///
165 | /// IDialogContext
166 | /// Awaitable bool indicating if start over
167 | /// Task
168 | public async Task OperationComplete(IDialogContext context, IAwaitable result)
169 | {
170 | var startOver = await result;
171 | if (startOver)
172 | await this.MessageReceivedAsync(context, null);
173 | else
174 | await this.routeOperation(context);
175 | }
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Resource.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Contacts
122 |
123 |
124 | /contacts
125 |
126 |
127 | Conversations
128 |
129 |
130 | /conversations
131 |
132 |
133 | Direct Reports
134 |
135 |
136 | /directReports
137 |
138 |
139 | Events
140 |
141 |
142 | /events
143 |
144 |
145 | Files
146 |
147 |
148 | /drive/root/children
149 |
150 |
151 | Groups
152 |
153 |
154 | /memberOf
155 |
156 |
157 | Mail
158 |
159 |
160 | /messages
161 |
162 |
163 | Manager
164 |
165 |
166 | /manager
167 |
168 |
169 | Group Members
170 |
171 |
172 | /members
173 |
174 |
175 | Notebooks
176 |
177 |
178 | /notes/notebooks
179 |
180 |
181 | Works With (w/Groups)
182 |
183 |
184 | /people
185 |
186 |
187 | Photo
188 |
189 |
190 | /photo/$value
191 |
192 |
193 | Plans
194 |
195 |
196 | /plans
197 |
198 |
199 | Tasks
200 |
201 |
202 | /tasks
203 |
204 |
205 | Tending Around
206 |
207 |
208 | /trendingAround
209 |
210 |
211 | Works With
212 |
213 |
214 | /workingWith
215 |
216 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Resource.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace MicrosoftGraphBot {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | public class Resource {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resource() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | public static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MicrosoftGraphBot.Resource", typeof(Resource).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | public static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized string similar to Contacts.
65 | ///
66 | public static string Contacts {
67 | get {
68 | return ResourceManager.GetString("Contacts", resourceCulture);
69 | }
70 | }
71 |
72 | ///
73 | /// Looks up a localized string similar to /contacts.
74 | ///
75 | public static string Contacts_Endpoint {
76 | get {
77 | return ResourceManager.GetString("Contacts_Endpoint", resourceCulture);
78 | }
79 | }
80 |
81 | ///
82 | /// Looks up a localized string similar to Conversations.
83 | ///
84 | public static string Conversations {
85 | get {
86 | return ResourceManager.GetString("Conversations", resourceCulture);
87 | }
88 | }
89 |
90 | ///
91 | /// Looks up a localized string similar to /conversations.
92 | ///
93 | public static string Conversations_Endpoint {
94 | get {
95 | return ResourceManager.GetString("Conversations_Endpoint", resourceCulture);
96 | }
97 | }
98 |
99 | ///
100 | /// Looks up a localized string similar to Direct Reports.
101 | ///
102 | public static string DirectReports {
103 | get {
104 | return ResourceManager.GetString("DirectReports", resourceCulture);
105 | }
106 | }
107 |
108 | ///
109 | /// Looks up a localized string similar to /directReports.
110 | ///
111 | public static string DirectReports_Endpoint {
112 | get {
113 | return ResourceManager.GetString("DirectReports_Endpoint", resourceCulture);
114 | }
115 | }
116 |
117 | ///
118 | /// Looks up a localized string similar to Events.
119 | ///
120 | public static string Events {
121 | get {
122 | return ResourceManager.GetString("Events", resourceCulture);
123 | }
124 | }
125 |
126 | ///
127 | /// Looks up a localized string similar to /events.
128 | ///
129 | public static string Events_Endpoint {
130 | get {
131 | return ResourceManager.GetString("Events_Endpoint", resourceCulture);
132 | }
133 | }
134 |
135 | ///
136 | /// Looks up a localized string similar to Files.
137 | ///
138 | public static string Files {
139 | get {
140 | return ResourceManager.GetString("Files", resourceCulture);
141 | }
142 | }
143 |
144 | ///
145 | /// Looks up a localized string similar to /drive/root/children.
146 | ///
147 | public static string Files_Endpoint {
148 | get {
149 | return ResourceManager.GetString("Files_Endpoint", resourceCulture);
150 | }
151 | }
152 |
153 | ///
154 | /// Looks up a localized string similar to Groups.
155 | ///
156 | public static string Groups {
157 | get {
158 | return ResourceManager.GetString("Groups", resourceCulture);
159 | }
160 | }
161 |
162 | ///
163 | /// Looks up a localized string similar to /memberOf.
164 | ///
165 | public static string Groups_Endpoint {
166 | get {
167 | return ResourceManager.GetString("Groups_Endpoint", resourceCulture);
168 | }
169 | }
170 |
171 | ///
172 | /// Looks up a localized string similar to Mail.
173 | ///
174 | public static string Mail {
175 | get {
176 | return ResourceManager.GetString("Mail", resourceCulture);
177 | }
178 | }
179 |
180 | ///
181 | /// Looks up a localized string similar to /messages.
182 | ///
183 | public static string Mail_Endpoint {
184 | get {
185 | return ResourceManager.GetString("Mail_Endpoint", resourceCulture);
186 | }
187 | }
188 |
189 | ///
190 | /// Looks up a localized string similar to Manager.
191 | ///
192 | public static string Manager {
193 | get {
194 | return ResourceManager.GetString("Manager", resourceCulture);
195 | }
196 | }
197 |
198 | ///
199 | /// Looks up a localized string similar to /manager.
200 | ///
201 | public static string Manager_Endpoint {
202 | get {
203 | return ResourceManager.GetString("Manager_Endpoint", resourceCulture);
204 | }
205 | }
206 |
207 | ///
208 | /// Looks up a localized string similar to Group Members.
209 | ///
210 | public static string Members {
211 | get {
212 | return ResourceManager.GetString("Members", resourceCulture);
213 | }
214 | }
215 |
216 | ///
217 | /// Looks up a localized string similar to /members.
218 | ///
219 | public static string Members_Endpoint {
220 | get {
221 | return ResourceManager.GetString("Members_Endpoint", resourceCulture);
222 | }
223 | }
224 |
225 | ///
226 | /// Looks up a localized string similar to Notebooks.
227 | ///
228 | public static string Notebooks {
229 | get {
230 | return ResourceManager.GetString("Notebooks", resourceCulture);
231 | }
232 | }
233 |
234 | ///
235 | /// Looks up a localized string similar to /notes/notebooks.
236 | ///
237 | public static string Notebooks_Endpoint {
238 | get {
239 | return ResourceManager.GetString("Notebooks_Endpoint", resourceCulture);
240 | }
241 | }
242 |
243 | ///
244 | /// Looks up a localized string similar to Works With (w/Groups).
245 | ///
246 | public static string People {
247 | get {
248 | return ResourceManager.GetString("People", resourceCulture);
249 | }
250 | }
251 |
252 | ///
253 | /// Looks up a localized string similar to /people.
254 | ///
255 | public static string People_Endpoint {
256 | get {
257 | return ResourceManager.GetString("People_Endpoint", resourceCulture);
258 | }
259 | }
260 |
261 | ///
262 | /// Looks up a localized string similar to Photo.
263 | ///
264 | public static string Photo {
265 | get {
266 | return ResourceManager.GetString("Photo", resourceCulture);
267 | }
268 | }
269 |
270 | ///
271 | /// Looks up a localized string similar to /photo/$value.
272 | ///
273 | public static string Photo_Endpoint {
274 | get {
275 | return ResourceManager.GetString("Photo_Endpoint", resourceCulture);
276 | }
277 | }
278 |
279 | ///
280 | /// Looks up a localized string similar to Plans.
281 | ///
282 | public static string Plans {
283 | get {
284 | return ResourceManager.GetString("Plans", resourceCulture);
285 | }
286 | }
287 |
288 | ///
289 | /// Looks up a localized string similar to /plans.
290 | ///
291 | public static string Plans_Endpoint {
292 | get {
293 | return ResourceManager.GetString("Plans_Endpoint", resourceCulture);
294 | }
295 | }
296 |
297 | ///
298 | /// Looks up a localized string similar to Tasks.
299 | ///
300 | public static string Tasks {
301 | get {
302 | return ResourceManager.GetString("Tasks", resourceCulture);
303 | }
304 | }
305 |
306 | ///
307 | /// Looks up a localized string similar to /tasks.
308 | ///
309 | public static string Tasks_Endpoint {
310 | get {
311 | return ResourceManager.GetString("Tasks_Endpoint", resourceCulture);
312 | }
313 | }
314 |
315 | ///
316 | /// Looks up a localized string similar to Tending Around.
317 | ///
318 | public static string TrendingAround {
319 | get {
320 | return ResourceManager.GetString("TrendingAround", resourceCulture);
321 | }
322 | }
323 |
324 | ///
325 | /// Looks up a localized string similar to /trendingAround.
326 | ///
327 | public static string TrendingAround_Endpoint {
328 | get {
329 | return ResourceManager.GetString("TrendingAround_Endpoint", resourceCulture);
330 | }
331 | }
332 |
333 | ///
334 | /// Looks up a localized string similar to Works With.
335 | ///
336 | public static string WorkingWith {
337 | get {
338 | return ResourceManager.GetString("WorkingWith", resourceCulture);
339 | }
340 | }
341 |
342 | ///
343 | /// Looks up a localized string similar to /workingWith.
344 | ///
345 | public static string WorkingWith_Endpoint {
346 | get {
347 | return ResourceManager.GetString("WorkingWith_Endpoint", resourceCulture);
348 | }
349 | }
350 | }
351 | }
352 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Dialog/ResourceTypes/FilesDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Net;
9 | using System.Net.Http;
10 | using System.Net.Http.Headers;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace MicrosoftGraphBot.Dialog.ResourceTypes
15 | {
16 | [Serializable]
17 | public class FilesDialog : IDialog
18 | {
19 | ///
20 | /// Called to start a dialog
21 | ///
22 | /// IDialogContext
23 | ///
24 | public async Task StartAsync(IDialogContext context)
25 | {
26 | context.Wait(MessageReceivedAsync);
27 | }
28 |
29 | ///
30 | /// Processes messages received on new thread
31 | ///
32 | /// IDialogContext
33 | /// Awaitable IMessageActivity
34 | /// Task
35 | public async Task MessageReceivedAsync(IDialogContext context, IAwaitable item)
36 | {
37 | var entity = context.ConversationData.GetDialogEntity();
38 | await processFiles(context, String.Format("https://graph.microsoft.com/v1.0/users/{0}/drive/root/children?$top=5", entity.id));
39 | }
40 |
41 | ///
42 | /// Processes a OneDrive container (root or folder)
43 | ///
44 | /// IDialogContext
45 | /// endpoint to query
46 | /// Task
47 | private async Task processFiles(IDialogContext context, string endpoint)
48 | {
49 | //save the current endpoint and retrieve the Dialog Entity
50 | context.SaveNavCurrent(endpoint);
51 | var entity = context.ConversationData.GetDialogEntity();
52 |
53 | //perform the http request
54 | HttpClient client = new HttpClient();
55 | var token = await context.GetAccessToken();
56 | JObject json = await client.MSGraphGET(token, endpoint);
57 | var files = ((JArray)json["value"]).ToFileList();
58 |
59 | //build a list of valid operations the user can take
60 | List operations = new List();
61 | foreach (var file in files)
62 | {
63 | //check if file or folder
64 | if (file.itemType == Models.ItemType.Folder)
65 | {
66 | var folderEndpoint = String.Format("https://graph.microsoft.com/v1.0/users/{0}/drive/items/{1}/children?$top=5", entity.id, file.id);
67 | operations.Add(new Models.QueryOperation() { Text = file.ToString(), Type = Models.OperationType.Folder, Endpoint = folderEndpoint });
68 | }
69 | else
70 | operations.Add(new Models.QueryOperation() { Text = file.ToString(), Type = Models.OperationType.Files, Endpoint = file.navEndpoint });
71 | }
72 |
73 | //allow users to upload into their own OneDrive
74 | if (entity.entityType == Models.EntityType.Me)
75 | operations.Add(new Models.QueryOperation() { Text = "(Upload)", Type = Models.OperationType.Upload, Endpoint = endpoint.Substring(0, endpoint.IndexOf("/children")) });
76 |
77 | //add paging for up, next, prev
78 | operations.InitializePaging(context, json);
79 |
80 | //add other operations and start over
81 | operations.Add(new Models.QueryOperation() { Text = String.Format("(Other {0} queries)", entity.ToString()), Type = Models.OperationType.ShowOperations });
82 | operations.Add(new Models.QueryOperation() { Text = "(Start over)", Type = Models.OperationType.StartOver });
83 |
84 | //Allow the user to select next path
85 | PromptDialog.Choice(context, async (IDialogContext choiceContext, IAwaitable choiceResult) =>
86 | {
87 | //CONTEXT SWITCH TO choiceContext
88 | var operation = await choiceResult;
89 |
90 | switch (operation.Type)
91 | {
92 | case Models.OperationType.Files:
93 | //save the operation for recursive call
94 | choiceContext.ConversationData.SetValue("FileOperation", operation);
95 |
96 | //the user selected a file...go to it in navstack
97 | choiceContext.NavPushItem(choiceContext.GetNavCurrent());
98 | choiceContext.NavPushLevel(); //push level to children
99 |
100 | //handle the selection
101 | await processFileSelection(choiceContext, operation);
102 | break;
103 | case Models.OperationType.Folder:
104 | choiceContext.NavPushItem(choiceContext.GetNavCurrent());
105 | choiceContext.NavPushLevel(); //push level to children
106 | await processFiles(choiceContext, operation.Endpoint);
107 | break;
108 | case Models.OperationType.Upload:
109 | //set upload context
110 | choiceContext.ConversationData.SetValue("UploadContext", operation.Endpoint);
111 | PromptDialog.Attachment(choiceContext, async (IDialogContext attachmentContext, IAwaitable> attachmentResult) =>
112 | {
113 | //CONTEXT SWITCH TO attachmentsContext
114 | var attachments = await attachmentResult;
115 |
116 | //process attachements
117 | var uploadToken = await attachmentContext.GetAccessToken();
118 | var uploadEndpoint = attachmentContext.ConversationData.Get("UploadContext");
119 | foreach (var attachment in attachments)
120 | {
121 | //parse the filename
122 | var filename = attachment.ContentUrl.Substring(attachment.ContentUrl.LastIndexOf("%5c") + 3);
123 |
124 | //perform the upload and give status along the way
125 | await attachmentContext.PostAsync(String.Format("Uploading {0}...", filename));
126 | var success = await upload(uploadToken, String.Format("{0}:/{1}:/content", uploadEndpoint, filename), attachment.ContentUrl);
127 | if (success)
128 | await attachmentContext.PostAsync(String.Format("{0} uploaded!", filename));
129 | else
130 | await attachmentContext.PostAsync(String.Format("{0} upload failed!", filename));
131 | }
132 |
133 | //re-run the current query
134 | await processFiles(attachmentContext, attachmentContext.GetNavCurrent());
135 | }, "Please select file(s) to upload.");
136 | break;
137 | case Models.OperationType.Up:
138 | //navigating up to parent...pop the level and then pop the last query on the parent
139 | choiceContext.NavPopLevel(); //pop level to parent
140 | await processFiles(choiceContext, choiceContext.NavPopItem());
141 | break;
142 | case Models.OperationType.Next:
143 | choiceContext.NavPushItem(choiceContext.GetNavCurrent());
144 | await processFiles(choiceContext, operation.Endpoint);
145 | break;
146 | case Models.OperationType.Previous:
147 | choiceContext.NavPopItem();
148 | await processFiles(choiceContext, operation.Endpoint);
149 | break;
150 | case Models.OperationType.ShowOperations:
151 | choiceContext.Done(false); //return to parent WITHOUT start over
152 | break;
153 | case Models.OperationType.StartOver:
154 | choiceContext.Done(true); //return to parent WITH start over
155 | break;
156 | }
157 | }, operations, "What would you like to see next?");
158 | }
159 |
160 | ///
161 | /// processes the selection of a file in a OneDrive container
162 | ///
163 | /// IDialogContext
164 | /// QueryOperation
165 | /// Task
166 | private async Task processFileSelection(IDialogContext context, Models.QueryOperation operation)
167 | {
168 | var token = await context.GetAccessToken();
169 | var entity = context.ConversationData.GetDialogEntity();
170 | HttpClient client = new HttpClient();
171 | var file = (await client.MSGraphGET(token, String.Format("https://graph.microsoft.com/v1.0/users/{0}{1}", entity.id, operation.Endpoint))).ToFile();
172 |
173 | //display the file and show new options
174 | var fileOperations = new List();
175 | fileOperations.Add(new Models.QueryOperation() { Text = "(Delete)", Type = Models.OperationType.Delete, Endpoint = operation.Endpoint });
176 | fileOperations.Add(new Models.QueryOperation() { Text = "(Download)", Type = Models.OperationType.Download, Endpoint = file.webUrl });
177 |
178 | //add paging for up (empty JObject will leave off next/prev
179 | fileOperations.InitializePaging(context, new JObject());
180 |
181 | //add other operations and start over
182 | fileOperations.Add(new Models.QueryOperation() { Text = String.Format("(Other {0} queries)", entity.ToString()), Type = Models.OperationType.ShowOperations });
183 | fileOperations.Add(new Models.QueryOperation() { Text = "(Start over)", Type = Models.OperationType.StartOver });
184 |
185 | //let the user choose what is next
186 | PromptDialog.Choice(context, async (IDialogContext fileContext, IAwaitable fileResult) =>
187 | {
188 | //CONTEXT SWITCH TO fileContext
189 | var subOperation = await fileResult;
190 | switch (subOperation.Type)
191 | {
192 | case Models.OperationType.Delete:
193 | PromptDialog.Confirm(fileContext, async (IDialogContext confirmContext, IAwaitable confirmResult) =>
194 | {
195 | //CONTEXT SWITCH TO confirmContext
196 | var confirm = await confirmResult;
197 | var fileOp = confirmContext.ConversationData.Get("FileOperation");
198 | if (confirm)
199 | {
200 | //delete the file
201 | HttpClient deleteClient = new HttpClient();
202 | var deleteToken = await confirmContext.GetAccessToken();
203 | var deleteEntity = confirmContext.ConversationData.GetDialogEntity();
204 | await confirmContext.PostAsync("Deleting file...");
205 | var deleteSuccess = await deleteClient.MSGraphDELETE(deleteToken, String.Format("https://graph.microsoft.com/v1.0/users/{0}{1}", deleteEntity.id, fileOp.Endpoint));
206 | if (deleteSuccess)
207 | await confirmContext.PostAsync("File deleted!");
208 | else
209 | await confirmContext.PostAsync("Delete failed!");
210 |
211 | //navigating up to parent...pop the level and then pop the last query on the parent
212 | confirmContext.NavPopLevel(); //pop level to parent
213 | await processFiles(confirmContext, confirmContext.NavPopItem());
214 | }
215 | else
216 | {
217 | //show options again
218 | await processFileSelection(confirmContext, fileOp);
219 | }
220 | }, "Are you sure you want to delete the file?");
221 | break;
222 | case Models.OperationType.Download:
223 | //display download link and then call show file options again
224 | await fileContext.PostAsync(String.Format("[{0}]({0})", subOperation.Endpoint));
225 | await processFileSelection(fileContext, fileContext.ConversationData.Get("FileOperation"));
226 | break;
227 | case Models.OperationType.Up:
228 | //navigating up to parent...pop the level and then pop the last query on the parent
229 | fileContext.NavPopLevel(); //pop level to parent
230 | await processFiles(fileContext, fileContext.NavPopItem());
231 | break;
232 | case Models.OperationType.ShowOperations:
233 | fileContext.Done(false); //return to parent WITHOUT start over
234 | break;
235 | case Models.OperationType.StartOver:
236 | fileContext.Done(true); //return to parent WITH start over
237 | break;
238 | }
239 | }, fileOperations, String.Format("{0} is {1} bytes. What would you like to see next?", file.text, file.size)); //TODO: show thumbnail???
240 | }
241 |
242 | ///
243 | /// Performs an upload of a file into a OneDrive container
244 | ///
245 | /// AccessToken string
246 | /// endpoint of container to upload into
247 | /// path of the local cached file from the upload
248 | /// bool for success
249 | private async Task upload(string token, string endpoint, string path)
250 | {
251 | HttpClient client = new HttpClient();
252 | client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
253 | client.DefaultRequestHeaders.Add("Accept", "application/json;odata.metadata=full");
254 |
255 | //read the file into a stream
256 | WebRequest readReq = WebRequest.Create(path);
257 | WebResponse readRes = readReq.GetResponse();
258 | using (var stream = readRes.GetResponseStream())
259 | {
260 | //prepare the content body
261 | var fileContent = new StreamContent(stream);
262 | fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
263 | var uploadRes = await client.PutAsync(endpoint, fileContent);
264 | return uploadRes.IsSuccessStatusCode;
265 | }
266 | }
267 | }
268 | }
269 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/MicrosoftGraphBot.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 |
8 |
9 | 2.0
10 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}
11 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
12 | Library
13 | Properties
14 | MicrosoftGraphBot
15 | MicrosoftGraphBot
16 | v4.6
17 | true
18 | 44358
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | true
29 | full
30 | false
31 | bin\
32 | DEBUG;TRACE
33 | prompt
34 | 4
35 |
36 |
37 | pdbonly
38 | true
39 | bin\
40 | TRACE
41 | prompt
42 | 4
43 |
44 |
45 |
46 | ..\packages\AuthBot.3.0.2-alpha\lib\net40\AuthBot.dll
47 | True
48 |
49 |
50 | ..\packages\Autofac.4.0.0-rc3-309\lib\net451\Autofac.dll
51 | True
52 |
53 |
54 | ..\packages\Chronic.Signed.0.3.2\lib\net40\Chronic.dll
55 | True
56 |
57 |
58 | ..\packages\Microsoft.Bot.Builder.3.0.1\lib\net46\Microsoft.Bot.Builder.dll
59 | True
60 |
61 |
62 | ..\packages\Microsoft.Bot.Builder.3.0.1\lib\net46\Microsoft.Bot.Connector.dll
63 | True
64 |
65 |
66 |
67 | ..\packages\Microsoft.Identity.Client.1.0.304142221-alpha\lib\net45\Microsoft.Identity.Client.dll
68 | True
69 |
70 |
71 | ..\packages\Microsoft.Identity.Client.1.0.304142221-alpha\lib\net45\Microsoft.Identity.Client.Platform.dll
72 | True
73 |
74 |
75 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.12.0\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll
76 | True
77 |
78 |
79 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.12.0\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll
80 | True
81 |
82 |
83 | ..\packages\Microsoft.IdentityModel.Logging.1.0.0\lib\net451\Microsoft.IdentityModel.Logging.dll
84 | True
85 |
86 |
87 | ..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.2.206221351\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll
88 | True
89 |
90 |
91 | ..\packages\Microsoft.IdentityModel.Tokens.5.0.0\lib\net451\Microsoft.IdentityModel.Tokens.dll
92 | True
93 |
94 |
95 | ..\packages\Microsoft.Rest.ClientRuntime.1.8.2\lib\net45\Microsoft.Rest.ClientRuntime.dll
96 | True
97 |
98 |
99 | ..\packages\Microsoft.Win32.Primitives.4.0.1\lib\net46\Microsoft.Win32.Primitives.dll
100 | True
101 |
102 |
103 | ..\packages\Microsoft.WindowsAzure.ConfigurationManager.3.2.1\lib\net40\Microsoft.WindowsAzure.Configuration.dll
104 | True
105 |
106 |
107 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
108 | True
109 |
110 |
111 |
112 |
113 | ..\packages\System.Diagnostics.DiagnosticSource.4.0.0\lib\net46\System.Diagnostics.DiagnosticSource.dll
114 | True
115 |
116 |
117 | ..\packages\System.IdentityModel.Tokens.Jwt.4.0.2.206221351\lib\net45\System.IdentityModel.Tokens.Jwt.dll
118 | True
119 |
120 |
121 |
122 |
123 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
124 | True
125 |
126 |
127 |
128 |
129 | ..\packages\System.Runtime.Serialization.Primitives.4.1.1\lib\net46\System.Runtime.Serialization.Primitives.dll
130 | True
131 |
132 |
133 | ..\packages\System.Security.Cryptography.Algorithms.4.2.0\lib\net46\System.Security.Cryptography.Algorithms.dll
134 | True
135 |
136 |
137 | ..\packages\System.Security.Cryptography.Encoding.4.0.0\lib\net46\System.Security.Cryptography.Encoding.dll
138 | True
139 |
140 |
141 | ..\packages\System.Security.Cryptography.Primitives.4.0.0\lib\net46\System.Security.Cryptography.Primitives.dll
142 | True
143 |
144 |
145 | ..\packages\System.Security.Cryptography.X509Certificates.4.1.0\lib\net46\System.Security.Cryptography.X509Certificates.dll
146 | True
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
159 | True
160 |
161 |
162 | ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll
163 | True
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 | Designer
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 | Global.asax
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 | True
214 | True
215 | Resource.resx
216 |
217 |
218 |
219 |
220 | Designer
221 |
222 |
223 | Web.config
224 |
225 |
226 | Web.config
227 |
228 |
229 |
230 |
231 | PublicResXFileCodeGenerator
232 | Resource.Designer.cs
233 |
234 |
235 |
236 |
237 | 10.0
238 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
239 |
240 |
241 | true
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 | True
251 | True
252 | 3978
253 | /
254 | https://localhost:44300/
255 | True
256 | https://localhost:44300/
257 | False
258 | False
259 |
260 |
261 | False
262 |
263 |
264 |
265 |
266 |
273 |
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Dialog/ResourceTypes/TasksDialog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net.Http;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 | using Microsoft.Bot.Builder.Dialogs;
8 | using Microsoft.Bot.Connector;
9 | using MicrosoftGraphBot.Models;
10 | using Newtonsoft.Json.Linq;
11 |
12 | namespace MicrosoftGraphBot.Dialog.ResourceTypes
13 | {
14 | [Serializable]
15 | public class TasksDialog : IDialog
16 | {
17 | private const int PageSize = 5;
18 |
19 | public TasksDialog()
20 | {
21 |
22 | }
23 |
24 | ///
25 | /// Called to start a dialog.
26 | ///
27 | /// IDialogContext
28 | ///
29 | #pragma warning disable 1998
30 | public async Task StartAsync(IDialogContext context)
31 | #pragma warning restore 1998
32 | {
33 | context.Wait(ShowOperationsAsync);
34 | }
35 |
36 | ///
37 | /// Processes messages received on new thread.
38 | ///
39 | /// IDialogContext
40 | /// Awaitable IMessageActivity
41 | /// Task
42 | public async Task ShowOperationsAsync(IDialogContext context,
43 | IAwaitable item = null)
44 | {
45 | await ShowOperationsAsync(context, 0);
46 | }
47 |
48 | ///
49 | /// Processes messages received on new thread.
50 | ///
51 | /// IDialogContext
52 | /// int
53 | /// Task
54 | public async Task ShowOperationsAsync(IDialogContext context, int page)
55 | {
56 | // OData does currently not work well on /tasks (bug). Implementing a
57 | // custom navigation model.
58 |
59 | // Save the current page.
60 | context.ConversationData.SetValue("Page", page);
61 |
62 | // Get needed data for the HTTP request.
63 | var entity = context.ConversationData.GetDialogEntity();
64 | var requestUrl = (entity.entityType == EntityType.Me || entity.entityType == EntityType.User)
65 | ? $"https://graph.microsoft.com/beta/users/{entity.id}/tasks"
66 | : $"https://graph.microsoft.com/beta/plans/{entity.id}/tasks";
67 | var httpClient = new HttpClient();
68 | var accessToken = await context.GetAccessToken();
69 |
70 | // Perform the HTTP request.
71 | var response = await httpClient.MSGraphGET(accessToken, requestUrl);
72 | var allTasks = ((JArray)response["value"]).ToTasksList();
73 |
74 | // Remove completed tasks.
75 | allTasks = new List(allTasks.Where(t => t.PercentComplete < 100));
76 |
77 | // Not getting OData to work on /tasks, limiting in client instead.
78 | var tasks = new List(allTasks
79 | .OrderBy(t => t.CreatedDateTime)
80 | .Skip(page * PageSize)
81 | .Take(PageSize));
82 |
83 | // TODO: Aggregate above filtering to single method. Current setup is for clarity.
84 |
85 | // Create tasks operations.
86 | var operations = new List();
87 | operations.AddRange(tasks.Select(t =>
88 | {
89 | // Create the text (trimmed if needed).
90 | var text = t.text.Length <= 20
91 | ? t.text
92 | : new string(t.text.Take(20).ToArray()).Trim() + "...";
93 | return new QueryOperation
94 | {
95 | Text = text,
96 | Type = OperationType.Tasks,
97 | Endpoint = t.navEndpoint,
98 | ContextObject = t
99 | };
100 | }));
101 |
102 | // Create new task operation.
103 | operations.Add(new QueryOperation
104 | {
105 | Text = "(Create task)",
106 | Type = OperationType.Create,
107 | Endpoint = requestUrl
108 | });
109 |
110 | // Create previous page operation.
111 | if (page > 0)
112 | {
113 | operations.Add(new QueryOperation
114 | {
115 | Text = "(Previous page)",
116 | Type = OperationType.Previous,
117 | Endpoint = requestUrl
118 | });
119 | }
120 |
121 | // Create next page operation.
122 | if ((page + 1) * PageSize < allTasks.Count)
123 | {
124 | operations.Add(new QueryOperation
125 | {
126 | Text = "(Next page)",
127 | Type = OperationType.Next,
128 | Endpoint = requestUrl
129 | });
130 | }
131 |
132 | // Create other operations.
133 | var me = context.ConversationData.Me();
134 | operations.Add(new QueryOperation
135 | {
136 | Text = $"(Other {me} queries)",
137 | Type = OperationType.ShowOperations
138 | });
139 |
140 | // Create start over operation.
141 | operations.Add(new QueryOperation
142 | {
143 | Text = "(Start over)",
144 | Type = OperationType.StartOver
145 | });
146 |
147 | // Allow user to select the operation.
148 | PromptDialog.Choice(context, OnOperationsChoiceDialogResume, operations,
149 | "What would you like to see next?");
150 | }
151 |
152 | private async Task OnOperationsChoiceDialogResume(IDialogContext context,
153 | IAwaitable result)
154 | {
155 | var page = context.ConversationData.Get("Page");
156 |
157 | // Get choice result.
158 | var operation = await result;
159 | switch (operation.Type)
160 | {
161 | case OperationType.Tasks:
162 | // Save the operation for recursive call.
163 | context.ConversationData.SetValue("TaskOperation", operation);
164 |
165 | // Handle the selection.
166 | await ShowTaskOperationsAsync(context, operation);
167 | break;
168 | case OperationType.Create:
169 | // Get the dialog entity and see if we can
170 | // skip a step (in case of plan).
171 | var dialogEntity = context.ConversationData.GetDialogEntity();
172 | if (dialogEntity.entityType == EntityType.Me || dialogEntity.entityType == EntityType.User)
173 | {
174 | await context.Forward(new PlanLookupDialog(), OnPlanLookupDialogResume,
175 | new Plan(), CancellationToken.None);
176 | }
177 | else
178 | {
179 | // Save the plan.
180 | context.ConversationData.SetValue("Plan", dialogEntity);
181 |
182 | // Get a bucket.
183 | await context.Forward(new BucketLookupDialog(), OnBucketLookupDialogResume,
184 | new Bucket(), CancellationToken.None);
185 | }
186 | break;
187 | case OperationType.Next:
188 | // Move to the new page.
189 | await ShowOperationsAsync(context, page + 1);
190 | break;
191 | case OperationType.Previous:
192 | // Move to the previous page.
193 | await ShowOperationsAsync(context, page - 1);
194 | break;
195 | case OperationType.ShowOperations:
196 | // Reset the dialog entity.
197 | context.ConversationData.SaveDialogEntity(new BaseEntity(
198 | context.ConversationData.Me(), EntityType.Me));
199 | context.Done(false);
200 | break;
201 | case OperationType.StartOver:
202 | // Reset the dialog entity.
203 | context.ConversationData.SaveDialogEntity(new BaseEntity(
204 | context.ConversationData.Me(), EntityType.Me));
205 | context.Done(true);
206 | break;
207 | }
208 | }
209 |
210 | #region Create Task Operation
211 |
212 | private async Task OnPlanLookupDialogResume(IDialogContext context,
213 | IAwaitable result)
214 | {
215 | // Save the plan.
216 | var plan = await result;
217 | context.ConversationData.SetValue("Plan", plan);
218 |
219 | // Get a bucket.
220 | await context.Forward(new BucketLookupDialog(), OnBucketLookupDialogResume, new Bucket(),
221 | CancellationToken.None);
222 | }
223 |
224 | private async Task OnBucketLookupDialogResume(IDialogContext context,
225 | IAwaitable result)
226 | {
227 | // Save the bucket.
228 | var bucket = await result;
229 | context.ConversationData.SetValue("Bucket", bucket);
230 |
231 | // Get the task.
232 | PromptDialog.Text(context, OnCreateTaskDialogResume,
233 | "What is the task that you would like to create?");
234 | }
235 |
236 | private async Task OnCreateTaskDialogResume(IDialogContext context,
237 | IAwaitable result)
238 | {
239 | // Get data needed to create a new task.
240 | var text = await result;
241 | var user = context.ConversationData.Get("Me");
242 | var plan = context.ConversationData.Get("Plan");
243 | var bucket = context.ConversationData.Get("Bucket");
244 |
245 | // Create the task data.
246 | var task = new PlanTask
247 | {
248 | AssignedTo = user.id,
249 | PlanId = plan.Id,
250 | BucketId = bucket.Id,
251 | Title = text
252 | };
253 |
254 | var httpClient = new HttpClient();
255 | var accessToken = await context.GetAccessToken();
256 |
257 | // Create the task.
258 | await context.PostAsync("Creating task...");
259 | var response = await httpClient.MSGraphPOST(accessToken,
260 | "https://graph.microsoft.com/beta/tasks", task);
261 | await context.PostAsync(response ? "Task created!" : "Creation failed!");
262 |
263 | // Clear data.
264 | context.ConversationData.RemoveValue("Plan");
265 | context.ConversationData.RemoveValue("Bucket");
266 |
267 | // Show operations.
268 | await ShowOperationsAsync(context);
269 | }
270 |
271 | #endregion
272 |
273 | #region Task Operations
274 |
275 | #pragma warning disable 1998
276 | private async Task ShowTaskOperationsAsync(IDialogContext context, QueryOperation operation)
277 | #pragma warning restore 1998
278 | {
279 | // Get the task.
280 | var task = operation.GetContextObjectAs();
281 |
282 | // Create task operations.
283 | var operations = new List();
284 |
285 | // Create in progress operation.
286 | if (task.PercentComplete == 0)
287 | {
288 | operations.Add(new QueryOperation
289 | {
290 | Text = "(In progress)",
291 | Type = OperationType.InProgress,
292 | Endpoint = operation.Endpoint,
293 | ContextObject = task
294 | });
295 | }
296 |
297 | // Create complete operation.
298 | if (task.PercentComplete != 100)
299 | {
300 | operations.Add(new QueryOperation
301 | {
302 | Text = "(Complete)",
303 | Type = OperationType.Complete,
304 | Endpoint = operation.Endpoint,
305 | ContextObject = task
306 | });
307 | }
308 |
309 | // Create delete operation.
310 | operations.Add(new QueryOperation
311 | {
312 | Text = "(Delete)",
313 | Type = OperationType.Delete,
314 | Endpoint = operation.Endpoint,
315 | ContextObject = task
316 | });
317 |
318 | // Create up operation.
319 | operations.Add(new QueryOperation
320 | {
321 | Text = "(Up)",
322 | Type = OperationType.Up,
323 | Endpoint = operation.Endpoint
324 | });
325 |
326 | // Create other operations.
327 | var me = context.ConversationData.Me();
328 | operations.Add(new QueryOperation
329 | {
330 | Text = $"(Other {me} queries)",
331 | Type = OperationType.ShowOperations
332 | });
333 |
334 | // Create start over operation.
335 | operations.Add(new QueryOperation
336 | {
337 | Text = "(Start over)",
338 | Type = OperationType.StartOver
339 | });
340 |
341 | // Create prompt text.
342 | var promptText = $"Task \"{task.Title}\" is ";
343 |
344 | // Set completion status.
345 | switch (task.PercentComplete)
346 | {
347 | case 0:
348 | promptText += "not started";
349 | break;
350 | case 100:
351 | promptText += "completed";
352 | break;
353 | default:
354 | promptText += "in progress";
355 | break;
356 | }
357 | promptText += ". What would you like to do next?";
358 |
359 | // Allow user to select the operation.
360 | PromptDialog.Choice(context, OnTaskOperationsChoiceDialogResume, operations, promptText);
361 | }
362 |
363 | private async Task OnTaskOperationsChoiceDialogResume(IDialogContext context,
364 | IAwaitable result)
365 | {
366 | // Get choice result.
367 | switch ((await result).Type)
368 | {
369 | case OperationType.InProgress:
370 | PromptDialog.Confirm(context, OnTaskInProgressDialogResumeAsync,
371 | "Are you sure that you want to flag this task as in progress?");
372 | break;
373 | case OperationType.Complete:
374 | PromptDialog.Confirm(context, OnTaskCompleteDialogResumeAsync,
375 | "Are you sure that you want to flag this task as completed?");
376 | break;
377 | case OperationType.Delete:
378 | PromptDialog.Confirm(context, OnDeleteTaskDialogResume,
379 | "Are you sure that you want to delete the task?");
380 | break;
381 | case OperationType.Up:
382 | var page = context.ConversationData.Get("Page");
383 | await ShowOperationsAsync(context, page);
384 | break;
385 | case OperationType.ShowOperations:
386 | // Reset the dialog entity.
387 | context.ConversationData.SaveDialogEntity(new BaseEntity(
388 | context.ConversationData.Me(), EntityType.Me));
389 | context.Done(false);
390 | break;
391 | case OperationType.StartOver:
392 | // Reset the dialog entity.
393 | context.ConversationData.SaveDialogEntity(new BaseEntity(
394 | context.ConversationData.Me(), EntityType.Me));
395 | context.Done(true);
396 | break;
397 | }
398 | }
399 |
400 | #endregion
401 |
402 | #region Change Task Progress Operations
403 |
404 | private async Task OnTaskInProgressDialogResumeAsync(IDialogContext context,
405 | IAwaitable result)
406 | {
407 | await UpdateTaskProgressAsync(context, result, 50);
408 | }
409 |
410 | private async Task OnTaskCompleteDialogResumeAsync(IDialogContext context,
411 | IAwaitable result)
412 | {
413 | await UpdateTaskProgressAsync(context, result, 100);
414 | }
415 |
416 | private async Task UpdateTaskProgressAsync(IDialogContext context,
417 | IAwaitable result, int percentComplete)
418 | {
419 | var confirm = await result;
420 | var operation = context.ConversationData.Get("TaskOperation");
421 |
422 | // Get the task.
423 | var task = operation.GetContextObjectAs();
424 |
425 | if (confirm)
426 | {
427 | var httpClient = new HttpClient();
428 | var accessToken = await context.GetAccessToken();
429 |
430 | // Update the task.
431 | await context.PostAsync("Updating task...");
432 | var response = await httpClient.MSGraphPATCH(accessToken,
433 | $"https://graph.microsoft.com/beta/{operation.Endpoint}", new
434 | {
435 | PercentComplete = percentComplete
436 | }, task.ETag);
437 | await context.PostAsync(response ? "Task updated!" : "Update failed!");
438 |
439 | // Show operations.
440 | await ShowOperationsAsync(context);
441 | }
442 | else
443 | {
444 | // Show task operations.
445 | await ShowTaskOperationsAsync(context, operation);
446 | }
447 | }
448 |
449 | #endregion
450 |
451 | #region Task Delete Operation
452 |
453 | private async Task OnDeleteTaskDialogResume(IDialogContext context,
454 | IAwaitable result)
455 | {
456 | var confirm = await result;
457 | var operation = context.ConversationData.Get("TaskOperation");
458 |
459 | // Get the task.
460 | var task = operation.GetContextObjectAs();
461 |
462 | if (confirm)
463 | {
464 | var httpClient = new HttpClient();
465 | var accessToken = await context.GetAccessToken();
466 |
467 | // Delete the task.
468 | await context.PostAsync("Deleting task...");
469 | var response = await httpClient.MSGraphDELETE(accessToken,
470 | $"https://graph.microsoft.com/beta/{operation.Endpoint}", task.ETag);
471 | await context.PostAsync(response ? "Task deleted!" : "Delete failed!");
472 |
473 | // Navigating up to parent, pop the level and then pop the
474 | // last query on the parent.
475 | context.NavPopLevel();
476 | context.NavPopItem();
477 | await ShowOperationsAsync(context);
478 | }
479 | else
480 | {
481 | // Show task operations.
482 | await ShowTaskOperationsAsync(context, operation);
483 | }
484 | }
485 |
486 | #endregion
487 | }
488 | }
--------------------------------------------------------------------------------
/MicrosoftGraphBot/Extensions.cs:
--------------------------------------------------------------------------------
1 | using AuthBot;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using Microsoft.Bot.Builder.Luis.Models;
4 | using Microsoft.Bot.Connector;
5 | using MicrosoftGraphBot.Dialog;
6 | using MicrosoftGraphBot.Models;
7 | using Newtonsoft.Json.Linq;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Net.Http;
12 | using System.Net.Http.Headers;
13 | using System.Reflection;
14 | using System.Resources;
15 | using System.Text;
16 | using System.Threading.Tasks;
17 | using Newtonsoft.Json;
18 |
19 | namespace MicrosoftGraphBot
20 | {
21 | public static class Extensions
22 | {
23 | ///
24 | /// Simplifies the query for a token given our resource will always be the Microsoft Graph
25 | ///
26 | /// IBotContext
27 | /// AccessToken string
28 | public static async Task GetAccessToken(this IBotContext context)
29 | {
30 | return await context.GetAccessToken("https://graph.microsoft.com");
31 | }
32 |
33 | ///
34 | /// Converts a list of Graph ResourceType enums to a list of QueryOperations
35 | ///
36 | /// List of ResourceType enums
37 | /// List of QueryOperation objects
38 | public static List ToQueryOperations(this List resourceTypes)
39 | {
40 | List operations = new List();
41 | foreach (var op in resourceTypes)
42 | {
43 | operations.Add(new QueryOperation()
44 | {
45 | Type = op,
46 | Text = Resource.ResourceManager.GetString(op.ToString()),
47 | Endpoint = Resource.ResourceManager.GetString(String.Format("{0}_Endpoint", op.ToString()))
48 | });
49 | }
50 | return operations;
51 | }
52 |
53 | ///
54 | /// Saves the dialog entity (who queries are being performed for)
55 | ///
56 | /// IBotDataBag
57 | /// BaseEntity
58 | public static void SaveDialogEntity(this IBotDataBag conversationData, BaseEntity entity)
59 | {
60 | conversationData.SetValue("DialogEntity", entity);
61 | }
62 |
63 | ///
64 | /// Gets the dialog entity (who queries are being performed for)
65 | ///
66 | /// IBotDataBag
67 | /// BaseEntity
68 | public static BaseEntity GetDialogEntity(this IBotDataBag conversationData)
69 | {
70 | return conversationData.Get("DialogEntity");
71 | }
72 |
73 | ///
74 | /// Initializes the ConversationData by clearing it from the last thread
75 | ///
76 | /// IDialogContext
77 | /// LuisResult
78 | public static async Task Initialize(this IDialogContext context)
79 | {
80 | //reset the conversation data for new thead
81 | context.ConversationData.RemoveValue("DialogEntity");
82 |
83 | //try to initialize me
84 | User me = null;
85 | if (!context.ConversationData.TryGetValue("Me", out me))
86 | {
87 | var token = await context.GetAccessToken();
88 | me = await User.Me(token);
89 | context.ConversationData.SetValue("Me", me);
90 | }
91 | }
92 |
93 | ///
94 | /// resets cached data for a new operation
95 | ///
96 | /// IDialogContext
97 | public static void NewOperation(this IDialogContext context)
98 | {
99 | //initialize the NavPagingStack...provides two-dimensional breadcrumb
100 | //First list is the level...second is the paging
101 | //ex: level = folder; paging = paging for files in that folder
102 | //ex: level = person; paging = paged list of direct reports for a person
103 | var navStack = new List>();
104 | navStack.Add(new List());
105 | context.ConversationData.SetValue>>("NavStack", navStack);
106 | context.ConversationData.RemoveValue("NavCurrent");
107 | }
108 |
109 | ///
110 | /// Gets me
111 | ///
112 | /// IBotDataBag
113 | /// User
114 | public static User Me(this IBotDataBag conversationData)
115 | {
116 | return conversationData.Get("Me");
117 | }
118 |
119 | ///
120 | /// checks if a specific user is ME
121 | ///
122 | /// User to check against
123 | /// IDialogContext
124 | /// bool
125 | public static bool IsMe(this User user, IDialogContext context)
126 | {
127 | var me = context.ConversationData.Get("Me");
128 | return me.id.Equals(user.id, StringComparison.CurrentCultureIgnoreCase);
129 | }
130 |
131 | //START - THESE ARE ALL PAGING UTILITIES
132 | public static void SaveNavCurrent(this IDialogContext context, string endpoint)
133 | {
134 | context.ConversationData.SetValue("NavCurrent", endpoint);
135 | }
136 |
137 | public static string GetNavCurrent(this IDialogContext context)
138 | {
139 | return context.ConversationData.Get("NavCurrent");
140 | }
141 |
142 | public static void NavPushLevel(this IDialogContext context)
143 | {
144 | //implemented as a list and not a real stack because serialization was corrupting order
145 | var stack = context.ConversationData.Get>>("NavStack");
146 | stack.Insert(0, new List());
147 | context.ConversationData.SetValue>>("NavStack", stack);
148 | }
149 |
150 | public static void NavPushItem(this IDialogContext context, string endpoint)
151 | {
152 | //implemented as a list and not a real stack because serialization was corrupting order
153 | var stack = context.ConversationData.Get>>("NavStack");
154 | stack[0].Insert(0, endpoint);
155 | context.ConversationData.SetValue>>("NavStack", stack);
156 | }
157 |
158 | public static void NavPopLevel(this IDialogContext context)
159 | {
160 | //implemented as a list and not a real stack because serialization was corrupting order
161 | var stack = context.ConversationData.Get>>("NavStack");
162 | stack.RemoveAt(0);
163 | context.ConversationData.SetValue>>("NavStack", stack);
164 | }
165 |
166 | public static string NavPopItem(this IDialogContext context)
167 | {
168 | //implemented as a list and not a real stack because serialization was corrupting order
169 | var stack = context.ConversationData.Get>>("NavStack");
170 | var path = stack[0][0];
171 | stack[0].RemoveAt(0);
172 | context.ConversationData.SetValue>>("NavStack", stack);
173 | return path;
174 | }
175 |
176 | public static string NavPeekLevel(this IDialogContext context)
177 | {
178 | //implemented as a list and not a real stack because serialization was corrupting order
179 | var stack = context.ConversationData.Get>>("NavStack");
180 | if (stack.Count > 1)
181 | return stack[1][0];
182 | else
183 | return null;
184 | }
185 |
186 | public static string NavPeekItem(this IDialogContext context)
187 | {
188 | //implemented as a list and not a real stack because serialization was corrupting order
189 | var stack = context.ConversationData.Get>>("NavStack");
190 | if (stack[0].Count > 0)
191 | return stack[0][0];
192 | else
193 | return null;
194 | }
195 |
196 | public static void InitializePaging(this List operations, IDialogContext context, JObject json)
197 | {
198 | //add next link to the end
199 | if (json["@odata.nextLink"] != null)
200 | {
201 | var next = json.Value("@odata.nextLink");
202 | operations.Add(new QueryOperation() {Text = "(Next page)", Type = OperationType.Next, Endpoint = next});
203 | }
204 |
205 | //add previous to the front
206 | if (!String.IsNullOrEmpty(context.NavPeekItem()))
207 | {
208 | var prev = context.NavPeekItem();
209 |
210 | operations.Add(new QueryOperation()
211 | {
212 | Text = "(Prev page)",
213 | Type = OperationType.Previous,
214 | Endpoint = prev
215 | });
216 | }
217 |
218 | //add parent nav up
219 | if (!String.IsNullOrEmpty(context.NavPeekLevel()))
220 | operations.Add(new QueryOperation()
221 | {
222 | Text = "(Up to parent)",
223 | Type = OperationType.Up,
224 | Endpoint = context.NavPeekLevel()
225 | });
226 | }
227 |
228 | //START - THESE ARE ALL PAGING UTILITIES
229 |
230 |
231 | ///
232 | /// Performs a simple HTTP GET against the MSGraph given a token and endpoint
233 | ///
234 | /// HttpClient
235 | /// Access token string
236 | /// endpoint uri to perform GET on
237 | /// JObject
238 | public static async Task MSGraphGET(this HttpClient client, string token, string endpoint)
239 | {
240 | client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
241 | client.DefaultRequestHeaders.Add("Accept", "application/json");
242 | using (var response = await client.GetAsync(endpoint))
243 | {
244 | if (response.IsSuccessStatusCode)
245 | {
246 | var json = await response.Content.ReadAsStringAsync();
247 | return JObject.Parse(json);
248 | }
249 | else
250 | return null;
251 | }
252 | }
253 |
254 | ///
255 | /// Performs a HTTP DELETE against the MSGraph given an access token and request URI
256 | ///
257 | /// HttpClient
258 | /// Access token string
259 | /// Request URI to perform DELETE on
260 | /// Entity Tag header for Microsoft Graph item to perform DELETE on
261 | /// boolean for success
262 | public static async Task MSGraphDELETE(this HttpClient httpClient, string accessToken,
263 | string requestUri, string weakETag = null)
264 | {
265 | // Set Authorization and Accept header.
266 | httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
267 | httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
268 |
269 | // Set (weak) If-Match header.
270 | if (weakETag != null)
271 | {
272 | var headers = httpClient.DefaultRequestHeaders;
273 | headers.IfMatch.Add(new EntityTagHeaderValue(weakETag.Substring(2,
274 | weakETag.Length - 2), true));
275 | }
276 |
277 | using (var response = await httpClient.DeleteAsync(requestUri))
278 | {
279 | return response.IsSuccessStatusCode;
280 | }
281 | }
282 |
283 | ///
284 | /// Performs a HTTP POST against the MSGraph given an access token and request URI
285 | ///
286 | /// HttpClient
287 | /// Access token string
288 | /// Request uri to perform POST on
289 | /// Request body data for the request
290 | /// Entity Tag header for Microsoft Graph item to perform POST on
291 | /// boolean for success
292 | public static async Task MSGraphPOST(this HttpClient httpClient, string accessToken,
293 | string requestUri, T data, string weakETag = null) where T : class
294 | {
295 | // Set Authorization and Accept header.
296 | httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
297 | httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
298 |
299 | // Set If-Match header.
300 | if (weakETag != null)
301 | {
302 | var headers = httpClient.DefaultRequestHeaders;
303 | headers.IfMatch.Add(new EntityTagHeaderValue(weakETag.Substring(2,
304 | weakETag.Length - 2), true));
305 | }
306 |
307 | // Create data.
308 | var json = JsonConvert.SerializeObject(data);
309 | var content = new StringContent(json, Encoding.UTF8, "application/json");
310 | using (var response = await httpClient.PostAsync(requestUri, content))
311 | {
312 | return response.IsSuccessStatusCode;
313 | }
314 | }
315 |
316 | ///
317 | /// Performs a HTTP PATCH against the MSGraph given an access token and request URI
318 | ///
319 | /// HttpClient
320 | /// Access token string
321 | /// Request uri to perform PATCH on
322 | /// Request body data for the request
323 | /// Entity Tag header for Microsoft Graph item to perform PATCH on
324 | /// boolean for success
325 | public static async Task MSGraphPATCH(this HttpClient httpClient, string accessToken,
326 | string requestUri, T data, string weakETag = null) where T : class
327 | {
328 | // Set Authorization and Accept header.
329 | httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
330 | httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
331 |
332 | // Set If-Match header.
333 | if (weakETag != null)
334 | {
335 | var headers = httpClient.DefaultRequestHeaders;
336 | headers.IfMatch.Add(new EntityTagHeaderValue(weakETag.Substring(2,
337 | weakETag.Length - 2), true));
338 | }
339 |
340 | using (var response = await httpClient.PatchAsJsonAsync(requestUri, data))
341 | {
342 | return response.IsSuccessStatusCode;
343 | }
344 | }
345 |
346 | ///
347 | /// Implements the PATCH HTTP Method on the HttpClient.
348 | ///
349 | /// HttpClient
350 | /// Uri
351 | /// T
352 | /// HttpResponseMessage
353 | public static Task PatchAsJsonAsync(this HttpClient client,
354 | string requestUri, T value) where T : class
355 | {
356 | var request = new HttpRequestMessage(new HttpMethod("PATCH"), requestUri)
357 | {
358 | Content = new StringContent(JsonConvert.SerializeObject(value),
359 | Encoding.UTF8, "application/json")
360 | };
361 | return client.SendAsync(request);
362 | }
363 |
364 |
365 | ///
366 | /// Below are extensions to parse JSON.NET objects to strongly-typed graph objects
367 | ///
368 |
369 | ///
370 | /// Parses JArray to generic List of File objects
371 | ///
372 | /// JArray
373 | /// List of File objects
374 | public static List ToFileList(this JArray array)
375 | {
376 | List files = new List();
377 | foreach (var item in array)
378 | files.Add(item.ToFile());
379 | return files;
380 | }
381 |
382 | ///
383 | /// Parses JToken to File object
384 | ///
385 | /// JToken
386 | /// File object
387 | public static File ToFile(this JToken obj)
388 | {
389 | File f = null;
390 | if (obj != null)
391 | {
392 | f = new File()
393 | {
394 | id = obj.Value("id"),
395 | text = obj.Value("name"),
396 | size = obj.Value("size"),
397 | webUrl = obj.Value("webUrl"),
398 | itemType = (obj["folder"] != null) ? ItemType.Folder : ItemType.File,
399 | navEndpoint = String.Format("/drive/items/{0}", obj.Value("id"))
400 |
401 | };
402 | }
403 |
404 | return f;
405 | }
406 |
407 |
408 | ///
409 | /// Parses JArray to generic List of File objects
410 | ///
411 | /// JArray
412 | /// List of Mail objects
413 | public static List ToMailList(this JArray array)
414 | {
415 | List messages = new List();
416 | foreach (var item in array)
417 | messages.Add(item.ToMail());
418 | return messages;
419 | }
420 |
421 | ///
422 | /// Parses JToken to Mail object
423 | ///
424 | /// JToken
425 | /// Mail object
426 | public static Mail ToMail(this JToken obj)
427 | {
428 | Mail m = null;
429 | if (obj != null)
430 | {
431 | m = new Mail()
432 | {
433 | id = obj.Value("id"),
434 | text = obj.Value("subject"),
435 | isRead = obj.Value("isRead"),
436 | senderName = obj.SelectToken("sender.emailAddress").Value("name"),
437 | senderEmail = obj.SelectToken("sender.emailAddress").Value("address"),
438 | importance = obj.Value("importance"),
439 | sentDate = obj.Value("sentDateTime"),
440 | itemType = ItemType.Mail
441 | };
442 | }
443 |
444 | return m;
445 | }
446 |
447 |
448 | ///
449 | /// Parses JArray to generic List of User objects
450 | ///
451 | /// JArray
452 | /// List of User objects
453 | public static List ToUserList(this JArray array)
454 | {
455 | List users = new List();
456 | foreach (var item in array)
457 | users.Add(item.ToUser());
458 | return users;
459 | }
460 |
461 | ///
462 | /// Parses JToken to User object
463 | ///
464 | /// JToken
465 | /// User object
466 | public static User ToUser(this JToken obj)
467 | {
468 | User u = null;
469 | if (obj != null)
470 | {
471 | u = new User()
472 | {
473 | id = obj.Value("id"),
474 | text = obj.Value("displayName"),
475 | givenName = obj.Value("givenName"),
476 | surname = obj.Value("surname"),
477 | jobTitle = obj.Value("jobTitle"),
478 | mail = obj.Value("mail"),
479 | userPrincipalName = obj.Value("userPrincipalName"),
480 | mobilePhone = obj.Value("mobilePhone"),
481 | officeLocation = obj.Value("officeLocation")
482 | };
483 | }
484 |
485 | return u;
486 | }
487 |
488 |
489 | ///
490 | /// Parses JArray to generic List of Group objects
491 | ///
492 | /// JArray
493 | /// List of Group objects
494 | public static List ToGroupList(this JArray array)
495 | {
496 | List groups = new List();
497 | foreach (var item in array)
498 | groups.Add(item.ToGroup());
499 | return groups;
500 | }
501 |
502 | ///
503 | /// Parses JToken to User object
504 | ///
505 | /// JToken
506 | /// User object
507 | public static Group ToGroup(this JToken obj)
508 | {
509 | Group g = null;
510 | if (obj != null)
511 | {
512 | g = new Group()
513 | {
514 | id = obj.Value("id"),
515 | text = obj.Value("displayName"),
516 | description = obj.Value("description"),
517 | mail = obj.Value("mail"),
518 | itemType = ItemType.Group,
519 | visibility = obj.Value("visibility")
520 | };
521 | }
522 |
523 | return g;
524 | }
525 |
526 | ///
527 | /// Parses JArray to generic List of Plan objects
528 | ///
529 | /// JArray
530 | /// List of Plan objects
531 | public static List ToPlanList(this JArray array)
532 | {
533 | return array.Select(item => item.ToPlan()).ToList();
534 | }
535 |
536 | ///
537 | /// Parses JToken to Plan object
538 | ///
539 | /// JToken
540 | /// Plan object
541 | public static Plan ToPlan(this JToken token)
542 | {
543 | return token.ToObject();
544 | }
545 |
546 | ///
547 | /// Parses JArray to generic List of Bucket objects
548 | ///
549 | /// JArray
550 | /// List of Bucket objects
551 | public static List ToBucketList(this JArray array)
552 | {
553 | return array.Select(item => item.ToBucket()).ToList();
554 | }
555 |
556 | ///
557 | /// Parses JToken to Bucket object
558 | ///
559 | /// JToken
560 | /// Bucket object
561 | public static Bucket ToBucket(this JToken token)
562 | {
563 | return token.ToObject();
564 | }
565 |
566 | ///
567 | /// Parses JArray to generic List of Task objects
568 | ///
569 | /// JArray
570 | /// List of Task objects
571 | public static List ToTasksList(this JArray array)
572 | {
573 | return array.Select(item => item.ToTask()).ToList();
574 | }
575 |
576 | ///
577 | /// Parses JToken to Task object
578 | ///
579 | /// JToken
580 | /// Task object
581 | public static PlanTask ToTask(this JToken token)
582 | {
583 | return token.ToObject();
584 | }
585 | }
586 | }
587 |
--------------------------------------------------------------------------------