├── source ├── Views │ ├── _ViewStart.cshtml │ ├── Home │ │ ├── About.cshtml │ │ └── Graph.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ ├── _ResultsTable.cshtml │ │ ├── _LoginPartial.cshtml │ │ ├── _ResultsPartial.cshtml │ │ └── _Layout.cshtml │ ├── Web.config │ └── MyExtensionMethods.cs ├── favicon.ico ├── Global.asax ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── Areas │ └── HelpPage │ │ ├── Views │ │ ├── Help │ │ │ ├── DisplayTemplates │ │ │ │ ├── ImageSample.cshtml │ │ │ │ ├── TextSample.cshtml │ │ │ │ ├── SimpleTypeModelDescription.cshtml │ │ │ │ ├── ComplexTypeModelDescription.cshtml │ │ │ │ ├── CollectionModelDescription.cshtml │ │ │ │ ├── InvalidSample.cshtml │ │ │ │ ├── DictionaryModelDescription.cshtml │ │ │ │ ├── KeyValuePairModelDescription.cshtml │ │ │ │ ├── EnumTypeModelDescription.cshtml │ │ │ │ ├── Samples.cshtml │ │ │ │ ├── ModelDescriptionLink.cshtml │ │ │ │ ├── ApiGroup.cshtml │ │ │ │ ├── Parameters.cshtml │ │ │ │ └── HelpPageApiModel.cshtml │ │ │ ├── ResourceModel.cshtml │ │ │ ├── Api.cshtml │ │ │ └── Index.cshtml │ │ ├── _ViewStart.cshtml │ │ ├── Shared │ │ │ └── _Layout.cshtml │ │ └── Web.config │ │ ├── ModelDescriptions │ │ ├── SimpleTypeModelDescription.cs │ │ ├── DictionaryModelDescription.cs │ │ ├── CollectionModelDescription.cs │ │ ├── ParameterAnnotation.cs │ │ ├── EnumValueDescription.cs │ │ ├── KeyValuePairModelDescription.cs │ │ ├── IModelDocumentationProvider.cs │ │ ├── ModelDescription.cs │ │ ├── ComplexTypeModelDescription.cs │ │ ├── EnumTypeModelDescription.cs │ │ ├── ParameterDescription.cs │ │ ├── ModelNameAttribute.cs │ │ └── ModelNameHelper.cs │ │ ├── SampleGeneration │ │ ├── SampleDirection.cs │ │ ├── TextSample.cs │ │ ├── InvalidSample.cs │ │ └── ImageSample.cs │ │ ├── HelpPageAreaRegistration.cs │ │ ├── ApiDescriptionExtensions.cs │ │ ├── Controllers │ │ └── HelpController.cs │ │ ├── HelpPage.css │ │ ├── Models │ │ └── HelpPageApiModel.cs │ │ └── App_Start │ │ └── HelpPageConfig.cs ├── Models │ ├── Message.cs │ ├── RootMessage.cs │ ├── PostMessage.cs │ ├── AppList.cs │ ├── TeamFunSettings.cs │ ├── TeamGuestSetting.cs │ ├── Channel.cs │ ├── TeamsApp.cs │ ├── Clone.cs │ ├── TeamMessagingSettings.cs │ ├── TeamMemberSettings.cs │ ├── Member.cs │ ├── ResultsItem.cs │ ├── GraphResource.cs │ ├── Group.cs │ ├── Team.cs │ └── ResultsViewModel.cs ├── Scripts │ ├── _references.js │ ├── Graph.js │ ├── respond.min.js │ ├── respond.matchmedia.addListener.min.js │ └── jquery.validate.unobtrusive.min.js ├── App_Start │ ├── FilterConfig.cs │ ├── RouteConfig.cs │ ├── BundleConfig.cs │ └── Startup.Auth.cs ├── AuthProvider │ ├── IAuthProvider.cs │ └── AuthProvider.cs ├── Startup.cs ├── Content │ └── Site.css ├── Controllers │ ├── ErrorController.cs │ └── AccountController.cs ├── Global.asax.cs ├── Web.Debug.config ├── Web.Release.config ├── Properties │ └── AssemblyInfo.cs ├── Utils │ ├── MsalAppBuilder.cs │ ├── Constants.cs │ ├── MSALAccount.cs │ ├── Globals.cs │ ├── ClaimPrincipalExtension.cs │ ├── MSALAppMemoryTokenCache.cs │ └── MSALAppSessionTokenCache.cs ├── packages.config └── ImportantFiles │ └── ServiceHelper.cs ├── Node ├── SampleApp │ ├── package.json │ ├── utils │ │ └── files.js │ ├── app.js │ ├── graph │ │ ├── graph.js │ │ ├── sendmessage.html │ │ └── httpsrequesthelper.js │ ├── README.md │ └── auth │ │ ├── auth.js │ │ ├── login.html │ │ └── authHelper.js └── .vscode │ └── launch.json ├── microsoft-teams-sample-graph.yml ├── LICENSE-CODE ├── ThirdPartyNotices ├── csharp-teams-sample-graph.sln ├── README-localized ├── README-zh-cn.md ├── README-ja-jp.md ├── README-pt-br.md ├── README-ru-ru.md └── README-es-es.md ├── CONTRIBUTING.md └── README.md /source/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /source/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/csharp-teams-sample-graph/master/source/favicon.ico -------------------------------------------------------------------------------- /source/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="Microsoft_Teams_Graph_RESTAPIs_Connect.WebApiApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /source/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/csharp-teams-sample-graph/master/source/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /source/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/csharp-teams-sample-graph/master/source/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /source/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/csharp-teams-sample-graph/master/source/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/ImageSample.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage 2 | @model ImageSample 3 | 4 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/TextSample.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage 2 | @model TextSample 3 | 4 |
5 | @Model.Text
6 | 
-------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/SimpleTypeModelDescription.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 2 | @model SimpleTypeModelDescription 3 | @Model.Documentation -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | // Change the Layout path below to blend the look and feel of the help page with your existing web pages. 3 | Layout = "~/Areas/HelpPage/Views/Shared/_Layout.cshtml"; 4 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/ModelDescriptions/SimpleTypeModelDescription.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 2 | { 3 | public class SimpleTypeModelDescription : ModelDescription 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/ComplexTypeModelDescription.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 2 | @model ComplexTypeModelDescription 3 | @Html.DisplayFor(m => m.Properties, "Parameters") -------------------------------------------------------------------------------- /source/Areas/HelpPage/ModelDescriptions/DictionaryModelDescription.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 2 | { 3 | public class DictionaryModelDescription : KeyValuePairModelDescription 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /source/Models/Message.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 7 | { 8 | public class Message 9 | { 10 | public String content { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /source/Models/RootMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 7 | { 8 | public class RootMessage 9 | { 10 | public Message body { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/ModelDescriptions/CollectionModelDescription.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 2 | { 3 | public class CollectionModelDescription : ModelDescription 4 | { 5 | public ModelDescription ElementDescription { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /source/Models/PostMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 7 | { 8 | public class PostMessage 9 | { 10 | public RootMessage rootMessage { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/CollectionModelDescription.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 2 | @model CollectionModelDescription 3 | @if (Model.ElementDescription is ComplexTypeModelDescription) 4 | { 5 | @Html.DisplayFor(m => m.ElementDescription) 6 | } -------------------------------------------------------------------------------- /source/Models/AppList.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Web; 6 | 7 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 8 | { 9 | public class AppList 10 | { 11 | public String teamId { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /source/Views/Home/About.cshtml: -------------------------------------------------------------------------------- 1 | 3 | @using Resources 4 | @{ 5 | ViewBag.Title = Resource.About; 6 | } 7 |

@ViewBag.Title

8 |

@Resource.About_Description

-------------------------------------------------------------------------------- /source/Scripts/_references.js: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// 8 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/SampleGeneration/SampleDirection.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage 2 | { 3 | /// 4 | /// Indicates whether the sample is used for request or response 5 | /// 6 | public enum SampleDirection 7 | { 8 | Request = 0, 9 | Response 10 | } 11 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | @ViewBag.Title 7 | @RenderSection("scripts", required: false) 8 | 9 | 10 | @RenderBody() 11 | 12 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/ModelDescriptions/ParameterAnnotation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 4 | { 5 | public class ParameterAnnotation 6 | { 7 | public Attribute AnnotationAttribute { get; set; } 8 | 9 | public string Documentation { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /source/App_Start/FilterConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | 4 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect 5 | { 6 | public class FilterConfig 7 | { 8 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 9 | { 10 | filters.Add(new HandleErrorAttribute()); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/ModelDescriptions/EnumValueDescription.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 2 | { 3 | public class EnumValueDescription 4 | { 5 | public string Documentation { get; set; } 6 | 7 | public string Name { get; set; } 8 | 9 | public string Value { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /source/Models/TeamFunSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 7 | { 8 | public class TeamFunSettings 9 | { 10 | public Boolean allowGiphy { get; set; } 11 | public string giphyContentRating { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/InvalidSample.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage 2 | @model InvalidSample 3 | 4 | @if (HttpContext.Current.IsDebuggingEnabled) 5 | { 6 |
7 |

@Model.ErrorMessage

8 |
9 | } 10 | else 11 | { 12 |

Sample not available.

13 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/ModelDescriptions/KeyValuePairModelDescription.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 2 | { 3 | public class KeyValuePairModelDescription : ModelDescription 4 | { 5 | public ModelDescription KeyModelDescription { get; set; } 6 | 7 | public ModelDescription ValueModelDescription { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /source/Models/TeamGuestSetting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 7 | { 8 | public class TeamGuestSettings 9 | { 10 | public bool allowCreateUpdateChannels { get; set; } 11 | public bool allowDeleteChannels { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/ModelDescriptions/IModelDocumentationProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 5 | { 6 | public interface IModelDocumentationProvider 7 | { 8 | string GetDocumentation(MemberInfo member); 9 | 10 | string GetDocumentation(Type type); 11 | } 12 | } -------------------------------------------------------------------------------- /source/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | 3 | @using Resources 4 | @{ 5 | ViewBag.Title = Resource.App_Name; 6 | } 7 |

@ViewBag.Title

8 |

@Resource.Error_Introduction

9 |
@ViewBag.Message
-------------------------------------------------------------------------------- /source/AuthProvider/IAuthProvider.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. 3 | * See LICENSE in the source repository root for complete license information. 4 | */ 5 | using System.Threading.Tasks; 6 | 7 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Auth 8 | { 9 | public interface IAuthProvider 10 | { 11 | Task GetUserAccessTokenAsync(); 12 | 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /source/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.Owin; 5 | using Owin; 6 | 7 | [assembly: OwinStartup(typeof(Microsoft_Teams_Graph_RESTAPIs_Connect.Startup))] 8 | 9 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect 10 | { 11 | public partial class Startup 12 | { 13 | public void Configuration(IAppBuilder app) 14 | { 15 | ConfigureAuth(app); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/ModelDescriptions/ModelDescription.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 4 | { 5 | /// 6 | /// Describes a type model. 7 | /// 8 | public abstract class ModelDescription 9 | { 10 | public string Documentation { get; set; } 11 | 12 | public Type ModelType { get; set; } 13 | 14 | public string Name { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/DictionaryModelDescription.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 2 | @model DictionaryModelDescription 3 | Dictionary of @Html.DisplayFor(m => Model.KeyModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.KeyModelDescription }) [key] 4 | and @Html.DisplayFor(m => Model.ValueModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.ValueModelDescription }) [value] -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/KeyValuePairModelDescription.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 2 | @model KeyValuePairModelDescription 3 | Pair of @Html.DisplayFor(m => Model.KeyModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.KeyModelDescription }) [key] 4 | and @Html.DisplayFor(m => Model.ValueModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.ValueModelDescription }) [value] -------------------------------------------------------------------------------- /source/Models/Channel.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Web; 6 | 7 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 8 | { 9 | public class Channel 10 | { 11 | [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] 12 | public string id { get; set; } 13 | 14 | public string displayName { get; set; } 15 | public string description { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /Node/SampleApp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Teams_Sample_Graph_Node_App", 3 | "version": "1.0.0", 4 | "description": "This is a small sample app using the Microsoft Teams APIs in the Microsoft Graph", 5 | "main": "app.js", 6 | "author": "Richard Taylor", 7 | "license": "ISC", 8 | "dependencies": { 9 | "fs-extra": "^2.1.2", 10 | "node-rest-client": "^3.1.0", 11 | "node-uuid": "^1.4.8", 12 | "oauth": "^0.9.14", 13 | "restify": "^4.3.0", 14 | "restify-cookies": "^0.2.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /source/Content/Site.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | padding-bottom: 20px; 4 | } 5 | 6 | /* Set padding to keep content from hitting the edges */ 7 | .body-content { 8 | padding-left: 15px; 9 | padding-right: 15px; 10 | } 11 | 12 | /* Set width on the form input elements since they're 100% wide by default */ 13 | input, 14 | select, 15 | textarea { 16 | max-width: 280px; 17 | } 18 | 19 | .bluerow { 20 | background-color: lavender 21 | } 22 | 23 | label { 24 | margin-right: 12px; 25 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/ModelDescriptions/ComplexTypeModelDescription.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | 3 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 4 | { 5 | public class ComplexTypeModelDescription : ModelDescription 6 | { 7 | public ComplexTypeModelDescription() 8 | { 9 | Properties = new Collection(); 10 | } 11 | 12 | public Collection Properties { get; private set; } 13 | } 14 | } -------------------------------------------------------------------------------- /source/Models/TeamsApp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 7 | { 8 | public class TeamsApp 9 | { 10 | public string id { get; set; } 11 | public string name { get; set; } 12 | public string version { get; set; } 13 | public string isBlocked { get; set; } 14 | public string installedState { get; set; } 15 | public string context { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /source/Scripts/Graph.js: -------------------------------------------------------------------------------- 1 | var grapchClient = { 2 | 3 | getChannels: function () { 4 | 5 | var teamId = $('#TeamId').val(); 6 | var userId = $('#UserId').val(); 7 | 8 | 9 | 10 | $.ajax({ 11 | url: "/Home/", 12 | method: "POST", 13 | data: { 'team-id': teamId, 'user-id': userId }, 14 | success: function (result) { 15 | $("#ChannelsResult").html(result); 16 | } 17 | 18 | }); 19 | }, 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | } -------------------------------------------------------------------------------- /source/Models/Clone.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 7 | { 8 | public class Clone 9 | { 10 | public string displayName { get; set; } 11 | public string description { get; set; } 12 | public string mailNickName { get; set; } 13 | public string teamVisibilityType { get; set; } 14 | public string partsToClone { get; set; } // "apps,members,settings,tabs,channels" 15 | } 16 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/ModelDescriptions/EnumTypeModelDescription.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.ObjectModel; 3 | 4 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 5 | { 6 | public class EnumTypeModelDescription : ModelDescription 7 | { 8 | public EnumTypeModelDescription() 9 | { 10 | Values = new Collection(); 11 | } 12 | 13 | public Collection Values { get; private set; } 14 | } 15 | } -------------------------------------------------------------------------------- /microsoft-teams-sample-graph.yml: -------------------------------------------------------------------------------- 1 | ### YamlMime:Sample 2 | sample: 3 | - name: Microsoft Teams Graph API Samples for C# 4 | path: '' 5 | description: Sample apps (C#) for accessing Microsoft Teams data via the Microsoft Graph 6 | readme: '' 7 | generateZip: FALSE 8 | isLive: TRUE 9 | technologies: 10 | - Microsoft Graph 11 | azureDeploy: '' 12 | author: richardtaylorrt 13 | platforms: [] 14 | languages: 15 | - C# 16 | - node.js 17 | extensions: 18 | products: 19 | - Microsoft Teams 20 | scenarios: [] 21 | -------------------------------------------------------------------------------- /source/Controllers/ErrorController.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. 3 | * See LICENSE in the source repository root for complete license information. 4 | */ 5 | 6 | using System.Web.Mvc; 7 | 8 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Controllers 9 | { 10 | public class ErrorController : Controller 11 | { 12 | // GET: Error 13 | public ActionResult Index(string message) 14 | { 15 | ViewBag.Message = message; 16 | return View("Error"); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /source/Models/TeamMessagingSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 7 | { 8 | public class TeamMessagingSettings 9 | { 10 | public Boolean allowUserEditMessages { get; set; } 11 | public Boolean allowUserDeleteMessages { get; set; } 12 | public Boolean allowOwnerDeleteMessages { get; set; } 13 | public Boolean allowTeamMentions { get; set; } 14 | public Boolean allowChannelMentions { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /source/Models/TeamMemberSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 7 | { 8 | public class TeamMemberSettings 9 | { 10 | public Boolean allowCreateUpdateChannels { get; set; } 11 | public Boolean allowDeleteChannels { get; set; } 12 | public Boolean allowAddRemoveApps { get; set; } 13 | public Boolean allowCreateUpdateRemoveTabs { get; set; } 14 | public Boolean allowCreateUpdateRemoveConnectors { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /source/Models/Member.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Web; 6 | 7 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 8 | { 9 | public class Member 10 | { 11 | public String groupId { get; set; } 12 | public String upn { get; set; } 13 | public bool owner { get; set; } 14 | 15 | [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] 16 | public string id { get; set; } 17 | } 18 | 19 | public class User 20 | { 21 | public string id { get; set; } 22 | } 23 | } -------------------------------------------------------------------------------- /source/Models/ResultsItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 7 | { 8 | public class ResultsItem 9 | { 10 | // The ID and display name for the entity's radio button. 11 | public string Id { get; set; } 12 | public string Display { get; set; } 13 | 14 | // The properties of an entity that display in the UI. 15 | public Dictionary Properties; 16 | 17 | public ResultsItem() 18 | { 19 | Properties = new Dictionary(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /source/Models/GraphResource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 7 | { 8 | public class CreateChannel 9 | { 10 | public string displayName { get; set; } 11 | public string description { get; set; } 12 | } 13 | 14 | public class PostMessage 15 | { 16 | public RootMessage rootMessage { get; set; } 17 | } 18 | 19 | public class RootMessage 20 | { 21 | public MessageBody body { get; set; } 22 | } 23 | 24 | public class MessageBody 25 | { 26 | public string content { get; set; } 27 | } 28 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/ModelDescriptions/ParameterDescription.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.ObjectModel; 3 | 4 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 5 | { 6 | public class ParameterDescription 7 | { 8 | public ParameterDescription() 9 | { 10 | Annotations = new Collection(); 11 | } 12 | 13 | public Collection Annotations { get; private set; } 14 | 15 | public string Documentation { get; set; } 16 | 17 | public string Name { get; set; } 18 | 19 | public ModelDescription TypeDescription { get; set; } 20 | } 21 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/ModelDescriptions/ModelNameAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 4 | { 5 | /// 6 | /// Use this attribute to change the name of the generated for a type. 7 | /// 8 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, AllowMultiple = false, Inherited = false)] 9 | public sealed class ModelNameAttribute : Attribute 10 | { 11 | public ModelNameAttribute(string name) 12 | { 13 | Name = name; 14 | } 15 | 16 | public string Name { get; private set; } 17 | } 18 | } -------------------------------------------------------------------------------- /source/App_Start/RouteConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Routing; 7 | 8 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect 9 | { 10 | public class RouteConfig 11 | { 12 | public static void RegisterRoutes(RouteCollection routes) 13 | { 14 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 | 16 | routes.MapRoute( 17 | name: "Default", 18 | url: "{controller}/{action}/{id}", 19 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 20 | ); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/ResourceModel.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Web.Http 2 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 3 | @model ModelDescription 4 | 5 | 6 |
7 | 14 |

@Model.Name

15 |

@Model.Documentation

16 |
17 | @Html.DisplayFor(m => Model) 18 |
19 |
20 | -------------------------------------------------------------------------------- /source/Models/Group.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Web; 6 | 7 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 8 | { 9 | public class Group 10 | { 11 | public String displayName { get; set; } 12 | public String mailNickname { get; set; } 13 | public String description { get; set; } 14 | public String[] groupTypes { get; set; } 15 | public Boolean mailEnabled { get; set; } 16 | public Boolean securityEnabled { get; set; } 17 | public String visibility { get; set; } 18 | 19 | [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] 20 | public string id { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /Node/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${file}", 12 | "env": { 13 | "NODE_ENV": "development", 14 | "AUTH_CLIENT_ID" : "", //auth client ID 15 | "AUTH_CLIENT_SECRET" : "", //auth client secret 16 | "BASE_URI": "" //Host name for your tab/application 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/Api.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Web.Http 2 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.Models 3 | @model HelpPageApiModel 4 | 5 | @{ 6 | var description = Model.ApiDescription; 7 | ViewBag.Title = description.HttpMethod.Method + " " + description.RelativePath; 8 | } 9 | 10 | 11 |
12 | 19 |
20 | @Html.DisplayForModel() 21 |
22 |
23 | -------------------------------------------------------------------------------- /source/Global.asax.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Web; 6 | using System.Web.Http; 7 | using System.Web.Mvc; 8 | using System.Web.Optimization; 9 | using System.Web.Routing; 10 | using System.Web.Security; 11 | using System.Web.SessionState; 12 | 13 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect 14 | { 15 | public class WebApiApplication : System.Web.HttpApplication 16 | { 17 | protected void Application_Start() 18 | { 19 | AreaRegistration.RegisterAllAreas(); 20 | FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 21 | RouteConfig.RegisterRoutes(RouteTable.Routes); 22 | BundleConfig.RegisterBundles(BundleTable.Bundles); 23 | 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Node/SampleApp/utils/files.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | 3 | function sendFile(path, res){ 4 | var data = fs.readFileSync(path, 'utf-8'); 5 | res.writeHead(200, { 6 | 'Content-Length': Buffer.byteLength(data), 7 | 'Content-Type': 'text/html' 8 | }); 9 | 10 | res.write(data); 11 | res.end(); 12 | } 13 | module.exports.sendFile = sendFile; 14 | 15 | module.exports.sendFileOrLogin = function sendFileOrLogin(path, req, res, next){ 16 | if (req.params.auth && (req.cookies.REFRESH_TOKEN_CACHE_KEY === undefined)) { 17 | var redirectUrl = '/login?'; 18 | if (req.params.web) { 19 | redirectUrl += 'web=' + req.params.web +'&'; 20 | } 21 | redirectUrl += 'redirectUrl=' + encodeURIComponent(req.url); 22 | res.redirect(redirectUrl, next); 23 | } else { 24 | sendFile(path, res); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/HelpPageAreaRegistration.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Http; 2 | using System.Web.Mvc; 3 | 4 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage 5 | { 6 | public class HelpPageAreaRegistration : AreaRegistration 7 | { 8 | public override string AreaName 9 | { 10 | get 11 | { 12 | return "HelpPage"; 13 | } 14 | } 15 | 16 | public override void RegisterArea(AreaRegistrationContext context) 17 | { 18 | context.MapRoute( 19 | "HelpPage_Default", 20 | "Help/{action}/{apiId}", 21 | new { controller = "Help", action = "Index", apiId = UrlParameter.Optional }); 22 | 23 | HelpPageConfig.Register(GlobalConfiguration.Configuration); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/EnumTypeModelDescription.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 2 | @model EnumTypeModelDescription 3 | 4 |

Possible enumeration values:

5 | 6 | 7 | 8 | 9 | 10 | 11 | @foreach (EnumValueDescription value in Model.Values) 12 | { 13 | 14 | 15 | 18 | 21 | 22 | } 23 | 24 |
NameValueDescription
@value.Name 16 |

@value.Value

17 |
19 |

@value.Documentation

20 |
-------------------------------------------------------------------------------- /Node/SampleApp/app.js: -------------------------------------------------------------------------------- 1 | const restify = require('restify'); 2 | const CookieParser = require('restify-cookies'); 3 | 4 | process.env.AUTH_CLIENT_ID = (process.env.AUTH_CLIENT_ID) ? process.env.AUTH_CLIENT_ID : '[auth client ID]'; 5 | process.env.AUTH_CLIENT_SECRET = (process.env.AUTH_CLIENT_SECRET) ? process.env.AUTH_CLIENT_SECRET : '[auth client secret]'; 6 | process.env.BASE_URI = (process.env.BASE_URI) ? process.env.BASE_URI : '[the host name for your application]'; 7 | 8 | var server = restify.createServer(); 9 | server.use(restify.queryParser()); 10 | server.use(CookieParser.parse); 11 | server.use(restify.bodyParser()); 12 | 13 | server.listen(process.env.port || process.env.PORT || 55065, () => { 14 | console.log(`Started sample app for Microsoft Teams in Microsoft Graph`); 15 | }); 16 | 17 | var auth = require('./auth/auth.js'); 18 | auth.init(server); 19 | auth.start_listening(); 20 | 21 | var graph = require('./graph/graph.js'); 22 | graph.init(server); 23 | graph.start_listening(); 24 | -------------------------------------------------------------------------------- /source/Views/Shared/_ResultsTable.cshtml: -------------------------------------------------------------------------------- 1 | 3 | @using Resources; 4 | @model IEnumerable 5 | 6 |
7 |
8 | 9 | @{ 10 | int i = 0; 11 | foreach (var t in Model) 12 | { 13 | //var color = (i % 2) == 0 ? "white" : "lavender"; 14 | var color = (i % 2) == 0 ? "" : "bluerow"; 15 | 16 | 17 | 18 | 19 | i++; 20 | } 21 | } 22 |
@t.Text@t.Value
23 |
24 |
25 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/Samples.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Net.Http.Headers 2 | @model Dictionary 3 | 4 | @{ 5 | // Group the samples into a single tab if they are the same. 6 | Dictionary samples = Model.GroupBy(pair => pair.Value).ToDictionary( 7 | pair => String.Join(", ", pair.Select(m => m.Key.ToString()).ToArray()), 8 | pair => pair.Key); 9 | var mediaTypes = samples.Keys; 10 | } 11 |
12 | @foreach (var mediaType in mediaTypes) 13 | { 14 |

@mediaType

15 |
16 | Sample: 17 | @{ 18 | var sample = samples[mediaType]; 19 | if (sample == null) 20 | { 21 |

Sample not available.

22 | } 23 | else 24 | { 25 | @Html.DisplayFor(s => sample); 26 | } 27 | } 28 |
29 | } 30 |
-------------------------------------------------------------------------------- /source/Areas/HelpPage/SampleGeneration/TextSample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage 4 | { 5 | /// 6 | /// This represents a preformatted text sample on the help page. There's a display template named TextSample associated with this class. 7 | /// 8 | public class TextSample 9 | { 10 | public TextSample(string text) 11 | { 12 | if (text == null) 13 | { 14 | throw new ArgumentNullException("text"); 15 | } 16 | Text = text; 17 | } 18 | 19 | public string Text { get; private set; } 20 | 21 | public override bool Equals(object obj) 22 | { 23 | TextSample other = obj as TextSample; 24 | return other != null && Text == other.Text; 25 | } 26 | 27 | public override int GetHashCode() 28 | { 29 | return Text.GetHashCode(); 30 | } 31 | 32 | public override string ToString() 33 | { 34 | return Text; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/ModelDescriptionLink.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 2 | @model Type 3 | @{ 4 | ModelDescription modelDescription = ViewBag.modelDescription; 5 | if (modelDescription is ComplexTypeModelDescription || modelDescription is EnumTypeModelDescription) 6 | { 7 | if (Model == typeof(Object)) 8 | { 9 | @:Object 10 | } 11 | else 12 | { 13 | @Html.ActionLink(modelDescription.Name, "ResourceModel", "Help", new { modelName = modelDescription.Name }, null) 14 | } 15 | } 16 | else if (modelDescription is CollectionModelDescription) 17 | { 18 | var collectionDescription = modelDescription as CollectionModelDescription; 19 | var elementDescription = collectionDescription.ElementDescription; 20 | @:Collection of @Html.DisplayFor(m => elementDescription.ModelType, "ModelDescriptionLink", new { modelDescription = elementDescription }) 21 | } 22 | else 23 | { 24 | @Html.DisplayFor(m => modelDescription) 25 | } 26 | } -------------------------------------------------------------------------------- /LICENSE-CODE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) Microsoft Corporation 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | associated documentation files (the "Software"), to deal in the Software without restriction, 6 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial 11 | portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 15 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 16 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 17 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /ThirdPartyNotices: -------------------------------------------------------------------------------- 1 | ##Legal Notices 2 | Microsoft and any contributors grant you a license to the Microsoft documentation and other content 3 | in this repository under the [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/legalcode), 4 | see the [LICENSE](LICENSE) file, and grant you a license to any code in the repository under the [MIT License](https://opensource.org/licenses/MIT), see the 5 | [LICENSE-CODE](LICENSE-CODE) file. 6 | 7 | Microsoft, Windows, Microsoft Azure and/or other Microsoft products and services referenced in the documentation 8 | may be either trademarks or registered trademarks of Microsoft in the United States and/or other countries. 9 | The licenses for this project do not grant you rights to use any Microsoft names, logos, or trademarks. 10 | Microsoft's general trademark guidelines can be found at http://go.microsoft.com/fwlink/?LinkID=254653. 11 | 12 | Privacy information can be found at https://privacy.microsoft.com/en-us/ 13 | 14 | Microsoft and any contributors reserve all others rights, whether under their respective copyrights, patents, 15 | or trademarks, whether by implication, estoppel or otherwise. -------------------------------------------------------------------------------- /source/Areas/HelpPage/SampleGeneration/InvalidSample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage 4 | { 5 | /// 6 | /// This represents an invalid sample on the help page. There's a display template named InvalidSample associated with this class. 7 | /// 8 | public class InvalidSample 9 | { 10 | public InvalidSample(string errorMessage) 11 | { 12 | if (errorMessage == null) 13 | { 14 | throw new ArgumentNullException("errorMessage"); 15 | } 16 | ErrorMessage = errorMessage; 17 | } 18 | 19 | public string ErrorMessage { get; private set; } 20 | 21 | public override bool Equals(object obj) 22 | { 23 | InvalidSample other = obj as InvalidSample; 24 | return other != null && ErrorMessage == other.ErrorMessage; 25 | } 26 | 27 | public override int GetHashCode() 28 | { 29 | return ErrorMessage.GetHashCode(); 30 | } 31 | 32 | public override string ToString() 33 | { 34 | return ErrorMessage; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /csharp-teams-sample-graph.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27428.2015 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GraphAPI.Web", "source\GraphAPI.Web.csproj", "{9497154D-1F71-402C-A6DC-130FB6B8F39C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {9497154D-1F71-402C-A6DC-130FB6B8F39C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {9497154D-1F71-402C-A6DC-130FB6B8F39C}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {9497154D-1F71-402C-A6DC-130FB6B8F39C}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {9497154D-1F71-402C-A6DC-130FB6B8F39C}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {F6A58AB2-6EA7-4951-8D62-9D68DD81CA85} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /source/App_Start/BundleConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Optimization; 3 | 4 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect 5 | { 6 | public class BundleConfig 7 | { 8 | // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862 9 | public static void RegisterBundles(BundleCollection bundles) 10 | { 11 | bundles.Add(new ScriptBundle("~/bundles/jquery").Include( 12 | "~/Scripts/jquery-{version}.js")); 13 | 14 | // Use the development version of Modernizr to develop with and learn from. Then, when you're 15 | // ready for production, use the build tool at http://modernizr.com to pick only the tests you need. 16 | bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( 17 | "~/Scripts/modernizr-*")); 18 | 19 | bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( 20 | "~/Scripts/bootstrap.js", 21 | "~/Scripts/respond.js")); 22 | 23 | bundles.Add(new StyleBundle("~/Content/css").Include( 24 | "~/Content/bootstrap.css", 25 | "~/Content/site.css")); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/SampleGeneration/ImageSample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage 4 | { 5 | /// 6 | /// This represents an image sample on the help page. There's a display template named ImageSample associated with this class. 7 | /// 8 | public class ImageSample 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The URL of an image. 14 | public ImageSample(string src) 15 | { 16 | if (src == null) 17 | { 18 | throw new ArgumentNullException("src"); 19 | } 20 | Src = src; 21 | } 22 | 23 | public string Src { get; private set; } 24 | 25 | public override bool Equals(object obj) 26 | { 27 | ImageSample other = obj as ImageSample; 28 | return other != null && Src == other.Src; 29 | } 30 | 31 | public override int GetHashCode() 32 | { 33 | return Src.GetHashCode(); 34 | } 35 | 36 | public override string ToString() 37 | { 38 | return Src; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /source/Models/Team.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Web; 6 | 7 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 8 | { 9 | public class Team 10 | { 11 | [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] 12 | public TeamGuestSettings guestSettings { get; set; } 13 | 14 | [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] 15 | public TeamMemberSettings memberSettings { get; set; } 16 | 17 | [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] 18 | public TeamMessagingSettings messagingSettings { get; set; } 19 | 20 | [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] 21 | public TeamFunSettings funSettings { get; set; } 22 | 23 | [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] 24 | public string id { get; set; } 25 | 26 | [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] 27 | public string displayName { get; set; } 28 | } 29 | 30 | public class ResultList 31 | { 32 | [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] 33 | public T[] value { get; set; } 34 | } 35 | } -------------------------------------------------------------------------------- /Node/SampleApp/graph/graph.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. 3 | * See LICENSE in the project root for license information. 4 | */ 5 | const files = require('../utils/files.js'); 6 | const httpsrequesthelper = require('./httpsrequesthelper.js'); 7 | 8 | var server; 9 | 10 | function start_listening() { 11 | 12 | this.server.get('/', (req, res, next) => { 13 | files.sendFileOrLogin('./graph/sendmessage.html', req, res, next); 14 | }); 15 | 16 | this.server.get(/^\/graph/, (req, res, next) => { 17 | // Proxy requests onto the Microsoft Graph 18 | var url = req.url.substring('/graph'.length); 19 | httpsrequesthelper.executeRequestWithErrorHandling(req, res, next, 'GET', url, (data) => { 20 | res.send(data); 21 | res.end(); 22 | }); 23 | }); 24 | 25 | this.server.post(/^\/graph/, (req, res, next) => { 26 | // Proxy requests onto the Microsoft Graph 27 | var url = req.url.substring('/graph'.length); 28 | httpsrequesthelper.executeRequestWithErrorHandling(req, res, next, 'POST', url, (data) => { 29 | if (data) { res.send(data); } 30 | res.end(); 31 | }); 32 | }); 33 | } 34 | 35 | module.exports.init = function(server) { 36 | this.server = server; 37 | return this; 38 | } 39 | 40 | module.exports.start_listening = start_listening; -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Web.Http 2 | @using System.Web.Http.Controllers 3 | @using System.Web.Http.Description 4 | @using System.Collections.ObjectModel 5 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.Models 6 | @model Collection 7 | 8 | @{ 9 | ViewBag.Title = "ASP.NET Web API Help Page"; 10 | 11 | // Group APIs by controller 12 | ILookup apiGroups = Model.ToLookup(api => api.ActionDescriptor.ControllerDescriptor); 13 | } 14 | 15 | 16 |
17 |
18 |
19 |

@ViewBag.Title

20 |
21 |
22 |
23 |
24 | 32 |
33 | @foreach (var group in apiGroups) 34 | { 35 | @Html.DisplayFor(m => group, "ApiGroup") 36 | } 37 |
38 |
39 | -------------------------------------------------------------------------------- /source/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /source/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Node/SampleApp/README.md: -------------------------------------------------------------------------------- 1 | # Node.js sample app for Microsoft Teams APIs in Microsoft Graph 2 | 3 | This sample app, written in Node.js, shows a web site calling the Microsoft Graph Team APIs. 4 | 5 | ## Prerequisites 6 | The minimum prerequisites to run this sample are: 7 | * The latest update of Visual Studio. You can download the community version [here](http://www.visualstudio.com) for free. 8 | * An Office 365 account with access to Microsoft Teams, with [sideloading enabled](https://msdn.microsoft.com/en-us/microsoft-teams/setup). 9 | * An account with the [appropriate rights](../README.md) to register and run the samples. 10 | 11 | ## Register the application: 12 | Please see the project's [Read Me file](../../README.md) for more details. Note that for the Node sample, you should set your redirect URI to be: http://localhost:55065/login 13 | 14 | ## Build and run the sample app 15 | 1. In app.js, update the process.env variables with your app's ID and secret and 'https://localhost:55065' as the hostname. 16 | 2. Run “node app.js”. 17 | 3. Go to http://localhost:55065/login in your browser. 18 | 4. Sign in with your account, and grant the requested permissions. 19 | * Note you'll need to have appropriate elevated rights to run the app (Group.ReadWrite.All and User.ReadWrite.All) 20 | 5. Choose operation, such as 'Get My Teams', 'Get Channels', 'Create Channel' or 'Post Message'. 21 | 6. Response information is displayed at the bottom of the page. 22 | 23 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/ApiGroup.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Web.Http 2 | @using System.Web.Http.Controllers 3 | @using System.Web.Http.Description 4 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage 5 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.Models 6 | @model IGrouping 7 | 8 | @{ 9 | var controllerDocumentation = ViewBag.DocumentationProvider != null ? 10 | ViewBag.DocumentationProvider.GetDocumentation(Model.Key) : 11 | null; 12 | } 13 | 14 |

@Model.Key.ControllerName

15 | @if (!String.IsNullOrEmpty(controllerDocumentation)) 16 | { 17 |

@controllerDocumentation

18 | } 19 | 20 | 21 | 22 | 23 | 24 | @foreach (var api in Model) 25 | { 26 | 27 | 28 | 38 | 39 | } 40 | 41 |
APIDescription
@api.HttpMethod.Method @api.RelativePath 29 | @if (api.Documentation != null) 30 | { 31 |

@api.Documentation

32 | } 33 | else 34 | { 35 |

No documentation available.

36 | } 37 |
-------------------------------------------------------------------------------- /source/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("Microsoft_Teams_Graph_RESTAPIs_Connect")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Microsoft_Teams_Graph_RESTAPIs_Connect")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 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("46bf832a-0350-4488-b294-2dbf7d91ca9f")] 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 | -------------------------------------------------------------------------------- /source/Utils/MsalAppBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using Microsoft.Identity.Client; 6 | using Newtonsoft.Json; 7 | using Newtonsoft.Json.Linq; 8 | 9 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect 10 | { 11 | public static class MsalAppBuilder 12 | { 13 | public static IConfidentialClientApplication BuildConfidentialClientApplication() 14 | { 15 | IConfidentialClientApplication clientapp = ConfidentialClientApplicationBuilder.Create(Globals.ClientId) 16 | .WithClientSecret(Globals.ClientSecret) 17 | .WithRedirectUri(Globals.RedirectUri) 18 | .WithAuthority(new Uri(Globals.Authority)) 19 | .Build(); 20 | 21 | MSALPerUserMemoryTokenCache userTokenCache = new MSALPerUserMemoryTokenCache(clientapp.UserTokenCache); 22 | return clientapp; 23 | } 24 | 25 | public static void ClearUserTokenCache() 26 | { 27 | IConfidentialClientApplication clientapp = ConfidentialClientApplicationBuilder.Create(Globals.ClientId) 28 | .WithClientSecret(Globals.ClientSecret) 29 | .WithRedirectUri(Globals.RedirectUri) 30 | .WithAuthority(new Uri(Globals.Authority)) 31 | .Build(); 32 | 33 | // We only clear the user's tokens. 34 | MSALPerUserMemoryTokenCache userTokenCache = new MSALPerUserMemoryTokenCache(clientapp.UserTokenCache); 35 | userTokenCache.Clear(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /source/Views/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | 3 | @using Resources 4 | @if (Request.IsAuthenticated) 5 | { 6 | 7 | 16 | 17 | } 18 | else 19 | { 20 | 38 | 39 | 46 | } 47 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/ModelDescriptions/ModelNameHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 7 | { 8 | internal static class ModelNameHelper 9 | { 10 | // Modify this to provide custom model name mapping. 11 | public static string GetModelName(Type type) 12 | { 13 | ModelNameAttribute modelNameAttribute = type.GetCustomAttribute(); 14 | if (modelNameAttribute != null && !String.IsNullOrEmpty(modelNameAttribute.Name)) 15 | { 16 | return modelNameAttribute.Name; 17 | } 18 | 19 | string modelName = type.Name; 20 | if (type.IsGenericType) 21 | { 22 | // Format the generic type name to something like: GenericOfAgurment1AndArgument2 23 | Type genericType = type.GetGenericTypeDefinition(); 24 | Type[] genericArguments = type.GetGenericArguments(); 25 | string genericTypeName = genericType.Name; 26 | 27 | // Trim the generic parameter counts from the name 28 | genericTypeName = genericTypeName.Substring(0, genericTypeName.IndexOf('`')); 29 | string[] argumentTypeNames = genericArguments.Select(t => GetModelName(t)).ToArray(); 30 | modelName = String.Format(CultureInfo.InvariantCulture, "{0}Of{1}", genericTypeName, String.Join("And", argumentTypeNames)); 31 | } 32 | 33 | return modelName; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/ApiDescriptionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Web; 4 | using System.Web.Http.Description; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage 7 | { 8 | public static class ApiDescriptionExtensions 9 | { 10 | /// 11 | /// Generates an URI-friendly ID for the . E.g. "Get-Values-id_name" instead of "GetValues/{id}?name={name}" 12 | /// 13 | /// The . 14 | /// The ID as a string. 15 | public static string GetFriendlyId(this ApiDescription description) 16 | { 17 | string path = description.RelativePath; 18 | string[] urlParts = path.Split('?'); 19 | string localPath = urlParts[0]; 20 | string queryKeyString = null; 21 | if (urlParts.Length > 1) 22 | { 23 | string query = urlParts[1]; 24 | string[] queryKeys = HttpUtility.ParseQueryString(query).AllKeys; 25 | queryKeyString = String.Join("_", queryKeys); 26 | } 27 | 28 | StringBuilder friendlyPath = new StringBuilder(); 29 | friendlyPath.AppendFormat("{0}-{1}", 30 | description.HttpMethod.Method, 31 | localPath.Replace("/", "-").Replace("{", String.Empty).Replace("}", String.Empty)); 32 | if (queryKeyString != null) 33 | { 34 | friendlyPath.AppendFormat("_{0}", queryKeyString.Replace('.', '-')); 35 | } 36 | return friendlyPath.ToString(); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /source/Controllers/AccountController.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. 3 | * See LICENSE in the source repository root for complete license information. 4 | */ 5 | 6 | using System.Web; 7 | using System.Web.Mvc; 8 | using Microsoft.Owin.Security; 9 | using Microsoft.Owin.Security.Cookies; 10 | using Microsoft.Owin.Security.OpenIdConnect; 11 | using System.Security.Claims; 12 | 13 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Controllers 14 | { 15 | public class AccountController : Controller 16 | { 17 | public void SignIn() 18 | { 19 | if (!Request.IsAuthenticated) 20 | { 21 | // Signal OWIN to send an authorization request to Azure. 22 | HttpContext.GetOwinContext().Authentication.Challenge( 23 | new AuthenticationProperties { RedirectUri = "/" }, 24 | OpenIdConnectAuthenticationDefaults.AuthenticationType); 25 | } 26 | } 27 | 28 | // Here we clear the token cache and end the session with the web app. 29 | public void SignOut() 30 | { 31 | if (Request.IsAuthenticated) 32 | { 33 | // Get the user's token cache and clear it. 34 | string userObjectId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value; 35 | MsalAppBuilder.ClearUserTokenCache(); 36 | } 37 | 38 | // Send an OpenID Connect sign-out request. 39 | HttpContext.GetOwinContext().Authentication.SignOut( 40 | CookieAuthenticationDefaults.AuthenticationType); 41 | Response.Redirect("/"); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /Node/SampleApp/auth/auth.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. 3 | * See LICENSE in the project root for license information. 4 | */ 5 | const authHelper = require('./authHelper.js'); 6 | const files = require('../utils/files.js'); 7 | 8 | var server; 9 | 10 | function start_listening() { 11 | 12 | this.server.get('login', (req, res, next) => { 13 | if (req.query.code !== undefined) { 14 | authHelper.getTokenFromCode(req.query.code, function (e, accessToken, refreshToken) { 15 | if (e === null) { 16 | // Cache the access and refresh token in a cookie for simplicity. 17 | // DON'T DO THIS IN A PRODUCTION APP. 18 | res.setCookie(authHelper.ACCESS_TOKEN_CACHE_KEY, accessToken); 19 | res.setCookie(authHelper.REFRESH_TOKEN_CACHE_KEY, refreshToken); 20 | // Now we're signed in, go to the originally requested page, as configured in 'state' param. 21 | res.redirect(req.params.state, next); 22 | } else { 23 | res.status(500); 24 | res.send(); 25 | } 26 | }); 27 | } 28 | else 29 | { 30 | files.sendFile('./auth/login.html', res); 31 | } 32 | }); 33 | 34 | this.server.get('disconnect', function (req, res, next) { 35 | res.clearCookie('nodecookie'); 36 | authHelper.clearCookies(res); 37 | res.status(200); 38 | res.redirect('/login', next); 39 | }); 40 | 41 | this.server.get('api/authurl', (req, res, next) => { 42 | // Get the authentication login URL for use client side. 43 | var ret = { authUrl: authHelper.getAuthUrl() }; 44 | res.send(ret); 45 | res.end(); 46 | }); 47 | } 48 | 49 | module.exports.init = function(server) { 50 | this.server = server; 51 | return this; 52 | } 53 | 54 | module.exports.start_listening = start_listening; -------------------------------------------------------------------------------- /source/Utils/Constants.cs: -------------------------------------------------------------------------------- 1 | /************************************************************************************************ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015 Microsoft Corporation 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | ***********************************************************************************************/ 24 | 25 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect 26 | { 27 | /// 28 | /// claim keys constants 29 | /// 30 | public static class ClaimConstants 31 | { 32 | public const string ObjectId = "http://schemas.microsoft.com/identity/claims/objectidentifier"; 33 | public const string TenantId = "http://schemas.microsoft.com/identity/claims/tenantid"; 34 | public const string tid = "tid"; 35 | } 36 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/Parameters.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Collections.Generic 2 | @using System.Collections.ObjectModel 3 | @using System.Web.Http.Description 4 | @using System.Threading 5 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 6 | @model IList 7 | 8 | @if (Model.Count > 0) 9 | { 10 | 11 | 12 | 13 | 14 | 15 | @foreach (ParameterDescription parameter in Model) 16 | { 17 | ModelDescription modelDescription = parameter.TypeDescription; 18 | 19 | 20 | 23 | 26 | 39 | 40 | } 41 | 42 |
NameDescriptionTypeAdditional information
@parameter.Name 21 |

@parameter.Documentation

22 |
24 | @Html.DisplayFor(m => modelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = modelDescription }) 25 | 27 | @if (parameter.Annotations.Count > 0) 28 | { 29 | foreach (var annotation in parameter.Annotations) 30 | { 31 |

@annotation.Documentation

32 | } 33 | } 34 | else 35 | { 36 |

None.

37 | } 38 |
43 | } 44 | else 45 | { 46 |

None.

47 | } 48 | 49 | -------------------------------------------------------------------------------- /source/Views/Shared/_ResultsPartial.cshtml: -------------------------------------------------------------------------------- 1 | 3 | @using Resources; 4 | @model Microsoft_Teams_Graph_RESTAPIs_Connect.Models.ResultsViewModel 5 |
6 |
7 | @if (Model != null) 8 | { 9 | if (Model.Items.Any()) 10 | { 11 | foreach (var item in Model.Items) 12 | { 13 |
16 | if (item.Properties.Count > 0) 17 | { 18 | 19 | @foreach (var property in item.Properties) 20 | { 21 | 22 | @if (property.Key != "Stream") 23 | { 24 | 25 | 26 | } 27 | else if (property.Value != null) 28 | { 29 | 30 | } 31 | 32 | } 33 |
@property.Key@property.Value
34 |
35 | } 36 | } 37 | } 38 | else 39 | { 40 |

@Resource.No_Results

41 | } 42 | } 43 |
44 |
45 |
46 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Web.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 | -------------------------------------------------------------------------------- /source/Views/Web.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 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/Views/Help/DisplayTemplates/HelpPageApiModel.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Web.Http 2 | @using System.Web.Http.Description 3 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.Models 4 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions 5 | @model HelpPageApiModel 6 | 7 | @{ 8 | ApiDescription description = Model.ApiDescription; 9 | } 10 |

@description.HttpMethod.Method @description.RelativePath

11 |
12 |

@description.Documentation

13 | 14 |

Request Information

15 | 16 |

URI Parameters

17 | @Html.DisplayFor(m => m.UriParameters, "Parameters") 18 | 19 |

Body Parameters

20 | 21 |

@Model.RequestDocumentation

22 | 23 | @if (Model.RequestModelDescription != null) 24 | { 25 | @Html.DisplayFor(m => m.RequestModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.RequestModelDescription }) 26 | if (Model.RequestBodyParameters != null) 27 | { 28 | @Html.DisplayFor(m => m.RequestBodyParameters, "Parameters") 29 | } 30 | } 31 | else 32 | { 33 |

None.

34 | } 35 | 36 | @if (Model.SampleRequests.Count > 0) 37 | { 38 |

Request Formats

39 | @Html.DisplayFor(m => m.SampleRequests, "Samples") 40 | } 41 | 42 |

Response Information

43 | 44 |

Resource Description

45 | 46 |

@description.ResponseDescription.Documentation

47 | 48 | @if (Model.ResourceDescription != null) 49 | { 50 | @Html.DisplayFor(m => m.ResourceDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.ResourceDescription }) 51 | if (Model.ResourceProperties != null) 52 | { 53 | @Html.DisplayFor(m => m.ResourceProperties, "Parameters") 54 | } 55 | } 56 | else 57 | { 58 |

None.

59 | } 60 | 61 | @if (Model.SampleResponses.Count > 0) 62 | { 63 |

Response Formats

64 | @Html.DisplayFor(m => m.SampleResponses, "Samples") 65 | } 66 | 67 |
-------------------------------------------------------------------------------- /source/Utils/MSALAccount.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Identity.Client; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect 7 | { 8 | /// 9 | /// An MSAL IAccount implementation 10 | /// 11 | /// 12 | internal class MSALAccount : IAccount 13 | { 14 | public string Username { get; set; } 15 | 16 | public string Environment { get; set; } 17 | 18 | public AccountId HomeAccountId { get; set; } 19 | 20 | internal MSALAccount() 21 | { 22 | this.HomeAccountId = new AccountId(string.Empty, string.Empty, string.Empty); 23 | } 24 | public MSALAccount(string identifier, string objectId, string tenantId) 25 | { 26 | this.HomeAccountId = new AccountId(identifier, objectId, tenantId); 27 | } 28 | 29 | public override bool Equals(Object obj) 30 | { 31 | //Check for null and compare run-time types. 32 | if ((obj == null) || !this.GetType().Equals(obj.GetType())) 33 | { 34 | return false; 35 | } 36 | else 37 | { 38 | MSALAccount other = obj as MSALAccount; 39 | 40 | return (this.Environment == other.Environment) 41 | && (this.Username == other.Username) 42 | && (this.HomeAccountId.Identifier == other.HomeAccountId.Identifier) 43 | && (this.HomeAccountId.ObjectId == other.HomeAccountId.ObjectId) 44 | && (this.HomeAccountId.TenantId == other.HomeAccountId.TenantId); 45 | } 46 | } 47 | 48 | /// 49 | /// Serves as a hash function for a particular type. 50 | /// 51 | /// 52 | /// A hash code for the current Address. 53 | /// 54 | public override int GetHashCode() 55 | { 56 | return (this.GetType().FullName + this.Username.ToString() + this.Environment.ToString()).GetHashCode(); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /Node/SampleApp/auth/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Login 4 | 5 | 45 | 46 | 47 | 48 |
49 |

Task Tracker

50 |
51 |
52 | 55 |
56 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /source/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 3 | @using Resources 4 | 5 | 6 | 7 | 8 | 9 | @ViewBag.Title 10 | @Styles.Render("~/Content/css") 11 | @Styles.Render("https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css") 12 | @Styles.Render("https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap-theme.min.css") 13 | @Scripts.Render("https://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.6.2.js") 14 | 15 | 16 | 35 |
36 | @RenderBody() 37 |
38 |
39 |

© @DateTime.Now.Year - @ViewBag.Title

40 |
41 |
42 | @Scripts.Render("https://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.2.3.min.js") 43 | @Scripts.Render("https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js") 44 | @RenderSection("scripts", required: false) 45 | 46 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/Controllers/HelpController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Http; 3 | using System.Web.Mvc; 4 | using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.ModelDescriptions; 5 | using Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.Models; 6 | 7 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.Controllers 8 | { 9 | /// 10 | /// The controller that will handle requests for the help page. 11 | /// 12 | public class HelpController : Controller 13 | { 14 | private const string ErrorViewName = "Error"; 15 | 16 | public HelpController() 17 | : this(GlobalConfiguration.Configuration) 18 | { 19 | } 20 | 21 | public HelpController(HttpConfiguration config) 22 | { 23 | Configuration = config; 24 | } 25 | 26 | public HttpConfiguration Configuration { get; private set; } 27 | 28 | public ActionResult Index() 29 | { 30 | ViewBag.DocumentationProvider = Configuration.Services.GetDocumentationProvider(); 31 | return View(Configuration.Services.GetApiExplorer().ApiDescriptions); 32 | } 33 | 34 | public ActionResult Api(string apiId) 35 | { 36 | if (!String.IsNullOrEmpty(apiId)) 37 | { 38 | HelpPageApiModel apiModel = Configuration.GetHelpPageApiModel(apiId); 39 | if (apiModel != null) 40 | { 41 | return View(apiModel); 42 | } 43 | } 44 | 45 | return View(ErrorViewName); 46 | } 47 | 48 | public ActionResult ResourceModel(string modelName) 49 | { 50 | if (!String.IsNullOrEmpty(modelName)) 51 | { 52 | ModelDescriptionGenerator modelDescriptionGenerator = Configuration.GetModelDescriptionGenerator(); 53 | ModelDescription modelDescription; 54 | if (modelDescriptionGenerator.GeneratedModels.TryGetValue(modelName, out modelDescription)) 55 | { 56 | return View(modelDescription); 57 | } 58 | } 59 | 60 | return View(ErrorViewName); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /source/Utils/Globals.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Configuration; 6 | 7 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect 8 | { 9 | public static class Globals 10 | { 11 | public const string ConsumerTenantId = "9188040d-6c67-4c5b-b112-36a304b66dad"; 12 | public const string IssuerClaim = "iss"; 13 | public const string Authority = "https://login.microsoftonline.com/common/v2.0/"; 14 | public const string TenantIdClaimType = "http://schemas.microsoft.com/identity/claims/tenantid"; 15 | public const string MicrosoftGraphGroupsApi = "https://graph.microsoft.com/v1.0/groups"; 16 | public const string MicrosoftGraphUsersApi = "https://graph.microsoft.com/v1.0/users"; 17 | public const string AdminConsentFormat = "https://login.microsoftonline.com/{0}/adminconsent?client_id={1}&state={2}&redirect_uri={3}"; 18 | public const string BasicSignInScopes = "openid profile email offline_access user.readbasic.all"; 19 | public const string NameClaimType = "name"; 20 | 21 | /// 22 | /// The Client ID is used by the application to uniquely identify itself to Azure AD. 23 | /// 24 | public static string ClientId { get; } = ConfigurationManager.AppSettings["ida:AppId"]; 25 | 26 | /// 27 | /// The ClientSecret is a credential used to authenticate the application to Azure AD. Azure AD supports password and certificate credentials. 28 | /// 29 | public static string ClientSecret { get; } = ConfigurationManager.AppSettings["ida:AppSecret"]; 30 | 31 | /// 32 | /// Redirect URI 33 | /// 34 | public static string RedirectUri { get; } = ConfigurationManager.AppSettings["ida:RedirectUri"]; 35 | 36 | /// 37 | /// The Post Logout Redirect Uri is the URL where the user will be redirected after they sign out. 38 | /// 39 | public static string PostLogoutRedirectUri { get; } = ConfigurationManager.AppSettings["ida:PostLogoutRedirectUri"]; 40 | 41 | /// 42 | /// The TenantId is the DirectoryId of the Azure AD tenant being used in the sample 43 | /// 44 | public static string TenantId { get; } = ConfigurationManager.AppSettings["ida:TenantId"]; 45 | } 46 | } -------------------------------------------------------------------------------- /source/AuthProvider/AuthProvider.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. 3 | * See LICENSE in the source repository root for complete license information. 4 | */ 5 | 6 | using Microsoft.Identity.Client; 7 | using Microsoft.Owin.Security; 8 | using Microsoft.Owin.Security.OpenIdConnect; 9 | using System; 10 | using System.Configuration; 11 | using System.Security.Claims; 12 | using System.Threading.Tasks; 13 | using System.Web; 14 | using Resources; 15 | using Microsoft_Teams_Graph_RESTAPIs_Connect.ImportantFiles; 16 | 17 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Auth 18 | { 19 | public sealed class AuthProvider : IAuthProvider 20 | { 21 | 22 | // Properties used to get and manage an access token. 23 | private string redirectUri = ServiceHelper.RedirectUri; 24 | private string appId = ServiceHelper.AppId; 25 | private string appSecret = ServiceHelper.AppSecret; 26 | private string scopes = ServiceHelper.Scopes; 27 | 28 | private static readonly AuthProvider instance = new AuthProvider(); 29 | private AuthProvider() { } 30 | 31 | public static AuthProvider Instance 32 | { 33 | get 34 | { 35 | return instance; 36 | } 37 | } 38 | 39 | // Get an access token. First tries to get the token from the token cache. 40 | public async Task GetUserAccessTokenAsync() 41 | { 42 | string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value; 43 | IConfidentialClientApplication cc = MsalAppBuilder.BuildConfidentialClientApplication(); 44 | 45 | try 46 | { 47 | string[] scopes = ServiceHelper.Scopes.Split(new char[] { ' ' }); 48 | AuthenticationResult result = await cc.AcquireTokenSilent(scopes, ClaimsPrincipal.Current.ToIAccount()).ExecuteAsync(); 49 | return result.AccessToken; 50 | } 51 | 52 | // Unable to retrieve the access token silently. 53 | catch (MsalUiRequiredException) 54 | { 55 | HttpContext.Current.Request.GetOwinContext().Authentication.Challenge( 56 | new AuthenticationProperties() { RedirectUri = "/" }, 57 | OpenIdConnectAuthenticationDefaults.AuthenticationType); 58 | 59 | throw new Exception(Resource.Error_AuthChallengeNeeded); 60 | } 61 | } 62 | 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /source/Areas/HelpPage/HelpPage.css: -------------------------------------------------------------------------------- 1 | .help-page h1, 2 | .help-page .h1, 3 | .help-page h2, 4 | .help-page .h2, 5 | .help-page h3, 6 | .help-page .h3, 7 | #body.help-page, 8 | .help-page-table th, 9 | .help-page-table pre, 10 | .help-page-table p { 11 | font-family: "Segoe UI Light", Frutiger, "Frutiger Linotype", "Dejavu Sans", "Helvetica Neue", Arial, sans-serif; 12 | } 13 | 14 | .help-page pre.wrapped { 15 | white-space: -moz-pre-wrap; 16 | white-space: -pre-wrap; 17 | white-space: -o-pre-wrap; 18 | white-space: pre-wrap; 19 | } 20 | 21 | .help-page .warning-message-container { 22 | margin-top: 20px; 23 | padding: 0 10px; 24 | color: #525252; 25 | background: #EFDCA9; 26 | border: 1px solid #CCCCCC; 27 | } 28 | 29 | .help-page-table { 30 | width: 100%; 31 | border-collapse: collapse; 32 | text-align: left; 33 | margin: 0px 0px 20px 0px; 34 | border-top: 1px solid #D4D4D4; 35 | } 36 | 37 | .help-page-table th { 38 | text-align: left; 39 | font-weight: bold; 40 | border-bottom: 1px solid #D4D4D4; 41 | padding: 5px 6px 5px 6px; 42 | } 43 | 44 | .help-page-table td { 45 | border-bottom: 1px solid #D4D4D4; 46 | padding: 10px 8px 10px 8px; 47 | vertical-align: top; 48 | } 49 | 50 | .help-page-table pre, 51 | .help-page-table p { 52 | margin: 0px; 53 | padding: 0px; 54 | font-family: inherit; 55 | font-size: 100%; 56 | } 57 | 58 | .help-page-table tbody tr:hover td { 59 | background-color: #F3F3F3; 60 | } 61 | 62 | .help-page a:hover { 63 | background-color: transparent; 64 | } 65 | 66 | .help-page .sample-header { 67 | border: 2px solid #D4D4D4; 68 | background: #00497E; 69 | color: #FFFFFF; 70 | padding: 8px 15px; 71 | border-bottom: none; 72 | display: inline-block; 73 | margin: 10px 0px 0px 0px; 74 | } 75 | 76 | .help-page .sample-content { 77 | display: block; 78 | border-width: 0; 79 | padding: 15px 20px; 80 | background: #FFFFFF; 81 | border: 2px solid #D4D4D4; 82 | margin: 0px 0px 10px 0px; 83 | } 84 | 85 | .help-page .api-name { 86 | width: 40%; 87 | } 88 | 89 | .help-page .api-documentation { 90 | width: 60%; 91 | } 92 | 93 | .help-page .parameter-name { 94 | width: 20%; 95 | } 96 | 97 | .help-page .parameter-documentation { 98 | width: 40%; 99 | } 100 | 101 | .help-page .parameter-type { 102 | width: 20%; 103 | } 104 | 105 | .help-page .parameter-annotations { 106 | width: 20%; 107 | } 108 | 109 | .help-page h1, 110 | .help-page .h1 { 111 | font-size: 36px; 112 | line-height: normal; 113 | } 114 | 115 | .help-page h2, 116 | .help-page .h2 { 117 | font-size: 24px; 118 | } 119 | 120 | .help-page h3, 121 | .help-page .h3 { 122 | font-size: 20px; 123 | } 124 | 125 | #body.help-page { 126 | font-size: 14px; 127 | line-height: 143%; 128 | color: #333; 129 | } 130 | 131 | .help-page a { 132 | color: #0000EE; 133 | text-decoration: none; 134 | } 135 | -------------------------------------------------------------------------------- /source/Views/MyExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Web; 6 | using System.Web.Mvc; 7 | using System.Web.Mvc.Html; 8 | 9 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Views 10 | { 11 | public static class MyExtensionMethods 12 | { 13 | public static MvcHtmlString Concat(this MvcHtmlString first, params MvcHtmlString[] strings) 14 | { 15 | return MvcHtmlString.Create(first.ToString() + string.Concat(strings.Select(s => s.ToString()))); 16 | } 17 | 18 | public static MvcHtmlString MaybeShowLabeledTextBox 19 | (this HtmlHelper htmlHelper, bool show, Expression> member) 20 | { 21 | if (show) 22 | { 23 | return MvcHtmlString.Create("").Concat( 24 | MvcHtmlString.Create(""), 25 | htmlHelper.LabelFor(member), 26 | MvcHtmlString.Create(""), 27 | MvcHtmlString.Create(""), 28 | htmlHelper.TextBoxFor(member), 29 | MvcHtmlString.Create(""), 30 | MvcHtmlString.Create("") 31 | ); 32 | } 33 | return MvcHtmlString.Empty; 34 | } 35 | 36 | public static MvcHtmlString MaybeShowDropdown 37 | (this HtmlHelper htmlHelper, bool show, IEnumerable items, 38 | Func member1, Func member2, Expression> selection) 39 | { 40 | if (show) 41 | { 42 | var listitems = items.Select(t => new SelectListItem() { Text = member1(t), Value = member2(t) }); 43 | return MvcHtmlString.Create("").Concat( 44 | MvcHtmlString.Create(""), 45 | htmlHelper.LabelFor(selection), 46 | MvcHtmlString.Create(""), 47 | MvcHtmlString.Create(""), 48 | htmlHelper.DropDownListFor(selection, listitems), 49 | MvcHtmlString.Create(""), 50 | MvcHtmlString.Create("") 51 | ); 52 | } 53 | return MvcHtmlString.Empty; 54 | } 55 | 56 | 57 | public static MvcHtmlString MaybeShowResultsTable 58 | (this HtmlHelper htmlHelper, bool show, IEnumerable items, 59 | Func member1, Func member2) 60 | { 61 | if (show) 62 | { 63 | var listitems = items.Select(t => new SelectListItem() { Text = member1(t), Value = member2(t) }); 64 | return MvcHtmlString.Create("
").Concat( 65 | htmlHelper.Partial("_ResultsTable", listitems) 66 | ); 67 | } 68 | return MvcHtmlString.Empty; 69 | } 70 | 71 | } 72 | } -------------------------------------------------------------------------------- /source/Views/Home/Graph.cshtml: -------------------------------------------------------------------------------- 1 | 3 | @using Resources 4 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Models; 5 | @using Microsoft_Teams_Graph_RESTAPIs_Connect.Views; 6 | @using System.Linq.Expressions; 7 | 8 | @model FormOutput 9 | 10 |

@Resource.App_Name

11 |

Choose operation:

12 | 13 | @if (!GraphAPI.Web.Controllers.HomeController.hasAppId) 14 | { 15 |
You need to register this application and provide an app secret, see README.md for details.
16 | } 17 | 18 |
19 | @Html.ActionLink("Get My Teams", "GetTeamsAction", "Home")
20 | @Html.ActionLink("Get Channels", "GetChannelsForm", "Home")
21 | @Html.ActionLink("Get Apps", "GetAppsForm", "Home")
22 | 23 | @Html.ActionLink("Create Channel", "PostChannelsForm", "Home")
24 | @Html.ActionLink("Post Message", "PostMessageForm", "Home")
25 | 26 | @Html.ActionLink("Create Team and Group", "PostGroupForm", "Home")
27 | @Html.ActionLink("Add Team to Group", "AddTeamToGroupForm", "Home")
28 | 29 | @Html.ActionLink("Add Member", "AddMemberForm", "Home")
30 | @Html.ActionLink("Update Team", "UpdateTeamForm", "Home")
31 | 32 |
33 |
34 | 35 | 36 | @using (Html.BeginForm(Model.Action, "Home")) 37 | { 38 | @Html.MaybeShowResultsTable(Model.ShowTeamOutput, Model.Teams, t => t.displayName, t => t.id); 39 | @Html.MaybeShowResultsTable(Model.ShowChannelOutput, Model.Channels, t => t.displayName, t => t.id); 40 | 41 | 42 | @Html.MaybeShowDropdown(Model.ShowTeamDropdown, Model.Teams, t => t.displayName, t => t.id, m => m.SelectedTeam) 43 | @Html.MaybeShowDropdown(Model.ShowGroupDropdown, Model.Groups, t => t.displayName, t => t.id, m => m.SelectedGroup) 44 | @Html.MaybeShowLabeledTextBox(Model.ShowChannelDropdown, m => m.SelectedChannel) 45 | 46 | @*if (Model.ShowChannelDropdown) 47 | { 48 | @Html.LabelFor(m => m.SelectedChannel) 49 | @Html.DropDownListFor(m => m.SelectedChannel, Model.ChannelItems) 50 | //@Html.TextBoxFor(m => m.SelectedChannel); 51 | }*@ 52 | 53 | @Html.MaybeShowLabeledTextBox(Model.ShowNameInput, m => m.NameInput) 54 | @Html.MaybeShowLabeledTextBox(Model.ShowDisplayNameInput, m => m.DisplayNameInput) 55 | @Html.MaybeShowLabeledTextBox(Model.ShowDescriptionInput, m => m.DescriptionInput) 56 | @Html.MaybeShowLabeledTextBox(Model.ShowMailNicknameInput, m => m.MailNicknameInput) 57 | 58 | @Html.MaybeShowResultsTable(Model.ShowAppOutput, Model.Apps, t => t.name, t => t.id) 59 | @Html.MaybeShowDropdown(Model.ShowAppDropdown, Model.Apps, t => t.name, t => t.id, m => m.SelectedApp) 60 | 61 | @Html.MaybeShowLabeledTextBox(Model.ShowUpnInput, m => m.UpnInput) 62 | 63 | @Html.MaybeShowLabeledTextBox(Model.ShowMessageBodyInput, m => m.MessageBodyInput) 64 |
65 | 66 | if (Model.ButtonLabel != null) 67 | { 68 | 69 | } 70 | if (Model.SuccessMessage != null) 71 | { 72 |
@Model.SuccessMessage
73 | } 74 | } 75 | 76 | 84 | -------------------------------------------------------------------------------- /source/Models/ResultsViewModel.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. 3 | * See LICENSE in the source repository root for complete license information. 4 | */ 5 | 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using System.ComponentModel.DataAnnotations; 10 | using System.Linq; 11 | using System.Web.Mvc; 12 | 13 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Models 14 | { 15 | // View model to display a collection of one or more entities returned from the Microsoft Graph. 16 | public class ResultsViewModel 17 | { 18 | // The list of entities to display. 19 | public IEnumerable Items { get; set; } 20 | public ResultsViewModel() 21 | { 22 | Items = Enumerable.Empty(); 23 | } 24 | } 25 | 26 | public class FormOutput 27 | { 28 | // input: team, channel, app, clone params, input text, user id 29 | // groups: displayName, mailNickname, description, visibility 30 | 31 | public string Action { get; set; } 32 | public string ButtonLabel { get; set; } 33 | 34 | public string UserUpn { get; set; } // aka /me 35 | 36 | [Display(Name = "Name")] 37 | public string NameInput { get; set; } 38 | 39 | [Display(Name = "Description")] 40 | public string DescriptionInput { get; set; } 41 | 42 | [Display(Name = "Message Body")] 43 | public string MessageBodyInput { get; set; } 44 | 45 | [Display(Name = "Display Name")] 46 | public String DisplayNameInput { get; set; } 47 | 48 | [Display(Name = "Mail Nickname")] 49 | public String MailNicknameInput { get; set; } 50 | 51 | public string SuccessMessage { get; set; } 52 | 53 | // Team list 54 | 55 | public bool ShowTeamOutput { get; set; } = false; 56 | public bool ShowTeamDropdown { get; set; } = false; 57 | public bool ShowGroupDropdown { get; set; } = false; 58 | 59 | public Team[] Teams { get; set; } // output 60 | public Group[] Groups { get; set; } // output 61 | 62 | [Display(Name = "Team")] 63 | public string SelectedTeam { get; set; } // input 64 | [Display(Name = "Group")] 65 | public string SelectedGroup { get; set; } // input 66 | 67 | 68 | // Group/team create 69 | public bool ShowDisplayNameInput { get; set; } = false; 70 | public bool ShowMailNicknameInput { get; set; } = false; 71 | 72 | 73 | // Channel list 74 | 75 | public bool ShowChannelOutput { get; set; } = false; 76 | public bool ShowChannelDropdown { get; set; } = false; 77 | public bool ShowNameInput { get; set; } = false; 78 | public bool ShowDescriptionInput { get; set; } = false; 79 | public bool ShowMessageBodyInput { get; set; } = false; 80 | 81 | public Channel[] Channels { get; set; } // output 82 | 83 | [Display(Name = "Channel")] 84 | public string SelectedChannel{ get; set; } // input 85 | 86 | // app list 87 | 88 | public bool ShowAppOutput { get; set; } = false; 89 | public bool ShowAppDropdown { get; set; } = false; 90 | 91 | public TeamsApp[] Apps { get; set; } // output 92 | 93 | [Display(Name = "User principal name")] 94 | public string UpnInput { get; set; } 95 | public bool ShowUpnInput { get; set; } = false; 96 | 97 | [Display(Name = "App")] 98 | public string SelectedApp { get; set; } // input 99 | } 100 | } -------------------------------------------------------------------------------- /README-localized/README-zh-cn.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | products: 4 | - office-teams 5 | - ms-graph 6 | languages: 7 | - csharp 8 | extensions: 9 | contentType: samples 10 | technologies: 11 | - Microsoft Graph 12 | services: 13 | - Microsoft Teams 14 | createdDate: 5/30/2017 6:00:04 PM 15 | --- 16 | # Microsoft Teams Graph API 示例 17 | 18 | 此示例含有调用许多 Teams Graph API 的例,包括: 19 | 20 | * 获取我的团队 21 | * 获取频道 22 | * 获取应用程序 23 | * 创建频道 24 | * 发布消息 25 | * 创建团队和组 26 | * 添加团队至组 27 | * 添加成员至团队 28 | * 更新团队设置 29 | 30 | ## 相关示例 31 | 32 | * [Microsoft Teams Contoso 航空示例](https://github.com/microsoftgraph/contoso-airlines-teams-sample) 33 | * [Microsoft Teams Graph API 节点版本示例](https://github.com/OfficeDev/microsoft-teams-sample-graph/tree/master/Node/SampleApp) 34 | 35 | > 有关 Microsoft Teams 开发应用程序的详细信息,请参阅 Microsoft Teams [开发人员文档](https://msdn.microsoft.com/en-us/microsoft-teams/index)。\** 36 | 37 | ## 先决条件 38 | 39 | ### 具有管理员权限的 O365 账户 40 | 41 | 如果要设置此应用,用户需要是全局管理员,因为只有全局管理员才能许可应用程序使用 Group.ReadWrite.All 等权限。考虑通过使用 [Office 365 开发人员计划](https://dev.office.com/devprogram)创建开发人员账户来创建自己的测试租户。 42 | 43 | ### 已注册的应用 44 | 45 | 需要通过下列流程注册应用程序: 46 | 47 | 1. 使用工作/学校帐户或 Microsoft 个人帐户登录到 [Azure 门户](https://go.microsoft.com/fwlink/?linkid=2083908)。 48 | 2. 如果你的帐户有权访问多个租户,请在右上角选择该帐户,并将门户会话设置为所需的 Azure AD 租户。 49 | 3. 选择“**新注册**”。 50 | 4. 出现“注册应用程序页”后,输入应用程序的注册信息: 51 | * **名称** \- 输入一个会显示给应用用户的有意义的应用程序名称。 52 | * **支持的帐户类型** \- 选择希望应用程序支持的具体帐户。 53 | * **重定向 URI (可选)** \- 选择 **Web**并为**重定向 URI** 输入 'http://localhost:55065/'。 54 | 5. 完成后,选择“**注册**”。 55 | 6. Azure AD 会将唯一的应用程序(客户端)ID 分配给应用,同时你会转到应用程序的“概览”页。若要向应用程序添加其他功能,可选择品牌、证书和机密、API 权限等其他配置选项。 56 | 57 | 复制应用程序 ID。这是应用的唯一标识符。 58 | 7. 在左窗格的“**管理**”下,单击“**证书和密码**”。在“**客户端密码**”下,单击“**新建客户端密码**”。输入说明和到期日期,然后单击“**添加**”。此操作将创建密码字符串,或应用密码,用于应用程序验证其身份。 59 | 60 | 从新密码复制数值。 61 | 8. 在左窗格的“**管理**”下,单击“**身份验证**”。在“**隐式授权**”下,选中“**访问令牌**”和“**ID 令牌**”。在身份验证过程中,这可使应用同时接收登录信息 (id\_token) 以及应用可用来获取访问令牌的项目(在这种情况下,项目为授权代码)。保存所做的更改。 62 | 9. 在左窗格的“**管理**”下,单击“**API 权限**”, 然后“**添加新权限**”。选择“**Microsoft Graph**”,然后选择“**委派权限**”。添加 “Group.ReadWrite.All” (读取和写入所有组)和“User.ReadWrite.Al”(读取和写入全部用户的完整配置文件)权限。再次单击“**添加新权限**”,然后单击“**应用程序权限**”。添加 “Group.ReadWrite.All” (读取和写入所有组)和“User.ReadWrite.Al”(读取和写入全部用户的完整配置文件)权限。 63 | 64 | 查看各项目自述文件了解更多信息。 65 | 66 | ### 生成并运行示例应用 67 | 68 | 1. 在 Visual Studio 中打开示例解决方案。 69 | 2. 从上一节获取应用 ID 和应用密码 70 | 3. 创建名为 Web.config 的文件(将其放在 web.config 旁),并添加到 应用 ID 和应用密码中: 71 | 72 | ``` 73 | 74 | 75 | 76 | 77 | 78 | ``` 79 | 80 | 4. 使用已注册应用的“ida:RedirectUri”更新 Web 应用程序的 “Web 服务器” 81 | 82 | * 在解决方案资源管理器中,右击要为其指定 Web 服务器的 Web 应用程序项目的名称,然后单击“属性”。 83 | * 在“属性”窗口中单击“Web”选项卡。 84 | * 在“服务器”下,使用已注册应用程序的“ida:RedirectUri”更新“项目 Url”。 85 | * 单击“创建虚拟目录” 86 | * 保存文件。 87 | 88 | 5. 生成和运行示例。 89 | 90 | 6. 使用账户登录,并授予请求的权限。 91 | 92 | * 注意:需要具有相应的提升的权限才能运行应用(Group.ReadWrite.All 和 User.ReadWrite.All) 93 | 94 | 7. 选择操作,如“获取我的团队”、“获取频道”、“创建频道”或“发布消息”。 95 | 96 | 8. 响应信息将在页面底部显示。 97 | 98 | ## 反馈 99 | 100 | 欢迎提供反馈信息![下面介绍如何向我们发送反馈](https://msdn.microsoft.com/en-us/microsoft-teams/feedback)。 101 | 102 | ## Microsoft 开放源代码行为准则 103 | 104 | 此项目已采用 [Microsoft 开放源代码行为准则](https://opensource.microsoft.com/codeofconduct/)。有关详细信息,请参阅[行为准则 FAQ](https://opensource.microsoft.com/codeofconduct/faq/)。如有其他任何问题或意见,也可联系 [opencode@microsoft.com](mailto:opencode@microsoft.com)。 105 | 106 | ## 参与 107 | 108 | 请阅读“[参与](contributing.md)”,详细了解我们提交拉取请求的流程。 109 | 110 | ## 许可证 111 | 112 | 此项目使用 MIT 许可证授权 - 参见“[许可证](LICENSE)”文件了解详细信息。 113 | 114 | ## 版权信息 115 | 116 | 版权所有 (c) 2018 Microsoft Corporation。保留所有权利。 117 | -------------------------------------------------------------------------------- /source/Utils/ClaimPrincipalExtension.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Identity.Client; 2 | using System.Security.Claims; 3 | using System.Linq; 4 | 5 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect 6 | { 7 | public static class ClaimsPrincipalExtension 8 | { 9 | /// 10 | /// Get the Account identifier for an MSAL.NET account from a ClaimsPrincipal 11 | /// 12 | /// Claims principal 13 | /// A string corresponding to an account identifier as defined in 14 | public static string GetMsalAccountId(this ClaimsPrincipal claimsPrincipal) 15 | { 16 | string userObjectId = GetObjectId(claimsPrincipal); 17 | string tenantId = GetTenantId(claimsPrincipal); 18 | 19 | if (!string.IsNullOrWhiteSpace(userObjectId) && !string.IsNullOrWhiteSpace(tenantId)) 20 | { 21 | return $"{userObjectId}.{tenantId}"; 22 | } 23 | 24 | return null; 25 | } 26 | 27 | /// 28 | /// Get the unique object ID associated with the claimsPrincipal 29 | /// 30 | /// Claims principal from which to retrieve the unique object id 31 | /// Unique object ID of the identity, or null if it cannot be found 32 | public static string GetObjectId(this ClaimsPrincipal claimsPrincipal) 33 | { 34 | var objIdclaim = claimsPrincipal.FindFirst(ClaimConstants.ObjectId); 35 | 36 | if (objIdclaim == null) 37 | { 38 | objIdclaim = claimsPrincipal.FindFirst("oid"); 39 | } 40 | 41 | return objIdclaim != null ? objIdclaim.Value : string.Empty; 42 | } 43 | 44 | /// 45 | /// Tenant ID of the identity 46 | /// 47 | /// Claims principal from which to retrieve the tenant id 48 | /// Tenant ID of the identity, or null if it cannot be found 49 | public static string GetTenantId(this ClaimsPrincipal claimsPrincipal) 50 | { 51 | var tenantIdclaim = claimsPrincipal.FindFirst(ClaimConstants.TenantId); 52 | 53 | if (tenantIdclaim == null) 54 | { 55 | tenantIdclaim = claimsPrincipal.FindFirst("tid"); 56 | } 57 | 58 | return tenantIdclaim != null ? tenantIdclaim.Value : string.Empty; 59 | } 60 | 61 | public static IAccount ToIAccount(this ClaimsPrincipal claimsPrincipal) 62 | { 63 | if (claimsPrincipal != null) 64 | { 65 | return new MSALAccount(claimsPrincipal.GetMsalAccountId(), claimsPrincipal.GetObjectId(), claimsPrincipal.GetTenantId()); 66 | } 67 | return null; 68 | } 69 | 70 | /// 71 | /// Builds a ClaimsPrincipal from an IAccount 72 | /// 73 | /// The IAccount instance. 74 | /// A ClaimsPrincipal built from IAccount 75 | public static ClaimsPrincipal ToClaimsPrincipal(this IAccount account) 76 | { 77 | if (account != null) 78 | { 79 | var identity = new ClaimsIdentity(); 80 | identity.AddClaim(new Claim(ClaimConstants.ObjectId, account.HomeAccountId.ObjectId)); 81 | identity.AddClaim(new Claim(ClaimConstants.TenantId, account.HomeAccountId.TenantId)); 82 | identity.AddClaim(new Claim(ClaimTypes.Upn, account.Username)); 83 | return new ClaimsPrincipal(identity); 84 | } 85 | 86 | return null; 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /Node/SampleApp/graph/sendmessage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sample app for Microsoft Teams APIs in Microsoft Graph 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 |
15 |

Choose team:

16 |
17 |
18 |
19 |

Choose channel:

20 |
21 |
22 |
23 |

Send message:

24 |
25 |
26 |
27 | 28 |
29 | 30 |
31 |
32 |
Sent successfully!
33 |
34 | 35 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /source/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 | -------------------------------------------------------------------------------- /source/Scripts/respond.min.js: -------------------------------------------------------------------------------- 1 | /*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl 2 | * Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT 3 | * */ 4 | 5 | !function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='­',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b 10 | /// The model that represents an API displayed on the help page. 11 | /// 12 | public class HelpPageApiModel 13 | { 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | public HelpPageApiModel() 18 | { 19 | UriParameters = new Collection(); 20 | SampleRequests = new Dictionary(); 21 | SampleResponses = new Dictionary(); 22 | ErrorMessages = new Collection(); 23 | } 24 | 25 | /// 26 | /// Gets or sets the that describes the API. 27 | /// 28 | public ApiDescription ApiDescription { get; set; } 29 | 30 | /// 31 | /// Gets or sets the collection that describes the URI parameters for the API. 32 | /// 33 | public Collection UriParameters { get; private set; } 34 | 35 | /// 36 | /// Gets or sets the documentation for the request. 37 | /// 38 | public string RequestDocumentation { get; set; } 39 | 40 | /// 41 | /// Gets or sets the that describes the request body. 42 | /// 43 | public ModelDescription RequestModelDescription { get; set; } 44 | 45 | /// 46 | /// Gets the request body parameter descriptions. 47 | /// 48 | public IList RequestBodyParameters 49 | { 50 | get 51 | { 52 | return GetParameterDescriptions(RequestModelDescription); 53 | } 54 | } 55 | 56 | /// 57 | /// Gets or sets the that describes the resource. 58 | /// 59 | public ModelDescription ResourceDescription { get; set; } 60 | 61 | /// 62 | /// Gets the resource property descriptions. 63 | /// 64 | public IList ResourceProperties 65 | { 66 | get 67 | { 68 | return GetParameterDescriptions(ResourceDescription); 69 | } 70 | } 71 | 72 | /// 73 | /// Gets the sample requests associated with the API. 74 | /// 75 | public IDictionary SampleRequests { get; private set; } 76 | 77 | /// 78 | /// Gets the sample responses associated with the API. 79 | /// 80 | public IDictionary SampleResponses { get; private set; } 81 | 82 | /// 83 | /// Gets the error messages associated with this model. 84 | /// 85 | public Collection ErrorMessages { get; private set; } 86 | 87 | private static IList GetParameterDescriptions(ModelDescription modelDescription) 88 | { 89 | ComplexTypeModelDescription complexTypeModelDescription = modelDescription as ComplexTypeModelDescription; 90 | if (complexTypeModelDescription != null) 91 | { 92 | return complexTypeModelDescription.Properties; 93 | } 94 | 95 | CollectionModelDescription collectionModelDescription = modelDescription as CollectionModelDescription; 96 | if (collectionModelDescription != null) 97 | { 98 | complexTypeModelDescription = collectionModelDescription.ElementDescription as ComplexTypeModelDescription; 99 | if (complexTypeModelDescription != null) 100 | { 101 | return complexTypeModelDescription.Properties; 102 | } 103 | } 104 | 105 | return null; 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /Node/SampleApp/auth/authHelper.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. 3 | * See LICENSE in the project root for license information. 4 | */ 5 | 6 | // This sample uses an open source OAuth 2.0 library that is compatible 7 | // with the Azure AD v2.0 endpoint. 8 | // Microsoft does not provide fixes or direct support for this library. 9 | // Refer to the library’s repository to file issues or for other support. 10 | // For more information about auth libraries see: https://azure.microsoft.com/documentation/articles/active-directory-v2-libraries/ 11 | // Library repo: https://github.com/ciaranj/node-oauth 12 | 13 | var OAuth = require('oauth'); 14 | var uuid = require('node-uuid'); 15 | 16 | // The application registration (must match Azure AD config) 17 | // If running in cloud, configure details as env variables, otherwise configure them locally. 18 | var credentials = { 19 | authority: 'https://login.microsoftonline.com/common', 20 | authorize_endpoint: '/oauth2/v2.0/authorize', 21 | token_endpoint: '/oauth2/v2.0/token', 22 | client_id: process.env.AUTH_CLIENT_ID, 23 | client_secret: process.env.AUTH_CLIENT_SECRET, 24 | redirect_uri: `${process.env.BASE_URI}/login`, 25 | scope: 'User.ReadWrite.All Group.ReadWrite.All offline_access' 26 | }; 27 | 28 | /** 29 | * Generate a fully formed uri to use for authentication based on the supplied resource argument 30 | * @return {string} a fully formed uri with which authentication can be completed 31 | */ 32 | function getAuthUrl(redirectUrl) { 33 | var authUrl = credentials.authority + credentials.authorize_endpoint + 34 | '?client_id=' + credentials.client_id + 35 | '&response_type=code' + 36 | '&redirect_uri=' + credentials.redirect_uri + 37 | '&scope=' + credentials.scope + 38 | '&response_mode=query' + 39 | '&nonce=' + uuid.v4(); 40 | return authUrl; 41 | } 42 | 43 | /** 44 | * Gets a token for a given resource. 45 | * @param {string} code An authorization code returned from a client. 46 | * @param {AcquireTokenCallback} callback The callback function. 47 | */ 48 | function getTokenFromCode(code, callback) { 49 | var OAuth2 = OAuth.OAuth2; 50 | var oauth2 = new OAuth2( 51 | credentials.client_id, 52 | credentials.client_secret, 53 | credentials.authority, 54 | credentials.authorize_endpoint, 55 | credentials.token_endpoint 56 | ); 57 | 58 | oauth2.getOAuthAccessToken( 59 | code, 60 | { 61 | grant_type: 'authorization_code', 62 | redirect_uri: credentials.redirect_uri, 63 | response_mode: 'form_post', 64 | nonce: uuid.v4(), 65 | state: 'abcd' 66 | }, 67 | function (e, accessToken, refreshToken) { 68 | callback(e, accessToken, refreshToken); 69 | } 70 | ); 71 | } 72 | 73 | /** 74 | * Gets a new access token via a previously issued refresh token. 75 | * @param {string} refreshToken A refresh token returned in a token response 76 | * from a previous result of an authentication flow. 77 | * @param {AcquireTokenCallback} callback The callback function. 78 | */ 79 | function getTokenFromRefreshToken(refreshToken, callback) { 80 | var OAuth2 = OAuth.OAuth2; 81 | var oauth2 = new OAuth2( 82 | credentials.client_id, 83 | credentials.client_secret, 84 | credentials.authority, 85 | credentials.authorize_endpoint, 86 | credentials.token_endpoint 87 | ); 88 | 89 | oauth2.getOAuthAccessToken( 90 | refreshToken, 91 | { 92 | grant_type: 'refresh_token', 93 | redirect_uri: credentials.redirect_uri, 94 | response_mode: 'form_post', 95 | nonce: uuid.v4(), 96 | state: 'abcd' 97 | }, 98 | function (e, accessToken) { 99 | callback(e, accessToken); 100 | } 101 | ); 102 | } 103 | 104 | function hasAccessTokenExpired(e) { 105 | var expired; 106 | if (!e.innerError) { 107 | expired = false; 108 | } else { 109 | expired = e.code === 401 && 110 | e.innerError.code === 'InvalidAuthenticationToken' && 111 | e.innerError.message === 'Access token has expired.'; 112 | } 113 | return expired; 114 | } 115 | 116 | function clearCookies(res) { 117 | res.clearCookie('ACCESS_TOKEN_CACHE_KEY'); 118 | res.clearCookie('REFRESH_TOKEN_CACHE_KEY'); 119 | } 120 | 121 | exports.credentials = credentials; 122 | exports.getAuthUrl = getAuthUrl; 123 | exports.getTokenFromCode = getTokenFromCode; 124 | exports.getTokenFromRefreshToken = getTokenFromRefreshToken; 125 | exports.hasAccessTokenExpired = hasAccessTokenExpired; 126 | exports.clearCookies = clearCookies; 127 | exports.ACCESS_TOKEN_CACHE_KEY = 'ACCESS_TOKEN_CACHE_KEY'; 128 | exports.REFRESH_TOKEN_CACHE_KEY = 'REFRESH_TOKEN_CACHE_KEY'; 129 | -------------------------------------------------------------------------------- /README-localized/README-ja-jp.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | products: 4 | - office-teams 5 | - ms-graph 6 | languages: 7 | - csharp 8 | extensions: 9 | contentType: samples 10 | technologies: 11 | - Microsoft Graph 12 | services: 13 | - Microsoft Teams 14 | createdDate: 5/30/2017 6:00:04 PM 15 | --- 16 | # Microsoft Teams Graph API サンプル 17 | 18 | このサンプルでは、以下の Teams Graph API を呼び出す例を示します。 19 | 20 | * チームを取得する 21 | * チャネルを取得する 22 | * アプリを取得する 23 | * チャネルを作成する 24 | * メッセージを投稿する 25 | * チームとグループを作成する 26 | * チームをグループに追加する 27 | * メンバーをチームに追加する 28 | * チーム設定を変更する 29 | 30 | ## 関連するサンプル 31 | 32 | * [Microsoft Teams を使った Contoso Airlines サンプル](https://github.com/microsoftgraph/contoso-airlines-teams-sample) 33 | * [Microsoft Teams Graph API の Node サンプル](https://github.com/OfficeDev/microsoft-teams-sample-graph/tree/master/Node/SampleApp) 34 | 35 | > Microsoft Teams のアプリ開発の詳細については、Microsoft Teams [開発者向けドキュメント](https://msdn.microsoft.com/en-us/microsoft-teams/index)をご覧ください。 36 | 37 | ## 前提条件 38 | 39 | ### 管理者特権のある O365 アカウント 40 | 41 | このアプリを設定するには、グローバル管理者である必要があります。グローバル管理者のみが Group.ReadWrite.All などのアクセス許可を使用するアプリに同意できるためです。[Office 365 開発者プログラム](https://dev.office.com/devprogram)の開発者アカウントを作成して、自分自身のテスト テナントを作成することを検討してください。 42 | 43 | ### 登録済みのアプリ 44 | 45 | 次の手順に従ってアプリを登録する必要があります。 46 | 47 | 1. 職場または学校のアカウントか、個人の Microsoft アカウントを使用して、[Azure portal](https://go.microsoft.com/fwlink/?linkid=2083908)にサインインします。 48 | 2. ご利用のアカウントで複数のテナントにアクセスできる場合は、右上でアカウントを選択し、ポータルのセッションを目的の Azure AD テナントに設定します。 49 | 3. [**新規登録**] を選択します。 50 | 4. [アプリケーションの登録ページ] が表示されたら、以下のアプリケーションの登録情報を入力します。 51 | * **名前** \- アプリのユーザーに表示されるわかりやすいアプリケーション名を入力します。 52 | * **サポートされているアカウントの種類** \- アプリケーションでサポートするアカウントを選択します。 53 | * **リダイレクト URI (オプション)** \- [**Web**] を選択し、[**リダイレクト URI**] に "http://localhost:55065/" を入力します。 54 | 5. 終了したら、[**登録**] を選択します。 55 | 6. Azure AD によりアプリに一意のアプリケーション (クライアント) ID が割り当てられ、アプリケーションの [概要] ページに移動します。アプリケーションにさらに機能を追加するには、ブランディング、証明書と秘密情報、API アクセス許可など、その他の構成オプションを選択できます。 56 | 57 | アプリケーション ID をコピーします。これは、アプリの一意識別子です。 58 | 7. 左側のペインの [**管理**] で、[**証明書とシークレット**] をクリックします。[**クライアント シークレット**] で、[**新しいクライアント シークレット**] をクリックします。説明と有効期限を入力し、[**追加**] をクリックします。これにより、アプリケーションが ID を証明するために使用する秘密の文字列、またはアプリケーション パスワードが作成されます。 59 | 60 | 新しいシークレットの値をコピーします。 61 | 8. 左側のペインの [**管理**] で、 [**認証**] をクリックします。[**暗黙の付与**] で、[**アクセス トークン**] と [**ID トークン**] を確認します。認証時に、アクセス トークンを取得するためにアプリが使用できるサインイン情報 (id\_token) と成果物 (この場合は、認証コード) の両方をアプリで受信できるようになります。変更内容を保存します。 62 | 9. 左側のペインの [**管理**] で、[**API のアクセス許可**] をクリックして、[**アクセス許可の追加**] をクリックします。[**Microsoft Graph**] を選び、[**委任されたアクセス許可**] を選びます。"Group.ReadWrite.All" (すべてのグループの読み取りと書き込み) アクセス許可と "User.ReadWrite.All" (すべてのユーザーの完全なプロファイルの読み取りと書き込み) アクセス許可を追加します。[**アクセス許可の追加**] をもう一度クリックし、[**アプリケーションのアクセス許可**] をクリックします。"Group.ReadWrite.All" (すべてのグループの読み取りと書き込み) アクセス許可と "User.ReadWrite.All" (すべてのユーザーの完全なプロファイルの読み取りと書き込み) アクセス許可を追加します。 63 | 64 | 詳細については、各プロジェクトの Readme を参照してください。 65 | 66 | ### サンプル アプリのビルドと実行 67 | 68 | 1. サンプル ソリューションを Visual Studio で開きます。 69 | 2. 前のセクションを参照して アプリ ID と アプリ シークレットを取得します。 70 | 3. Web.config と同じ場所に Web.config.secrets という名前のファイルを作成し、アプリ ID とアプリ シークレットを追加します。 71 | 72 | ``` 73 | 74 | 75 | 76 | 77 | 78 | ``` 79 | 80 | 4. 登録済みアプリの "ida:RedirectUri" と同じ値で、Web アプリケーションの "Web サーバー" を更新します。 81 | 82 | * ソリューション エクスプローラーで、Web サーバーを指定する Web アプリケーション プロジェクトの名前を右クリックし、[プロパティ] をクリックします。 83 | * [プロパティ] ウィンドウで、[Web] タブをクリックします。 84 | * [サーバー] で、登録されているアプリの "ida: RedirectUri" と同じ値で "Project Url" を更新します。 85 | * [仮想ディレクトリの作成] をクリックします。 86 | * ファイルを保存します。 87 | 88 | 5. サンプルをビルドして実行します。 89 | 90 | 6. 自分のアカウントでサインインし、要求されたアクセス許可を付与します。 91 | 92 | * アプリケーションを実行するには、適切な管理者権限 (Group.ReadWrite.All と User.ReadWrite.All) を持っている必要があります。 93 | 94 | 7. [チームを取得する]、[チャネルを取得する]、[チャネルを作成する]、[メッセージを投稿する] などの操作を選びます。 95 | 96 | 8. 応答情報は、ページの下部に表示されます。 97 | 98 | ## フィードバック 99 | 100 | フィードバックをお寄せください。[フィードバックの送信方法はこちらです](https://msdn.microsoft.com/en-us/microsoft-teams/feedback)。 101 | 102 | ## Microsoft オープン ソース倫理規定 103 | 104 | このプロジェクトでは、[Microsoft Open Source Code of Conduct (Microsoft オープン ソース倫理規定)](https://opensource.microsoft.com/codeofconduct/) が採用されています。詳細については、「[Code of Conduct の FAQ (倫理規定の FAQ)](https://opensource.microsoft.com/codeofconduct/faq/)」を参照してください。また、その他の質問やコメントがあれば、[opencode@microsoft.com](mailto:opencode@microsoft.com) までお問い合わせください。 105 | 106 | ## 投稿 107 | 108 | プル要求を送信するプロセスの詳細については、「[投稿](contributing.md)」をお読みください。 109 | 110 | ## ライセンス 111 | 112 | このプロジェクトは、MIT ライセンスの下でライセンスされています。詳細については、[ライセンス](LICENSE) ファイルを参照してください。 113 | 114 | ## 著作権 115 | 116 | Copyright (c) 2018 Microsoft Corporation.All rights reserved. 117 | -------------------------------------------------------------------------------- /source/Scripts/respond.matchmedia.addListener.min.js: -------------------------------------------------------------------------------- 1 | /*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl 2 | * Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT 3 | * */ 4 | 5 | !function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='­',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";if(a.matchMedia&&a.matchMedia("all").addListener)return!1;var b=a.matchMedia,c=b("only all").matches,d=!1,e=0,f=[],g=function(){a.clearTimeout(e),e=a.setTimeout(function(){for(var c=0,d=f.length;d>c;c++){var e=f[c].mql,g=f[c].listeners||[],h=b(e.media).matches;if(h!==e.matches){e.matches=h;for(var i=0,j=g.length;j>i;i++)g[i].call(a,e)}}},30)};a.matchMedia=function(e){var h=b(e),i=[],j=0;return h.addListener=function(b){c&&(d||(d=!0,a.addEventListener("resize",g,!0)),0===j&&(j=f.push({mql:h,listeners:i})),i.push(b))},h.removeListener=function(a){for(var b=0,c=i.length;c>b;b++)i[b]===a&&i.splice(b,1)},h}}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b SendRequest(HttpMethod method, String endPoint, string accessToken, dynamic content = null) 52 | { 53 | HttpResponseMessage response = null; 54 | using (var client = new HttpClient()) 55 | { 56 | using (var request = new HttpRequestMessage(method, endPoint)) 57 | { 58 | request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 59 | request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); 60 | if (content != null) 61 | { 62 | string c; 63 | if (content is string) 64 | c = content; 65 | else 66 | c = JsonConvert.SerializeObject(content); 67 | request.Content = new StringContent(c, Encoding.UTF8, "application/json"); 68 | } 69 | 70 | response = await client.SendAsync(request); 71 | } 72 | } 73 | return response; 74 | 75 | } 76 | 77 | 78 | /// 79 | /// Helper function to prepare the ResultsItem list from request response. 80 | /// 81 | /// Request response 82 | /// Property name of the item Id 83 | /// Property name of the item display name 84 | /// 85 | public static async Task> GetResultsItem( 86 | HttpResponseMessage response, string idPropertyName, string displayPropertyName, string resourcePropId) 87 | { 88 | List items = new List(); 89 | 90 | JObject json = JObject.Parse(await response.Content.ReadAsStringAsync()); 91 | foreach (JProperty content in json.Children()) 92 | { 93 | if (content.Name.Equals("value")) 94 | { 95 | var res = content.Value.AsJEnumerable().GetEnumerator(); 96 | res.MoveNext(); 97 | 98 | while (res.Current != null) 99 | { 100 | string display = ""; 101 | string id = ""; 102 | 103 | foreach (JProperty prop in res.Current.Children()) 104 | { 105 | if (prop.Name.Equals(idPropertyName)) 106 | { 107 | id = prop.Value.ToString(); 108 | } 109 | 110 | if (prop.Name.Equals(displayPropertyName)) 111 | { 112 | display = prop.Value.ToString(); 113 | } 114 | } 115 | 116 | items.Add(new ResultsItem 117 | { 118 | Display = display, 119 | Id = id, 120 | Properties = new Dictionary 121 | { 122 | { resourcePropId, id } 123 | } 124 | }); 125 | 126 | res.MoveNext(); 127 | } 128 | } 129 | } 130 | 131 | return items; 132 | } 133 | 134 | } 135 | } -------------------------------------------------------------------------------- /Node/SampleApp/graph/httpsrequesthelper.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. 3 | * See LICENSE in the project root for license information. 4 | */ 5 | var https = require('https'); 6 | var authHelper = require('../auth/authHelper.js'); 7 | 8 | /** 9 | * Execute HTTPS request to the specified path, handling errors 10 | * @param req Incoming user request context 11 | * @param res Outgoing response context 12 | * @param next Next route handler context 13 | * @param {string} requestType the HTTPS request type 14 | * @param {string} requestPath the resource path to which to send the request 15 | * @param {callback} callback with data successfully retrieved. 16 | */ 17 | function executeRequestWithErrorHandling(req, res, next, requestType, requestPath, callback) { 18 | if (req.cookies.REFRESH_TOKEN_CACHE_KEY === undefined) { 19 | res.redirect(`/login?${process.env.host}&${process.env.ClientSecret}&${process.env.APPSETTING_ClientSecret}&${process.env.WEBSITE_HOSTNAME}`, next); 20 | } 21 | else 22 | { 23 | //Step 1. Attempt the request 24 | executeHttpsRequest( 25 | requestType, 26 | requestPath, 27 | req.body, 28 | req.cookies.ACCESS_TOKEN_CACHE_KEY, 29 | function (firstRequestError, data) { 30 | if (!firstRequestError) { 31 | //Success. Return data. 32 | callback(data); 33 | } else if (authHelper.hasAccessTokenExpired(firstRequestError)) { 34 | //Step 2. Request didn't work because access token expired. Handle the refresh flow 35 | authHelper.getTokenFromRefreshToken( 36 | req.cookies.REFRESH_TOKEN_CACHE_KEY, 37 | function (refreshError, accessToken) { 38 | res.setCookie(authHelper.ACCESS_TOKEN_CACHE_KEY, accessToken); 39 | if (accessToken !== null) { 40 | //Step 3. Got a new access token. Attempt the request again. 41 | executeHttpsRequest( 42 | requestType, 43 | requestPath, 44 | req.body, 45 | accessToken, 46 | function (secondRequestError, data) { 47 | if (!secondRequestError) { 48 | //Success. Return data. 49 | callback(data); 50 | } else { 51 | authHelper.clearCookies(res); 52 | renderError(res, secondRequestError); //Step 3 failed. 53 | } 54 | } 55 | ); 56 | } else { 57 | renderError(res, refreshError); //Step 2 failed. 58 | } 59 | }); 60 | } else { 61 | renderError(res, firstRequestError); //Step 1 failed. 62 | } 63 | } 64 | ); 65 | 66 | } 67 | 68 | } 69 | 70 | /** 71 | * Execute HTTPS request to the specified endpoint 72 | * @param {string} requestType the HTTPS request type 73 | * @param {string} requestPath the resource path from which to retrieve data 74 | * @param {object} requestBody the data to be 'POST'ed 75 | * @param {string} accessToken the access token with which the request should be authenticated 76 | * @param {callback} callback 77 | */ 78 | function executeHttpsRequest(requestType, requestPath, requestBody, accessToken, callback) { 79 | var requestBodyAsString = JSON.stringify(requestBody); 80 | var options = { 81 | host: 'graph.microsoft.com', 82 | path: requestPath, 83 | method: requestType, 84 | headers: { 85 | 'Content-Type': 'application/json', 86 | Authorization: 'Bearer ' + accessToken, 87 | 'Content-Length': (requestBody == null) ? 0 : requestBodyAsString.length 88 | } 89 | }; 90 | 91 | var request = https.request(options, function (response) { 92 | var body = ''; 93 | response.on('data', function (d) { 94 | body += d; 95 | }); 96 | response.on('end', function () { 97 | var error; 98 | if (response.statusCode === 200) { 99 | callback(null, JSON.parse(body)); 100 | } else if (response.statusCode === 202) { 101 | callback(null, null); 102 | } else if (response.statusCode === 204) { 103 | callback(null, null); 104 | } else { 105 | error = new Error(); 106 | error.code = response.statusCode; 107 | error.message = response.statusMessage; 108 | body = body.trim(); 109 | error.innerError = JSON.parse(body).error; 110 | callback(error, null); 111 | } 112 | }); 113 | }); 114 | 115 | // write the outbound data to it 116 | if (requestBody != null) { 117 | request.write(requestBodyAsString); 118 | } 119 | // we're done! 120 | request.end(); 121 | 122 | request.on('error', function (e) { 123 | callback(e, null); 124 | }); 125 | } 126 | 127 | function renderError(res, e) { 128 | res.send({ 129 | message: e.message, 130 | error: e 131 | }); 132 | res.end(); 133 | } 134 | 135 | exports.executeRequestWithErrorHandling = executeRequestWithErrorHandling; -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribute to Microsoft Teams sample 2 | 3 | Thank you for your interest in this sample! Your contributions and improvements will help the developer community. 4 | 5 | ## Ways to contribute 6 | 7 | There are several ways you can contribute to this sample: providing better code comments, fixing open issues, and adding new features. 8 | 9 | ### Provide better code comments 10 | 11 | Code comments make code samples even better by helping developers learn to use the code correctly in their own applications. If you spot a class, method, or section of code that you think could use better descriptions, then create a pull request with your code comments. 12 | In general we want our code comments to follow these guidelines: 13 | 14 | - Any code that has associated documentation displayed in an IDE (such as IntelliSense, or JavaDocs) has code comments. 15 | - Classes, methods, parameters, and return values have clear descriptions. 16 | - Exceptions and errors are documented. 17 | - Remarks exist for anything special or notable about the code. 18 | - Sections of code that have complex algorithms have appropriate comments describing what they do. 19 | - Code added from Stack Overflow, or any other source, is clearly attributed. 20 | 21 | ### Fix open issues 22 | 23 | Sometimes we get a lot of issues, and it can be hard to keep up. If you have a solution to an open issue that hasn't been addressed, fix the issue and then submit a pull request. 24 | 25 | ### Add a new feature 26 | 27 | New features are great! Be sure to check with the repository admin first to be sure the feature will fit the intent of the sample. Start by opening an issue in the repository that proposes and describes the feature. The repository admin will respond and may ask for more information. If the admin agrees to the new feature, create the feature and submit a pull request. 28 | 29 | ## Contribution guidelines 30 | 31 | We have some guidelines to help maintain a healthy repo and code for everyone. 32 | 33 | ### The Contribution License Agreement 34 | 35 | For most contributions, you'll be asked to sign a Contribution License Agreement (CLA). This will happen when you submit a pull request. Microsoft will send a link to the CLA to sign via email. Once you sign the CLA, your pull request can proceed. Read the CLA carefully, because you may need to have your employer sign it. 36 | 37 | ### Code contribution checklist 38 | 39 | Be sure to satisfy all of the requirements in the following list before submitting a pull request: 40 | 41 | - Follow the code style that is appropriate for the platform and language in this repo. For example, Android code follows the style conventions found in the [Code Style for Contributors guide](https://source.android.com/source/code-style.html). 42 | - Test your code. 43 | - Test the UI thoroughly to be sure nothing has been broken by your change. 44 | - Keep the size of your code change reasonable. if the repository owner cannot review your code change in 4 hours or less, your pull request may not be reviewed and approved quickly. 45 | - Avoid unnecessary changes. The reviewer will check differences between your code and the original code. Whitespace changes are called out along with your code. Be sure your changes will help improve the content. 46 | 47 | ### Submit a pull request to the master branch 48 | 49 | When you're finished with your work and are ready to have it merged into the master repository, follow these steps. Note: pull requests are typically reviewed within 10 business days. If your pull request is accepted you will be credited for your submission. 50 | 51 | 1. Submit your pull request against the master branch. 52 | 2. Sign the CLA, if you haven't already done so. 53 | 3. One of the repo admins will process your pull request, including performing a code review. If there are questions, discussions, or change requests in the pull request, be sure to respond. 54 | 4. When the repo admins are satisfied, they will accept and merge the pull request. 55 | 56 | Congratulations, you have successfully contributed to the sample! 57 | 58 | ## FAQ 59 | 60 | ### Where do I get a Contributor's License Agreement? 61 | 62 | You will automatically be sent a notice that you need to sign the Contributor's License Agreement (CLA) if your pull request requires one. 63 | 64 | As a community member, you must sign the CLA before you can contribute large submissions to this project. You only need complete and submit the CLA document once. Carefully review the document. You may be required to have your employer sign the document. 65 | 66 | ### What happens with my contributions? 67 | 68 | When you submit your changes, via a pull request, our team will be notified and will review your pull request. You will receive notifications about your pull request from GitHub; you may also be notified by someone from our team if we need more information. We reserve the right to edit your submission for legal, style, clarity, or other issues. 69 | 70 | ### Who approves pull requests? 71 | 72 | The admin of the repository approves pull requests. 73 | 74 | ### How soon will I get a response about my change request or issue? 75 | 76 | We typically review pull requests and respond to issues within 10 business days. 77 | 78 | ## More resources 79 | 80 | - To learn more about Markdown, see [Daring Fireball](http://daringfireball.net/). 81 | - To learn more about using Git and GitHub, check out the [GitHub Help section](http://help.github.com/).​ 82 | -------------------------------------------------------------------------------- /source/App_Start/Startup.Auth.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. 3 | * See LICENSE in the source repository root for complete license information. 4 | */ 5 | 6 | using Microsoft.Identity.Client; 7 | using Microsoft.IdentityModel.Tokens; 8 | using Microsoft.Owin.Security; 9 | using Microsoft.Owin.Security.Cookies; 10 | using Microsoft.Owin.Security.OpenIdConnect; 11 | using Owin; 12 | using System.Configuration; 13 | using System.IdentityModel.Claims; 14 | using System.Threading.Tasks; 15 | using System.Web; 16 | 17 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect 18 | { 19 | public partial class Startup 20 | { 21 | 22 | // The appId is used by the application to uniquely identify itself to Azure AD. 23 | // The appSecret is the application's password. 24 | // The redirectUri is where users are redirected after sign in and consent. 25 | // The graphScopes are the Microsoft Graph permission scopes that are used by this sample: User.Read Mail.Send 26 | private static string appId = ConfigurationManager.AppSettings["ida:AppId"]; 27 | private static string appSecret = ConfigurationManager.AppSettings["ida:AppSecret"]; 28 | private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"]; 29 | private static string graphScopes = ConfigurationManager.AppSettings["ida:GraphScopes"]; 30 | private static string authority = "https://login.microsoftonline.com/common/v2.0"; 31 | public void ConfigureAuth(IAppBuilder app) 32 | { 33 | app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType); 34 | 35 | app.UseCookieAuthentication(new CookieAuthenticationOptions()); 36 | 37 | app.UseOpenIdConnectAuthentication( 38 | new OpenIdConnectAuthenticationOptions 39 | { 40 | 41 | // The `Authority` represents the Microsoft v2.0 authentication and authorization service. 42 | // The `Scope` describes the permissions that your app will need. See https://azure.microsoft.com/documentation/articles/active-directory-v2-scopes/ 43 | ClientId = appId, 44 | Authority = "https://login.microsoftonline.com/common/v2.0", 45 | PostLogoutRedirectUri = redirectUri, 46 | RedirectUri = redirectUri, 47 | Scope = "openid email profile offline_access " + graphScopes, 48 | TokenValidationParameters = new TokenValidationParameters 49 | { 50 | ValidateIssuer = false, 51 | // In a real application you would use IssuerValidator for additional checks, 52 | // like making sure the user's organization has signed up for your app. 53 | // IssuerValidator = (issuer, token, tvp) => 54 | // { 55 | // if (MyCustomTenantValidation(issuer)) 56 | // return issuer; 57 | // else 58 | // throw new SecurityTokenInvalidIssuerException("Invalid issuer"); 59 | // }, 60 | }, 61 | Notifications = new OpenIdConnectAuthenticationNotifications 62 | { 63 | AuthorizationCodeReceived = async (context) => 64 | { 65 | var code = context.Code; 66 | string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value; 67 | IConfidentialClientApplication cc = MsalAppBuilder.BuildConfidentialClientApplication(); 68 | string[] scopes = graphScopes.Split(new char[] { ' ' }); 69 | 70 | AuthenticationResult result = await cc.AcquireTokenByAuthorizationCode(scopes, code) 71 | .ExecuteAsync(); 72 | 73 | // Check whether the login is from the MSA tenant. 74 | // The sample uses this attribute to disable UI buttons for unsupported operations when the user is logged in with an MSA account. 75 | var currentTenantId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value; 76 | if (currentTenantId == "9188040d-6c67-4c5b-b112-36a304b66dad") 77 | { 78 | HttpContext.Current.Session.Add("AccountType", "msa"); 79 | } 80 | // Set IsAdmin session variable to false, since the user hasn't consented to admin scopes yet. 81 | HttpContext.Current.Session.Add("IsAdmin", false); 82 | }, 83 | AuthenticationFailed = (context) => 84 | { 85 | context.HandleResponse(); 86 | context.Response.Redirect("/Error?message=" + context.Exception.Message); 87 | return Task.FromResult(0); 88 | } 89 | } 90 | }); 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /source/Scripts/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | // Unobtrusive validation support library for jQuery and jQuery Validate 2 | // Copyright (c) .NET Foundation. All rights reserved. 3 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 4 | // @version v3.2.11 5 | !function(a){"function"==typeof define&&define.amd?define("jquery.validate.unobtrusive",["jquery-validation"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery-validation")):jQuery.validator.unobtrusive=a(jQuery)}(function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("
  • ").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function u(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=f.unobtrusive.options||{},u=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),u("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),u("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),u("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var m,f=a.validator,v="unobtrusiveValidation";return f.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=u(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){f.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=u(this);a&&a.attachValidation()})}},m=f.unobtrusive.adapters,m.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},m.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},m.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},m.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},f.addMethod("__dummy__",function(a,e,n){return!0}),f.addMethod("regex",function(a,e,n){var t;return!!this.optional(e)||(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),f.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),f.methods.extension?(m.addSingleVal("accept","mimtype"),m.addSingleVal("extension","extension")):m.addSingleVal("extension","extension","accept"),m.addSingleVal("regex","pattern"),m.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),m.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),m.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),m.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),m.add("required",function(a){"INPUT"===a.element.tagName.toUpperCase()&&"CHECKBOX"===a.element.type.toUpperCase()||e(a,"required",!0)}),m.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),m.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),m.add("fileextensions",["extensions"],function(a){e(a,"extension",a.params.extensions)}),a(function(){f.unobtrusive.parse(document)}),f.unobtrusive}); -------------------------------------------------------------------------------- /source/Utils/MSALAppMemoryTokenCache.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015 Microsoft Corporation 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | using Microsoft.Identity.Client; 26 | using System; 27 | using System.Runtime.Caching; 28 | 29 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect 30 | { 31 | /// 32 | /// An implementation of token cache for Confidential clients backed by MemoryCache. 33 | /// MemoryCache is useful in Api scenarios where there is no HttpContext to cache data. 34 | /// 35 | /// 36 | public class MSALAppMemoryTokenCache 37 | { 38 | /// 39 | /// The application cache key 40 | /// 41 | internal readonly string AppCacheId; 42 | 43 | /// 44 | /// The backing MemoryCache instance 45 | /// 46 | internal readonly MemoryCache memoryCache = MemoryCache.Default; 47 | 48 | /// 49 | /// The duration till the tokens are kept in memory cache. In production, a higher value , upto 90 days is recommended. 50 | /// 51 | private readonly DateTimeOffset cacheDuration = DateTimeOffset.Now.AddHours(48); 52 | 53 | /// 54 | /// The internal handle to the client's instance of the Cache 55 | /// 56 | private ITokenCache ApptokenCache; 57 | 58 | /// 59 | /// Initializes a new instance of the class. 60 | /// 61 | /// The client's instance of the token cache. 62 | /// The application's id (Client ID). 63 | public MSALAppMemoryTokenCache(ITokenCache tokenCache, string clientId) 64 | { 65 | this.AppCacheId = clientId + "_AppTokenCache"; 66 | 67 | if (this.ApptokenCache == null) 68 | { 69 | this.ApptokenCache = tokenCache; 70 | this.ApptokenCache.SetBeforeAccess(this.AppTokenCacheBeforeAccessNotification); 71 | this.ApptokenCache.SetAfterAccess(this.AppTokenCacheAfterAccessNotification); 72 | this.ApptokenCache.SetBeforeWrite(this.AppTokenCacheBeforeWriteNotification); 73 | } 74 | 75 | this.LoadAppTokenCacheFromMemory(); 76 | } 77 | 78 | /// 79 | /// if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry 80 | /// 81 | /// Contains parameters used by the MSAL call accessing the cache. 82 | private void AppTokenCacheBeforeWriteNotification(TokenCacheNotificationArgs args) 83 | { 84 | // Since we are using a MemoryCache ,whose methods are threads safe, we need not to do anything in this handler. 85 | } 86 | 87 | /// 88 | /// Loads the application's token from memory cache. 89 | /// 90 | private void LoadAppTokenCacheFromMemory() 91 | { 92 | // Ideally, methods that load and persist should be thread safe. MemoryCache.Get() is thread safe. 93 | byte[] tokenCacheBytes = (byte[])this.memoryCache.Get(this.AppCacheId); 94 | this.ApptokenCache.DeserializeMsalV3(tokenCacheBytes); 95 | } 96 | 97 | /// 98 | /// Persists the application's token to the cache. 99 | /// 100 | private void PersistAppTokenCache() 101 | { 102 | // Ideally, methods that load and persist should be thread safe.MemoryCache.Get() is thread safe. 103 | // Reflect changes in the persistence store 104 | this.memoryCache.Set(this.AppCacheId, this.ApptokenCache.SerializeMsalV3(), this.cacheDuration); 105 | } 106 | 107 | public void Clear() 108 | { 109 | this.memoryCache.Remove(this.AppCacheId); 110 | 111 | // Nulls the currently deserialized instance 112 | this.LoadAppTokenCacheFromMemory(); 113 | } 114 | 115 | /// 116 | /// Triggered right before MSAL needs to access the cache. Reload the cache from the persistence store in case it changed since the last access. 117 | /// 118 | /// Contains parameters used by the MSAL call accessing the cache. 119 | private void AppTokenCacheBeforeAccessNotification(TokenCacheNotificationArgs args) 120 | { 121 | this.LoadAppTokenCacheFromMemory(); 122 | } 123 | 124 | /// 125 | /// Triggered right after MSAL accessed the cache. 126 | /// 127 | /// Contains parameters used by the MSAL call accessing the cache. 128 | private void AppTokenCacheAfterAccessNotification(TokenCacheNotificationArgs args) 129 | { 130 | // if the access operation resulted in a cache update 131 | if (args.HasStateChanged) 132 | { 133 | this.PersistAppTokenCache(); 134 | } 135 | } 136 | } 137 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Microsoft Teams Graph API Samples 2 | 3 | **This project is being archived and replaced with the [Microsoft Graph snippets sample for ASP.NET Core 3.1](https://github.com/microsoftgraph/aspnet-snippets-sample). As part of the archival process, we're closing all open issues and pull requests.** 4 | 5 | **You can continue to use this sample "as-is", but it won't be maintained moving forward. We apologize for any inconvenience.** 6 | 7 | This sample has example calls to many of the Teams Graph APIs, including: 8 | 9 | * Get My Teams 10 | * Get Channels 11 | * Get Apps 12 | * Create Channel 13 | * Post Message 14 | * Create Team and Group 15 | * Add Team to Group 16 | * Add Member to team 17 | * Update Team settings 18 | 19 | ## Related samples 20 | 21 | * [Contoso Airlines sample for Microsoft Teams](https://github.com/microsoftgraph/contoso-airlines-teams-sample) 22 | * [Node version of the Microsoft Teams Graph API Samples](https://github.com/OfficeDev/microsoft-teams-sample-graph/tree/master/Node/SampleApp) 23 | 24 | > For more information on developing apps for Microsoft Teams, please review the Microsoft Teams [developer documentation](https://msdn.microsoft.com/en-us/microsoft-teams/index).** 25 | 26 | ## Prerequisites 27 | 28 | ### O365 Account with Admin privileges 29 | 30 | To set this app up, you'll need to be a global admin, because only global admins can consent to apps using permissions such as Group.ReadWrite.All. Consider creating your own test tenant by creating a developer account with our [Office 365 Developer program](https://dev.office.com/devprogram). 31 | 32 | ### Registered app 33 | 34 | You'll need to register an app through the following process: 35 | 36 | 1. Sign in to the [Azure portal](https://go.microsoft.com/fwlink/?linkid=2083908) using either a work or school account or a personal Microsoft account. 37 | 2. If your account gives you access to more than one tenant, select your account in the top right corner, and set your portal session to the Azure AD tenant that you want. 38 | 3. Select **New registration**. 39 | 4. When the Register an application page appears, enter your application's registration information: 40 | * **Name** - Enter a meaningful application name that will be displayed to users of the app. 41 | * **Supported account types** - Select which accounts you would like your application to support. 42 | * **Redirect URI (optional)** - Select **Web** and enter 'http://localhost:55065/' for the **Redirect URI**. 43 | 5. When finished, select **Register**. 44 | 6. Azure AD assigns a unique application (client) ID to your app, and you're taken to your application's Overview page. To add additional capabilities to your application, you can select other configuration options including branding, certificates and secrets, API permissions, and more. 45 | 46 | Copy the Application Id. This is the unique identifier for your app. 47 | 7. Under **Manage** on the left-hand pane, click **Certificates & secrets**. Under **Client secrets**, click **New client secret**. Enter a description and an expiration, then click **Add**. This creates a secret string, or application password, which the application uses to prove it's identity. 48 | 49 | Copy the value from the new secret. 50 | 8. Under **Manage** on the left-hand pane, click **Authentication**. Under **Implicit grant**, check **Access tokens** and **ID tokens**. During authentication, this enables the app to receive both sign-in info (the id_token) and artifacts (in this case, an authorization code) that the app can use to obtain an access token. Save your changes. 51 | 9. Under **Manage** on the left-hand pane, click **API permissions** and then **Add a new permission**. Select **Microsoft Graph** and then **Delegated permissions**. Add 'Group.ReadWrite.All' (Read and write all groups) and 'User.ReadWrite.All' (Read and write all users' full profile) permissions. Click **Add a new permission** again then **Application permissions**. Add 'Group.ReadWrite.All' (Read and write all groups) and 'User.ReadWrite.All' (Read and write all users' full profile) permissions. 52 | 53 | See the individual project readmes for more information. 54 | 55 | ### Build and run the sample app 56 | 57 | 1. Open the sample solution in Visual Studio. 58 | 2. Get your appid & app secret from the previous section 59 | 3. Create a file named Web.config.secrets (put it next to Web.config), and add in your appid and app secret: 60 | 61 | ``` 62 | 63 | 64 | 65 | 66 | 67 | ``` 68 | 69 | 4. Update the 'Web Server' of your web application with the 'ida:RedirectUri' of your registered app 70 | 71 | * In Solution Explorer, right-click the name of the Web application project for which you want to specify a Web server, and then click 'Properties'. 72 | * In the 'Properties' window, click the 'Web' tab. 73 | * Under 'Servers', update the 'Project Url' with the 'ida:RedirectUri' of your registered app. 74 | * Click 'Create Virtual Directory' 75 | * Save the file. 76 | 77 | 5. Build and run the sample. 78 | 79 | 6. Sign in with your account, and grant the requested permissions. 80 | 81 | * Note you'll need to have appropriate elevated rights to run the app (Group.ReadWrite.All and User.ReadWrite.All) 82 | 83 | 7. Choose operation, such as 'Get My Teams', 'Get Channels', 'Create Channel' or 'Post Message'. 84 | 85 | 8. Response information is displayed at the bottom of the page. 86 | 87 | ## Feedback 88 | 89 | We welcome your feedback! [Here's how to send us yours](https://msdn.microsoft.com/en-us/microsoft-teams/feedback). 90 | 91 | ## Microsoft Open Source Code of Conduct 92 | 93 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 94 | 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. 95 | 96 | ## Contributing 97 | 98 | Please read [Contributing](contributing.md) for details on the process for submitting pull requests to us. 99 | 100 | ## License 101 | 102 | This project is licensed under the MIT License - see the [License](LICENSE) file for details. 103 | 104 | ## Copyright 105 | 106 | Copyright (c) 2018 Microsoft Corporation. All rights reserved. 107 | -------------------------------------------------------------------------------- /source/Utils/MSALAppSessionTokenCache.cs: -------------------------------------------------------------------------------- 1 | /************************************************************************************************ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015 Microsoft Corporation 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | ***********************************************************************************************/ 24 | 25 | using Microsoft.Identity.Client; 26 | using System; 27 | using System.Threading; 28 | using System.Web; 29 | 30 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect 31 | { 32 | /// 33 | /// An implementation of token cache for Confidential clients backed by Http session. 34 | /// 35 | /// 36 | public class MSALAppSessionTokenCache 37 | { 38 | /// 39 | /// The application cache key 40 | /// 41 | internal readonly string AppCacheId; 42 | 43 | /// 44 | /// The HTTP context being used by this app 45 | /// 46 | internal HttpContextBase HttpContextInstance = null; 47 | 48 | /// 49 | /// The internal handle to the client's instance of the Cache 50 | /// 51 | private ITokenCache ApptokenCache; 52 | 53 | private static ReaderWriterLockSlim SessionLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); 54 | 55 | /// 56 | /// Initializes a new instance of the class. 57 | /// 58 | /// The client's instance of the token cache. 59 | /// The application's id (Client ID). 60 | public MSALAppSessionTokenCache(ITokenCache tokenCache, string clientId, HttpContextBase httpcontext) 61 | { 62 | this.HttpContextInstance = httpcontext; 63 | this.AppCacheId = clientId + "_AppTokenCache"; 64 | 65 | if (this.ApptokenCache == null) 66 | { 67 | this.ApptokenCache = tokenCache; 68 | this.ApptokenCache.SetBeforeAccess(this.AppTokenCacheBeforeAccessNotification); 69 | this.ApptokenCache.SetAfterAccess(this.AppTokenCacheAfterAccessNotification); 70 | this.ApptokenCache.SetBeforeWrite(this.AppTokenCacheBeforeWriteNotification); 71 | } 72 | 73 | this.LoadAppTokenCacheFromSession(); 74 | } 75 | 76 | /// 77 | /// if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry 78 | /// 79 | /// Contains parameters used by the MSAL call accessing the cache. 80 | private void AppTokenCacheBeforeWriteNotification(TokenCacheNotificationArgs args) 81 | { 82 | // Since we are using a SessionCache ,whose methods are threads safe, we need not to do anything in this handler. 83 | } 84 | 85 | /// 86 | /// Loads the application's tokens from session cache. 87 | /// 88 | private void LoadAppTokenCacheFromSession() 89 | { 90 | SessionLock.EnterReadLock(); 91 | 92 | this.ApptokenCache.DeserializeMsalV3((byte[])HttpContextInstance.Session[this.AppCacheId]); 93 | 94 | SessionLock.ExitReadLock(); 95 | } 96 | 97 | /// 98 | /// Persists the application token's to session cache. 99 | /// 100 | private void PersistAppTokenCache() 101 | { 102 | SessionLock.EnterWriteLock(); 103 | 104 | // Reflect changes in the persistence store 105 | HttpContextInstance.Session[this.AppCacheId] = this.ApptokenCache.SerializeMsalV3(); 106 | 107 | SessionLock.ExitWriteLock(); 108 | } 109 | 110 | /// 111 | /// Clears the TokenCache's copy of this user's cache. 112 | /// 113 | public void Clear() 114 | { 115 | SessionLock.EnterWriteLock(); 116 | 117 | HttpContextInstance.Session[this.AppCacheId] = null; 118 | 119 | SessionLock.ExitWriteLock(); 120 | 121 | // Nulls the currently deserialized instance 122 | this.LoadAppTokenCacheFromSession(); 123 | } 124 | 125 | /// 126 | /// Triggered right before MSAL needs to access the cache. Reload the cache from the persistence store in case it changed since the last access. 127 | /// 128 | /// Contains parameters used by the MSAL call accessing the cache. 129 | private void AppTokenCacheBeforeAccessNotification(TokenCacheNotificationArgs args) 130 | { 131 | this.LoadAppTokenCacheFromSession(); 132 | } 133 | 134 | /// 135 | /// Triggered right after MSAL accessed the cache. 136 | /// 137 | /// Contains parameters used by the MSAL call accessing the cache. 138 | private void AppTokenCacheAfterAccessNotification(TokenCacheNotificationArgs args) 139 | { 140 | // if the access operation resulted in a cache update 141 | if (args.HasStateChanged) 142 | { 143 | this.PersistAppTokenCache(); 144 | } 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /source/Areas/HelpPage/App_Start/HelpPageConfig.cs: -------------------------------------------------------------------------------- 1 | // Uncomment the following to provide samples for PageResult. Must also add the Microsoft.AspNet.WebApi.OData 2 | // package to your project. 3 | ////#define Handle_PageResultOfT 4 | 5 | using System; 6 | using System.Collections; 7 | using System.Collections.Generic; 8 | using System.Diagnostics; 9 | using System.Diagnostics.CodeAnalysis; 10 | using System.Linq; 11 | using System.Net.Http.Headers; 12 | using System.Reflection; 13 | using System.Web; 14 | using System.Web.Http; 15 | #if Handle_PageResultOfT 16 | using System.Web.Http.OData; 17 | #endif 18 | 19 | namespace Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage 20 | { 21 | /// 22 | /// Use this class to customize the Help Page. 23 | /// For example you can set a custom to supply the documentation 24 | /// or you can provide the samples for the requests/responses. 25 | /// 26 | public static class HelpPageConfig 27 | { 28 | [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", 29 | MessageId = "Microsoft_Teams_Graph_RESTAPIs_Connect.Areas.HelpPage.TextSample.#ctor(System.String)", 30 | Justification = "End users may choose to merge this string with existing localized resources.")] 31 | [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", 32 | MessageId = "bsonspec", 33 | Justification = "Part of a URI.")] 34 | public static void Register(HttpConfiguration config) 35 | { 36 | //// Uncomment the following to use the documentation from XML documentation file. 37 | //config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml"))); 38 | 39 | //// Uncomment the following to use "sample string" as the sample for all actions that have string as the body parameter or return type. 40 | //// Also, the string arrays will be used for IEnumerable. The sample objects will be serialized into different media type 41 | //// formats by the available formatters. 42 | //config.SetSampleObjects(new Dictionary 43 | //{ 44 | // {typeof(string), "sample string"}, 45 | // {typeof(IEnumerable), new string[]{"sample 1", "sample 2"}} 46 | //}); 47 | 48 | // Extend the following to provide factories for types not handled automatically (those lacking parameterless 49 | // constructors) or for which you prefer to use non-default property values. Line below provides a fallback 50 | // since automatic handling will fail and GeneratePageResult handles only a single type. 51 | #if Handle_PageResultOfT 52 | config.GetHelpPageSampleGenerator().SampleObjectFactories.Add(GeneratePageResult); 53 | #endif 54 | 55 | // Extend the following to use a preset object directly as the sample for all actions that support a media 56 | // type, regardless of the body parameter or return type. The lines below avoid display of binary content. 57 | // The BsonMediaTypeFormatter (if available) is not used to serialize the TextSample object. 58 | config.SetSampleForMediaType( 59 | new TextSample("Binary JSON content. See http://bsonspec.org for details."), 60 | new MediaTypeHeaderValue("application/bson")); 61 | 62 | //// Uncomment the following to use "[0]=foo&[1]=bar" directly as the sample for all actions that support form URL encoded format 63 | //// and have IEnumerable as the body parameter or return type. 64 | //config.SetSampleForType("[0]=foo&[1]=bar", new MediaTypeHeaderValue("application/x-www-form-urlencoded"), typeof(IEnumerable)); 65 | 66 | //// Uncomment the following to use "1234" directly as the request sample for media type "text/plain" on the controller named "Values" 67 | //// and action named "Put". 68 | //config.SetSampleRequest("1234", new MediaTypeHeaderValue("text/plain"), "Values", "Put"); 69 | 70 | //// Uncomment the following to use the image on "../images/aspNetHome.png" directly as the response sample for media type "image/png" 71 | //// on the controller named "Values" and action named "Get" with parameter "id". 72 | //config.SetSampleResponse(new ImageSample("../images/aspNetHome.png"), new MediaTypeHeaderValue("image/png"), "Values", "Get", "id"); 73 | 74 | //// Uncomment the following to correct the sample request when the action expects an HttpRequestMessage with ObjectContent. 75 | //// The sample will be generated as if the controller named "Values" and action named "Get" were having string as the body parameter. 76 | //config.SetActualRequestType(typeof(string), "Values", "Get"); 77 | 78 | //// Uncomment the following to correct the sample response when the action returns an HttpResponseMessage with ObjectContent. 79 | //// The sample will be generated as if the controller named "Values" and action named "Post" were returning a string. 80 | //config.SetActualResponseType(typeof(string), "Values", "Post"); 81 | } 82 | 83 | #if Handle_PageResultOfT 84 | private static object GeneratePageResult(HelpPageSampleGenerator sampleGenerator, Type type) 85 | { 86 | if (type.IsGenericType) 87 | { 88 | Type openGenericType = type.GetGenericTypeDefinition(); 89 | if (openGenericType == typeof(PageResult<>)) 90 | { 91 | // Get the T in PageResult 92 | Type[] typeParameters = type.GetGenericArguments(); 93 | Debug.Assert(typeParameters.Length == 1); 94 | 95 | // Create an enumeration to pass as the first parameter to the PageResult constuctor 96 | Type itemsType = typeof(List<>).MakeGenericType(typeParameters); 97 | object items = sampleGenerator.GetSampleObject(itemsType); 98 | 99 | // Fill in the other information needed to invoke the PageResult constuctor 100 | Type[] parameterTypes = new Type[] { itemsType, typeof(Uri), typeof(long?), }; 101 | object[] parameters = new object[] { items, null, (long)ObjectGenerator.DefaultCollectionSize, }; 102 | 103 | // Call PageResult(IEnumerable items, Uri nextPageLink, long? count) constructor 104 | ConstructorInfo constructor = type.GetConstructor(parameterTypes); 105 | return constructor.Invoke(parameters); 106 | } 107 | } 108 | 109 | return null; 110 | } 111 | #endif 112 | } 113 | } -------------------------------------------------------------------------------- /README-localized/README-pt-br.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | products: 4 | - office-teams 5 | - ms-graph 6 | languages: 7 | - csharp 8 | extensions: 9 | contentType: samples 10 | technologies: 11 | - Microsoft Graph 12 | services: 13 | - Microsoft Teams 14 | createdDate: 5/30/2017 6:00:04 PM 15 | --- 16 | # Exemplos de API do Graph no Microsoft Teams 17 | 18 | Este exemplo tem chamadas de exemplo para várias APIs do Graph Teams, incluindo: 19 | 20 | * Obter minhas equipes 21 | * Obter canais 22 | * Obter aplicativos 23 | * Criar canal 24 | * Postar uma mensagem 25 | * Criar equipe ou grupo 26 | * Adicionar equipe ao grupo 27 | * Adicionar membro à equipe 28 | * Alterar configurações da equipe 29 | 30 | ## Exemplos afins 31 | 32 | * [Exemplo da companhia aérea Contoso para Microsoft Teams](https://github.com/microsoftgraph/contoso-airlines-teams-sample) 33 | * [ Exemplos da versão node da API do Graph no Microsoft Teams](https://github.com/OfficeDev/microsoft-teams-sample-graph/tree/master/Node/SampleApp) 34 | 35 | > Para mais informações sobre o desenvolvimento de aplicativos para o Microsoft Teams, confira a[ documentação para desenvolvedores](https://msdn.microsoft.com/en-us/microsoft-teams/index)do Microsoft Teams.\** 36 | 37 | ## Pré-requisitos 38 | 39 | ### Conta do O365 com privilégios de administrador 40 | 41 | Para configurar esse aplicativo, você precisar ser um administrador global, pois somente administradores podem dar consentimento para aplicativos que usem permissões do tipo Group.ReadWrite.All. Considere a criação de seu próprio locatário de teste por meio da criação de uma conta de desenvolvedor com o nosso [programa para Desenvolvedores do Office 365](https://dev.office.com/devprogram). 42 | 43 | ### Aplicativo registrado 44 | 45 | Será necessário registrá-lo seguindo os procedimentos abaixo: 46 | 47 | 1. Entre no [portal do Azure](https://go.microsoft.com/fwlink/?linkid=2083908)usando uma conta corporativa, de estudante ou uma conta Microsoft pessoal. 48 | 2. Se sua conta fornecer acesso a mais de um locatário, selecione sua conta no canto superior direito e defina sua sessão do portal para o locatário desejado do Azure AD. 49 | 3. Selecione **Novo registro**. 50 | 4. Quando a página Registrar um aplicativo for exibida, insira as informações de registro do aplicativo: 51 | * **Nome** \- Insira um nome de aplicativo relevante o qual será exibido para os um do aplicativo. 52 | * **Tipos de contas com suporte** \- Selecione quais as contas para as quais você gostaria que o seu aplicativo oferecesse suporte. 53 | * **URI de redirecionamento (opcional)** \- Selecione **Web** e insira 'http://localhost:55065/' como **URI de redirecionamento**. 54 | 5. Quando terminar, selecione **Registrar**. 55 | 6. O Azure AD atribui uma ID exclusiva do aplicativo (cliente) para seu aplicativo, e você é redirecionado para a página Visão geral desse aplicativo. Para adicionar mais recursos ao seu aplicativo, você pode selecionar outras opções de configuração, incluindo identidade visual, certificados e segredos, permissões de API e muito mais. 56 | 57 | Copie a ID do Aplicativo. Esse é o identificador exclusivo do aplicativo. 58 | 7. Em**Gerenciar** no painel à esquerda, clique em **Certificados e segredos**. Em **Segredos do cliente**, clique em **Novo segredo do cliente**. Insira uma descrição e uma expiração, em seguida, clique em **Adicionar**. Isso cria uma cadeia de caracteres secreta ou uma senha do aplicativo, usado por ele para provar sua identidade. 59 | 60 | Copie o valor do novo segredo. 61 | 8. Em**Gerenciar**, no painel à esquerda, clique em **Autenticação**. Em **Concessão implícita**, marque **Tokens de acesso** e **Tokens de ID**. Durante a autenticação, isso permite que o aplicativo receba informações de entrada (o id\_token) e artefatos (neste caso, um código de autorização) que o aplicativo pode usar para obter um token de acesso. Salve suas alterações. 62 | 9. Em **Gerenciar**, no painel à esquerda, clique em ** Permissões da API** e, em seguida, em **Adicione uma nova permissão**. Selecione **Microsoft Graph** e **Permissões delegadas**. Adicione as permissões 'Group.ReadWrite.All' (ler e gravar todos os grupos) e 'User.ReadWrite.All (ler e gravar todos os perfis de todos os usuários). Clique em **Adicionar uma nova permissão** novamente e, em seguida, clique em **Permissões de aplicativo**. Adicione as permissões 'Group.ReadWrite.All' (ler e gravar todos os grupos) e 'User.ReadWrite.All (ler e gravar todos os perfis de todos os usuários). 63 | 64 | Confira o arquivo readme individual do projeto para saber mais. 65 | 66 | ### Crie e execute o aplicativo de exemplo 67 | 68 | 1. Abra a solução de exemplo no Visual Studio. 69 | 2. Obter o ID e o segredo do aplicativo definidos na seção anterior 70 | 3. Crie um arquivo chamando Web.config.secrets (coloque-o próximo a Web.config) e adicione o AppID e o segredo do aplicativo: 71 | 72 | ``` 73 | 74 | 75 | 76 | 77 | 78 | ``` 79 | 80 | 4. Atualize o "servidor Web" do seu aplicativo Web com a 'ida:RedirectUri' do seu aplicativo registrado 81 | 82 | * No Gerenciador de soluções, clique com o botão direito do mouse no nome do projeto do aplicativo Web para o qual você deseja especificar um servidor Web e, em seguida, clique em 'Propriedades'. 83 | * Na janela 'Propriedades', clique na guia 'Web'. 84 | * Em 'Servidores', atualize 'Project Url' com o 'ida:RedirectUri' do seu aplicativo registrado. 85 | * Clique em 'Criar diretório virtual' 86 | * Salve o arquivo. 87 | 88 | 5. Crie e execute o aplicativo de exemplo. 89 | 90 | 6. Entre com sua conta e conceda as permissões solicitadas. 91 | 92 | * Observe que é preciso ter direitos elevados para executar o aplicativo (permissões de Group.ReadWrite.All e de User.ReadWrite.All) 93 | 94 | 7. Escolha uma operação, como 'Obter minha equipes', 'Obter canais', 'Criar canal' ou 'postar mensagem'. 95 | 96 | 8. As informações de resposta são exibidas na parte inferior da página. 97 | 98 | ## Avaliações 99 | 100 | Seus comentários serão muito bem-vindos. [Veja aqui como nos enviar comentários](https://msdn.microsoft.com/en-us/microsoft-teams/feedback). 101 | 102 | ## Código de Conduta de Código Aberto da Microsoft 103 | 104 | Este projeto adotou o [Código de Conduta de Código Aberto da Microsoft](https://opensource.microsoft.com/codeofconduct/). Para saber mais, confira as [Perguntas frequentes sobre o Código de Conduta](https://opensource.microsoft.com/codeofconduct/faq/) ou entre em contato pelo [opencode@microsoft.com](mailto:opencode@microsoft.com) se tiver outras dúvidas ou comentários. 105 | 106 | ## Colaboração 107 | 108 | Leia [Colaboração](contributing.md) para obter detalhes sobre o nosso código de conduta e o processo de envio para nós de solicitações pull. 109 | 110 | ## Licença 111 | 112 | Este projeto está licenciado sob a Licença MIT, confira o arquivo [Licença](LICENSE) para obter detalhes. 113 | 114 | ## Direitos autorais 115 | 116 | Copyright (c) 2018 Microsoft Corporation. Todos os direitos reservados. 117 | -------------------------------------------------------------------------------- /README-localized/README-ru-ru.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | products: 4 | - office-teams 5 | - ms-graph 6 | languages: 7 | - csharp 8 | extensions: 9 | contentType: samples 10 | technologies: 11 | - Microsoft Graph 12 | services: 13 | - Microsoft Teams 14 | createdDate: 5/30/2017 6:00:04 PM 15 | --- 16 | # Примеры команд Microsoft Teams Graph 17 | 18 | В этом примере приведены примеры вызовов многих API-интерфейсов Teams Graph, в том числе: 19 | 20 | * Получить мои команды 21 | * Получить каналы 22 | * Получить приложения 23 | * Создание канала 24 | * Публикация сообщения 25 | * Создать команду и группу 26 | * Добавить команду в группу 27 | * Добавить участника в команду 28 | * Обновить настройки команды 29 | 30 | ## Родственные образцы 31 | 32 | * [Образец Contoso Airlines для Microsoft Teams](https://github.com/microsoftgraph/contoso-airlines-teams-sample) 33 | * [Версия узла. примеры API Microsoft Teams Graph](https://github.com/OfficeDev/microsoft-teams-sample-graph/tree/master/Node/SampleApp) 34 | 35 | > Для получения дополнительной информации о разработке приложений для Microsoft Teams, пожалуйста, просмотрите [документацию для разработчиков](https://msdn.microsoft.com/en-us/microsoft-teams/index) Microsoft Teams.\** 36 | 37 | ## Предварительные требования 38 | 39 | ### Учетная запись O365 с правами администратора 40 | 41 | Чтобы настроить это приложение, вам нужно быть глобальным администратором, поскольку только глобальные администраторы могут разрешать приложениям использовать разрешения, такие как Group.ReadWrite.All. Попробуйте создать собственного тестового арендатора, создав учетную запись разработчика с помощью нашей [программы для разработчиков Office 365](https://dev.office.com/devprogram). 42 | 43 | ### Зарегистрированное приложение 44 | 45 | Вам необходимо зарегистрировать приложение с помощью следующего процесса: 46 | 47 | 1. Войдите на [портал Azure](https://go.microsoft.com/fwlink/?linkid=2083908) с помощью личной учетной записи Майкрософт либо рабочей или учебной учетной записи. 48 | 2. Если ваша учетная запись предоставляет доступ к нескольким клиентам, в правом верхнем углу щелкните свою учетную запись и выберите для текущего сеанса работы нужный клиент Azure AD. 49 | 3. Выберите **Новая регистрация**. 50 | 4. Когда появится страница «Зарегистрировать приложение», введите регистрационную информацию вашего приложения: 51 | * **Имя** \- введите значимое имя приложения, которое будет отображаться пользователям приложения. 52 | * **Поддерживаемые типы учетных записей** — выберите учетные записи, которые должны поддерживать приложение. 53 | * **URI перенаправления (необязательно)** Выберите **Веб** и введите «http: // localhost: 55065 /» для **URI перенаправления**. 54 | 5. По завершении нажмите кнопку **зарегистрировать**. 55 | 6. Azure AD назначает уникальный идентификатор приложения (клиента) вашему приложению, и вы попадаете на страницу обзора вашего приложения. Чтобы добавить дополнительные возможности в свое приложение, вы можете выбрать другие параметры конфигурации, включая фирменную символику, сертификаты и секреты, разрешения API и прочее. 56 | 57 | Скопируйте идентификатор приложения. Это уникальный идентификатор приложения. 58 | 7. В разделе **Управление** на левой панели выберите **Сертификаты и секреты**. В разделе **Секреты клиента** выберите **Новый секрет клиента**. Введите описание и срок действия, а затем нажмите кнопку **добавить**. Это создает секретную строку или пароль приложения, которые приложение использует для подтверждения своей идентичности. 59 | 60 | Скопируйте значение из нового секрета. 61 | 8. В разделе **Управление** на левой панели выберите **проверка подлинности**. В разделе **неявное предоставление**проверьте, **маркеры доступа** и **Маркеры идентификаторов**. Благодаря этому при проверке подлинности приложение может получить данные для входа (id\_token) и артефакты (в данном случае — код авторизации), которые используются для получения маркера доступа. Сохраните изменения. 62 | 9. В разделе **управление**ми в области слева выберите пункт **разрешения API** а затем **добавить новое разрешение**. Выберите **Microsoft Graph** а затем **делегированные разрешения**. Добавьте разрешения «Group.ReadWrite.All» (чтение и запись всех групп) и «User.ReadWrite.All» (полный профиль чтения и записи всех пользователей). Щелкните **Добавление нового разрешения** еще раз, а затем **разрешения для приложения**. Добавьте разрешения «Group.ReadWrite.All» (чтение и запись всех групп) и «User.ReadWrite.All» (полный профиль чтения и записи всех пользователей). 63 | 64 | Смотрите отдельные проекты readmes для получения дополнительной информации. 65 | 66 | ### Создайте и запустите образец приложения 67 | 68 | 1. Откройте пример решения в Visual Studio. 69 | 2. Получить идентификатор приложения и секрет приложения из предыдущего раздела 70 | 3. Создайте файл с именем Web.config.secrets (поместите его рядом с Web.config) и добавьте в свой appid и секрет приложения: 71 | 72 | ``` 73 | 74 | 75 | 76 | 77 | 78 | ``` 79 | 80 | 4. Обновите «Веб-сервер» вашего веб-приложения с помощью «ida: RedirectUri» вашего зарегистрированного приложения. 81 | 82 | * В обозревателе решений щелкните правой кнопкой мыши имя проекта веб-приложения, для которого вы хотите указать веб-сервер, и выберите «Свойства». 83 | * В окне «Свойства» перейдите на вкладку «Интернет». 84 | * В разделе «Серверы» обновите «URL проекта» с помощью «ida: RedirectUri» вашего зарегистрированного приложения. 85 | * Нажмите «Создать виртуальный каталог» 86 | * Сохраните файл. 87 | 88 | 5. Выполните сборку и запуск приложения. 89 | 90 | 6. Войдите в свою учетную запись и предоставьте запрошенные разрешения. 91 | 92 | * Обратите внимание, что для запуска приложения вам понадобятся соответствующие повышенные права (Group.ReadWrite.All и User.ReadWrite.All). 93 | 94 | 7. Выберите операцию, например «Получить мои команды», «Получить каналы», «Создать канал» или «Опубликовать сообщение». 95 | 96 | 8. Сведения об ответе отображаются в нижней части страницы. 97 | 98 | ## Отзывы 99 | 100 | Мы приветствуем ваши отзывы! [Вот как отправить нам свое.](https://msdn.microsoft.com/en-us/microsoft-teams/feedback). 101 | 102 | ## Правила поведения Майкрософт, касающиеся обращения с открытым кодом 103 | 104 | Этот проект соответствует [Правилам поведения разработчиков открытого кода Майкрософт](https://opensource.microsoft.com/codeofconduct/). Дополнительные сведения см. в разделе [вопросов и ответов о правилах поведения](https://opensource.microsoft.com/codeofconduct/faq/). Если у вас возникли вопросы или замечания, напишите нам по адресу [opencode@microsoft.com](mailto:opencode@microsoft.com). 105 | 106 | ## Участие 107 | 108 | Пожалуйста, ознакомьтесь с разделом [Участие](contributing.md) для получения подробной информации о процессе отправки запросов на получение данных нам. 109 | 110 | ## Лицензия 111 | 112 | Этот проект лицензируется по лицензии MIT - подробности см. В файле [Лицензия](LICENSE). 113 | 114 | ## Авторские права 115 | 116 | © Корпорация Майкрософт (Microsoft Corporation), 2018. Все права защищены. 117 | -------------------------------------------------------------------------------- /README-localized/README-es-es.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | products: 4 | - office-teams 5 | - ms-graph 6 | languages: 7 | - csharp 8 | extensions: 9 | contentType: samples 10 | technologies: 11 | - Microsoft Graph 12 | services: 13 | - Microsoft Teams 14 | createdDate: 5/30/2017 6:00:04 PM 15 | --- 16 | # Ejemplos de la API de Microsoft Teams Graph 17 | 18 | Este ejemplo tiene llamadas a muchas de las API de Teams Graph, entre las que se incluyen: 19 | 20 | * Obtener mis equipos 21 | * Obtener canales 22 | * Obtener aplicaciones 23 | * Crear canales 24 | * Publicar mensaje 25 | * Crear equipo y grupo 26 | * Agrear equipo al grupo 27 | * Agregar miembro al equipo 28 | * Actualizar la configuración del equipo 29 | 30 | ## Ejemplos relacionados 31 | 32 | * [Ejemplo de Contoso Airlines para Microsoft Teams](https://github.com/microsoftgraph/contoso-airlines-teams-sample) 33 | * [Versión para Node de los ejemplos de la API de Microsoft Teams Graph](https://github.com/OfficeDev/microsoft-teams-sample-graph/tree/master/Node/SampleApp) 34 | 35 | > Para obtener más información sobre cómo desarrollar aplicaciones para Microsoft Teams, consulte la [documentación para desarrolladores](https://msdn.microsoft.com/en-us/microsoft-teams/index).\** 36 | 37 | ## Requisitos previos 38 | 39 | ### Cuenta de O365 con privilegios de administrador 40 | 41 | Para configurar esta aplicación, debe ser un administrador global, porque solo ellos pueden aceptar las aplicaciones que usan permisos como Group.ReadWrite.All. Considere la posibilidad de crear su propio espacio de prueba al crear una cuenta de desarrollador mediante nuestro [Programa de desarrolladores de Office 365](https://dev.office.com/devprogram). 42 | 43 | ### Aplicación registrada 44 | 45 | Tendrá que registrar una aplicación a través del proceso siguiente: 46 | 47 | 1. Inicie sesión en [Microsoft Azure Portal](https://go.microsoft.com/fwlink/?linkid=2083908) con una cuenta personal, profesional o educativa de Microsoft. 48 | 2. Si la cuenta le proporciona acceso a más de un inquilino, haga clic en la cuenta en la esquina superior derecha y establezca la sesión del portal en el inquilino de Azure AD que desee. 49 | 3. Haga clic en **Nuevo registro**. 50 | 4. Cuando aparezca la página Registrar una aplicación, escriba la información de registro: 51 | * **Nombre**: escriba un nombre significativo que se mostrará a los usuarios de la aplicación. 52 | * **Tipos de cuenta compatibles**: seleccione qué cuentas desea que la aplicación admita. 53 | * **URI de redirección (opcional)**: seleccione **Web** y escriba 'http://localhost:55065/' como valor de **URI de redirección**. 54 | 5. Cuando termine, seleccione **Registrar**. 55 | 6. Azure AD le asigna un id. de aplicación (cliente) único a la aplicación y lo lleva a la página de información general de la misma. Para agregar funcionalidades adicionales a la aplicación, puede seleccionar otras opciones de configuración, como personalización de marca, certificados y secretos, permisos de API y mucho más. 56 | 57 | Copie el Id. de aplicación. Este es el identificador único de su aplicación. 58 | 7. En **Administrar** en el panel izquierdo, haga clic en **Certificados y secretos**. En **Secretos de cliente**, haga clic en **Nuevo secreto de cliente**. Escriba una descripción y una fecha de expiración y, después, haga clic en **Agregar**. Se crea una cadena secreta o una contraseña que la aplicación usa para demostrar su identidad. 59 | 60 | Copie el valor del nuevo secreto. 61 | 8. En **Administrar** en el panel izquierdo, haga clic en **Autenticación**. En **Concesión implícita**, marque **Tokens de acceso** y **Tokens de id.**. Durante la autenticación, esto permite que la aplicación reciba la información de inicio de sesión (id\_token) y artefactos (en este caso, un código de autorización) que la aplicación puede usar para obtener un token de acceso. Guarde los cambios. 62 | 9. En **Administrar** en el panel izquierdo, haga clic en **Permisos de API** y luego en **Agregar un permiso**. Seleccione **Microsoft Graph** y luego **Permisos delegados**. Agregue los permisos "Group.ReadWrite.All (Read and write all groups)" y "User.ReadWrite.All (Read and write all users' full profile)". Vuelva a hacer clic en **Agregar un permiso** y luego en **Permisos de la aplicación**. Agregue los permisos "Group.ReadWrite.All (Read and write all groups)" y "User.ReadWrite.All (Read and write all users' full profile)". 63 | 64 | Para obtener más información, consulte los archivos Léame de los proyectos individuales. 65 | 66 | ### Compilar y ejecutar el ejemplo 67 | 68 | 1. Abra la solución de ejemplo en Visual Studio. 69 | 2. Obtenga el id. y el secreto de la aplicación de la sección anterior. 70 | 3. Cree un archivo con el nombre Web.config.secrets (colóquelo al lado de Web.config) y agregue el id. y el secreto de la aplicación: 71 | 72 | ``` 73 | 74 | 75 | 76 | 77 | 78 | ``` 79 | 80 | 4. Actualice el "Servidor web" de la aplicación web con el "ida:RedirectUri" de la aplicación registrada. 81 | 82 | * En el Explorador de soluciones, haga clic con el botón secundario en el nombre del proyecto de aplicación web para el que desea especificar un servidor web y, a continuación, haga clic en "Propiedades". 83 | * En la ventana "Propiedades", haga clic en la pestaña "Web". 84 | * En "Servidores", actualice la "Dirección URL del proyecto" con el "ida:RedirectUri" de la aplicación registrada. 85 | * Haga clic en "Crear directorio virtual". 86 | * Guarde el archivo. 87 | 88 | 5. Compile y ejecute el ejemplo. 89 | 90 | 6. Inicie sesión con su cuenta y conceda los permisos solicitados. 91 | 92 | * Tenga en cuenta que deberá tener los permisos apropiados para ejecutar la aplicación (Group.ReadWrite.All y User.ReadWrite.All). 93 | 94 | 7. Elija una operación, como "Obtener mis equipos", "Obtener canales", "Crear canal" o "Publicar mensaje". 95 | 96 | 8. La información de la respuesta se muestra en la parte inferior de la página. 97 | 98 | ## Comentarios 99 | 100 | Agradecemos sus comentarios. [Siga este procedimiento para enviarnos sus comentarios](https://msdn.microsoft.com/en-us/microsoft-teams/feedback). 101 | 102 | ## Código de conducta de código abierto de Microsoft 103 | 104 | Este proyecto ha adoptado el [Código de conducta de código abierto de Microsoft](https://opensource.microsoft.com/codeofconduct/). Para obtener más información, vea [Preguntas frecuentes sobre el código de conducta](https://opensource.microsoft.com/codeofconduct/faq/) o póngase en contacto con [opencode@microsoft.com](mailto:opencode@microsoft.com) si tiene otras preguntas o comentarios. 105 | 106 | ## Contribuciones 107 | 108 | Lea [Contribuciones](contributing.md) para obtener más información sobre nuestro código de conducta y sobre el proceso de envío de solicitudes de incorporación de cambios. 109 | 110 | ## Licencia 111 | 112 | Este proyecto está publicado bajo la licencia MIT. Consulte el archivo [Licencia](LICENSE) para obtener más información. 113 | 114 | ## Derechos de autor 115 | 116 | Copyright (c) 2018 Microsoft Corporation. Todos los derechos reservados. 117 | --------------------------------------------------------------------------------