[Office365GroupsMail] Open source connector (#310)

* [Office365GroupsMail] Open source connector

Adding the following operations to the open source repo:

- `ListConversations`
- `GetGroupConversation`
- `ListConversationThreads`
- `ListGroupThreads`
- `GetConversationThread`
- `DeleteConversationThread`
- `ListThreadPosts`
- `GetThreadPost`
- `GetAttachments`
- `ListGroups`

* [Office365GroupsMail] PR Fixes

Addressing the following issues:
- Scopes: remove `offline_access`.
- Properties: remove `token:TenantId`: this connectors does not use it.
- ListGroups operation: Change `Office 365 Groups Mail` to `Microsoft 365 Groups Mail`

* [Office365GroupsMail] PR fixes

1. Enable pagination by adding a policy template.
2. Fix publisher
3. Fix product name in readme.md

* [Office365GroupsMail] PR fixes

1. Enable pagination by adding a policy template.
2. Fix publisher
3. Fix product name in readme.md

* [Office365GroupsMail] Remove List Groups from pagination

* Update title

* Remove test ClientId

Co-authored-by: Laura Natalia Borbolla Palacios <laborbol@microsoft.com>
This commit is contained in:
Laura Borbolla 2020-07-26 20:21:56 -07:00 коммит произвёл GitHub
Родитель c717b4a608
Коммит d340b5b0b0
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 908 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,798 @@
{
"swagger": "2.0",
"info": {
"description": "The Microsoft 365 Groups Mail connector allows users to work with data located in a Microsoft 365 Group mailbox. The functionality in this connector works independently from a single user's personal mailbox and allows users to work with any Group they can access within their organization. The connector works off the Microsoft Graph API, and uses terminology specified in a Microsoft 365 Groups documentation within the Graph API. Learn more in the connector documentation.",
"title": "Microsoft 365 Groups Mail",
"version": "1.0",
"x-ms-api-annotation": {
"status": "Preview"
},
"contact": {
"name": "Microsoft"
}
},
"host": "graph.microsoft.com",
"basePath": "/",
"schemes": [
"https"
],
"consumes": [],
"produces": [],
"paths": {
"/v1.0/groups/{groupId}/conversations": {
"get": {
"operationId": "ListConversations",
"description": "Get all the conversations in this group.",
"summary": "List the conversations of a group",
"parameters": [
{
"$ref": "#/parameters/groupId__in_path"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "object",
"properties": {
"@odata.nextLink": {
"description": "Link to get next page of results",
"type": "string",
"x-ms-summary": "Next link",
"x-ms-visibility": "internal"
},
"value": {
"type": "array",
"items": {
"$ref": "#/definitions/Conversation"
}
}
}
}
},
"404": {
"description": "Invalid group",
"schema": {
"type": "object"
}
}
},
"x-ms-pageable": {
"nextLinkName": "@odata.nextLink"
}
}
},
"/v1.0/groups/{groupId}/conversations/{conversationId}": {
"get": {
"operationId": "GetGroupConversation",
"description": "Retrieves the properties of a particular conversation.",
"summary": "Get a group conversation",
"parameters": [
{
"$ref": "#/parameters/groupId__in_path"
},
{
"name": "conversationId",
"in": "path",
"required": true,
"type": "string",
"x-ms-url-encoding": "single",
"description": "Enter the conversation ID.",
"x-ms-summary": "Conversation ID"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/Conversation"
}
}
}
}
},
"/v1.0/groups/{groupId}/conversations/{conversationId}/threads": {
"get": {
"operationId": "ListConversationThreads",
"description": "Get all the threads in a group conversation.",
"summary": "List the conversation threads of a conversation",
"parameters": [
{
"$ref": "#/parameters/groupId__in_path"
},
{
"name": "conversationId",
"in": "path",
"required": true,
"type": "string",
"x-ms-url-encoding": "single",
"description": "Enter the conversation ID.",
"x-ms-summary": "Conversation ID"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "object",
"properties": {
"@odata.nextLink": {
"description": "Link to get next page of results",
"type": "string",
"x-ms-summary": "Next link",
"x-ms-visibility": "internal"
},
"@odata.context": {
"type": "string",
"description": "The Odata.context link.",
"x-ms-summary": "OData context",
"x-ms-visibility": "internal"
},
"value": {
"type": "array",
"items": {
"$ref": "#/definitions/ConversationThread"
}
}
}
}
}
},
"x-ms-pageable": {
"nextLinkName": "@odata.nextLink"
}
}
},
"/v1.0/groups/{groupId}/threads": {
"get": {
"operationId": "ListGroupThreads",
"description": "Get all the threads of a group.",
"summary": "List the threads of a group",
"parameters": [
{
"$ref": "#/parameters/groupId__in_path"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "object",
"properties": {
"@odata.nextLink": {
"description": "Link to get next page of results",
"type": "string",
"x-ms-summary": "Next link",
"x-ms-visibility": "internal"
},
"value": {
"type": "array",
"items": {
"$ref": "#/definitions/ConversationThread"
}
}
}
}
}
},
"x-ms-pageable": {
"nextLinkName": "@odata.nextLink"
}
}
},
"/v1.0/groups/{groupId}/threads/{threadId}": {
"get": {
"operationId": "GetConversationThread",
"description": "Get a specific thread that belongs to a group.",
"summary": "Get a conversation thread",
"parameters": [
{
"$ref": "#/parameters/groupId__in_path"
},
{
"name": "threadId",
"in": "path",
"required": true,
"type": "string",
"x-ms-url-encoding": "single",
"description": "Enter the conversation thread ID.",
"x-ms-summary": "Thread ID"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/ConversationThread"
}
}
}
},
"delete": {
"operationId": "DeleteConversationThread",
"description": "Deletes the specified conversation thread.",
"summary": "Delete a conversation thread",
"parameters": [
{
"$ref": "#/parameters/groupId__in_path"
},
{
"name": "threadId",
"in": "path",
"required": true,
"type": "string",
"x-ms-url-encoding": "single",
"description": "Enter the conversation thread ID.",
"x-ms-summary": "Thread ID"
}
],
"responses": {
"204": {
"description": "Success"
}
}
}
},
"/v1.0/groups/{groupId}/threads/{threadId}/posts": {
"get": {
"operationId": "ListThreadPosts",
"description": "Get all the posts of the specified conversation thread.",
"summary": "List the posts of a conversation thread",
"parameters": [
{
"$ref": "#/parameters/groupId__in_path"
},
{
"name": "threadId",
"in": "path",
"required": true,
"type": "string",
"x-ms-url-encoding": "single",
"description": "Enter the conversation thread ID.",
"x-ms-summary": "Thread ID"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "object",
"properties": {
"@odata.nextLink": {
"description": "Link to get next page of results",
"type": "string",
"x-ms-summary": "Next link",
"x-ms-visibility": "internal"
},
"@odata.context": {
"type": "string",
"description": "The @odata.context link.",
"x-ms-visibility": "internal"
},
"value": {
"type": "array",
"items": {
"$ref": "#/definitions/Post"
},
"description": "Array containing the posts in the specified thread."
}
}
}
}
},
"x-ms-pageable": {
"nextLinkName": "@odata.nextLink"
}
}
},
"/v1.0/groups/{groupId}/threads/{threadId}/posts/{postId}": {
"get": {
"operationId": "GetThreadPost",
"description": "Retrieves a post in a specified thread.",
"summary": "Get a thread post",
"parameters": [
{
"$ref": "#/parameters/groupId__in_path"
},
{
"name": "threadId",
"in": "path",
"required": true,
"type": "string",
"x-ms-url-encoding": "single",
"description": "Enter the conversation thread ID.",
"x-ms-summary": "Thread ID"
},
{
"name": "postId",
"in": "path",
"required": true,
"type": "string",
"x-ms-url-encoding": "single",
"description": "Enter the post ID.",
"x-ms-summary": "Post ID"
},
{
"$ref": "#/parameters/expand__in_query"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/Post"
}
}
}
}
},
"/v1.0/groups/{groupId}/threads/{threadId}/posts/{postId}/attachments": {
"get": {
"operationId": "GetAttachments",
"description": "Retrieve a list of attachments that belong to a post.",
"summary": "List the attachments of a post",
"parameters": [
{
"$ref": "#/parameters/groupId__in_path"
},
{
"name": "threadId",
"in": "path",
"required": true,
"type": "string",
"x-ms-url-encoding": "single",
"description": "Enter the conversation thread ID.",
"x-ms-summary": "Thread ID"
},
{
"name": "postId",
"in": "path",
"required": true,
"type": "string",
"x-ms-url-encoding": "single",
"description": "Enter the post ID.",
"x-ms-summary": "Post ID"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "object",
"properties": {
"@odata.nextLink": {
"description": "Link to get next page of results",
"type": "string",
"x-ms-summary": "Next link",
"x-ms-visibility": "internal"
},
"@odata.context": {
"type": "string",
"description": "The @odata.context link.",
"x-ms-visibility": "internal"
},
"value": {
"type": "array",
"items": {
"$ref": "#/definitions/Attachment"
},
"description": "Array containing the attachments of the post."
}
}
}
}
},
"x-ms-pageable": {
"nextLinkName": "@odata.nextLink"
}
}
},
"/v1.0/me/memberOf/$/microsoft.graph.group": {
"get": {
"operationId": "ListGroups",
"description": "Retrieves all Microsoft 365 Groups the user is part of.",
"summary": "List user groups",
"x-ms-visibility": "internal",
"parameters": [
{
"name": "$filter",
"in": "query",
"required": true,
"type": "string",
"x-ms-visibility": "internal",
"default": "groupTypes/any(c:c eq 'Unified')"
},
{
"name": "$select",
"in": "query",
"required": true,
"type": "string",
"x-ms-visibility": "internal",
"default": "id,displayName"
},
{
"name": "$top",
"in": "query",
"required": true,
"type": "integer",
"x-ms-visibility": "internal",
"default": 999
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "object",
"properties": {
"value": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"x-ms-summary": "Group ID"
},
"displayName": {
"type": "string",
"x-ms-summary": "Group display name"
},
"visibility": {
"type": "string",
"x-ms-summary": "Group visibility"
}
}
},
"description": "Array with the groups the user is part of."
}
}
}
}
}
}
}
},
"definitions": {
"Conversation": {
"type": "object",
"properties": {
"id": {
"type": "string",
"title": "Conversation ID",
"x-ms-summary": "Conversation ID",
"description": "The conversations's unique identifier."
},
"topic": {
"type": "string",
"title": "Conversation topic",
"x-ms-summary": "Conversation topic",
"description": "The topic of the conversation."
},
"hasAttachments": {
"type": "boolean",
"title": "Has attachments?",
"x-ms-summary": "Has attachments?",
"description": "Indicates whether any of the posts within this Conversation has at least one attachment."
},
"lastDeliveredDateTime": {
"type": "string",
"format": "date-time",
"title": "Last delivered timestamp",
"x-ms-summary": "Last delivered timestamp",
"description": "The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time."
},
"uniqueSenders": {
"type": "array",
"items": {
"type": "string"
},
"title": "Unique senders array",
"x-ms-summary": "Unique senders array",
"description": "All the users that sent a message to this Conversation."
},
"preview": {
"type": "string",
"title": "Preview",
"x-ms-summary": "Preview",
"description": "A short summary from the body of the latest post in this Conversation."
},
"threads": {
"x-ms-visibility": "internal",
"type": "array",
"items": {
"$ref": "#/definitions/ConversationThread"
}
}
},
"description": "Conversation object."
},
"ConversationThread": {
"type": "object",
"properties": {
"id": {
"type": "string",
"title": "Conversation thread ID",
"x-ms-summary": "Conversation thread ID",
"description": "The conversation thread's unique identifier."
},
"topic": {
"type": "string",
"title": "Conversation topic",
"x-ms-summary": "Conversation topic",
"description": "The topic of the conversation."
},
"hasAttachments": {
"type": "boolean",
"title": "Has attachments?",
"x-ms-summary": "Has attachments?",
"description": "Indicates whether any of the posts within this Conversation has at least one attachment."
},
"lastDeliveredDateTime": {
"type": "string",
"format": "date-time",
"title": "Last delivered timestamp",
"x-ms-summary": "Last delivered timestamp",
"description": "The Timestamp type represents date and time information using ISO 8601 format and is always in UTC time."
},
"uniqueSenders": {
"type": "array",
"items": {
"type": "string"
},
"title": "Unique senders array",
"x-ms-summary": "Unique senders array",
"description": "All the users that sent a message to this Conversation."
},
"preview": {
"type": "string",
"title": "Preview",
"x-ms-summary": "Preview",
"description": "A short summary from the body of the latest post in this Conversation."
},
"isLocked": {
"type": "boolean",
"title": "Is Locked?",
"x-ms-summary": "Is Locked?",
"description": "Indicates if the thread is locked."
},
"toRecipients": {
"type": "array",
"items": {
"$ref": "#/definitions/EmailAddress"
},
"description": "The To: recipients for the thread."
},
"ccRecipients": {
"type": "array",
"items": {
"$ref": "#/definitions/EmailAddress"
},
"description": "The Cc: recipients for the thread."
},
"posts": {
"x-ms-visibility": "internal",
"type": "array",
"items": {
"$ref": "#/definitions/Post"
}
}
},
"description": "Conversation thread object."
},
"Post": {
"type": "object",
"properties": {
"id": {
"type": "string",
"title": "Post ID",
"x-ms-summary": "Post ID",
"description": "The post's unique identifier."
},
"createdDateTime": {
"type": "string",
"format": "date-time",
"title": "Created timestamp of the post",
"x-ms-summary": "Post created timestamp"
},
"lastModifiedDateTime": {
"type": "string",
"format": "date-time",
"title": "Last modified timestamp of the post",
"x-ms-summary": "Post last modified timestamp"
},
"changeKey": {
"type": "string",
"title": "Change Key",
"x-ms-summary": "Post change Key",
"description": "Identifies the version of the post."
},
"conversationId": {
"type": "string",
"title": "Conversation ID",
"x-ms-summary": "Post conversation ID",
"description": "Unique ID of the conversation the post belongs to."
},
"conversationThreadId": {
"type": "string",
"title": "Conversation thread ID",
"x-ms-summary": "Post conversation thread ID",
"description": "Unique ID of the conversation thread the post belongs to."
},
"categories": {
"type": "array",
"items": {
"type": "string"
},
"title": "Categories",
"x-ms-summary": "Post categories",
"description": "The categories associated with the post."
},
"receivedDateTime": {
"type": "string",
"format": "date-time",
"title": "Received timestamp",
"x-ms-summary": "Post received timestamp",
"description": "Post received timestamp."
},
"hasAttachments": {
"type": "boolean",
"title": "Has attachments?",
"x-ms-summary": "Has attachments?",
"description": "Indicates whether the post has at least one attachment."
},
"newParticipants": {
"type": "array",
"items": {
"$ref": "#/definitions/EmailAddress"
},
"title": "New participants",
"x-ms-summary": "New participants",
"description": "Conversation participants that were added to the thread as part of this post."
},
"body": {
"$ref": "#/definitions/ItemBody"
},
"from": {
"$ref": "#/definitions/EmailAddress"
},
"sender": {
"$ref": "#/definitions/EmailAddress"
},
"attachments": {
"type": "array",
"items": {
"$ref": "#/definitions/Attachment"
}
}
},
"description": "Represents an individual Post item within a conversationThread entity."
},
"Attachment": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Id of the attachment.",
"x-ms-summary": "Attachment ID"
},
"name": {
"type": "string",
"description": "Name of attachment.",
"x-ms-summary": "Attachment name"
},
"contentType": {
"type": "string",
"description": "Content type of attachment.",
"x-ms-summary": "Attachment content Type"
},
"size": {
"type": "integer",
"format": "int32",
"description": "Size of attachment.",
"x-ms-summary": "Attachment size"
},
"contentBytes": {
"type": "string",
"format": "byte",
"description": "Content of attachment.",
"x-ms-summary": "Attachment content bytes"
}
}
},
"EmailAddress": {
"type": "object",
"properties": {
"emailAddress": {
"type": "object",
"properties": {
"name": {
"type": "string",
"x-ms-summary": "Name of the user"
},
"address": {
"type": "string",
"format": "email",
"x-ms-summary": "Email address of the user"
}
},
"description": "Represents information about a user in the sending or receiving end of an event, message or group post."
}
}
},
"ItemBody": {
"type": "object",
"properties": {
"contentType": {
"type": "string",
"x-ms-summary": "Body content type",
"x-ms-visibility": "advanced",
"description": "Content type of the body."
},
"content": {
"type": "string",
"x-ms-summary": "Body content",
"description": "Content of the body."
}
},
"description": "Represents properties of the body of an item, such as a message, event or group post."
}
},
"parameters": {
"groupId__in_path": {
"name": "groupId",
"in": "path",
"description": "Pick a group from the drop down or enter group id.",
"required": true,
"x-ms-summary": "Group ID",
"x-ms-url-encoding": "single",
"x-ms-dynamic-values": {
"operationId": "ListGroups",
"parameters": {
"$filter": "groupTypes/any(c:c eq 'Unified')",
"$select": "id,displayName",
"$top": 999
},
"value-path": "id",
"value-title": "displayName",
"value-collection": "value"
},
"x-ms-visibility": "important",
"type": "string"
},
"expand__in_query": {
"name": "$expand",
"in": "query",
"required": true,
"type": "string",
"default": "attachments",
"x-ms-visibility": "internal"
}
},
"responses": {},
"securityDefinitions": {
"undefined": {
"type": "oauth2",
"flow": "accessCode",
"authorizationUrl": "https://login.windows.net/common/oauth2/authorize",
"tokenUrl": "https://login.windows.net/common/oauth2/authorize",
"scopes": {}
}
},
"security": [
{
"undefined": []
}
],
"tags": [],
"x-ms-connector-metadata": [
{
"propertyName": "Website",
"propertyValue": "https://docs.microsoft.com/en-us/graph/api/resources/groups-overview?view=graph-rest-1.0"
},
{
"propertyName": "Categories",
"propertyValue": "Productivity"
}
]
}

Просмотреть файл

@ -0,0 +1,54 @@
{
"properties": {
"capabilities": [
"actions",
"triggers"
],
"connectionParameters": {
"token": {
"type": "oauthSetting",
"oAuthSettings": {
"identityProvider": "aad",
"clientId": "<<Place here your CliendId>>",
"scopes": [
"Group.ReadWrite.All"
],
"redirectMode": "Global",
"redirectUrl": "https://global.consent.azure-apim.net/redirect",
"properties": {
"AzureActiveDirectoryResourceId": "https://graph.microsoft.com"
},
"customParameters": {
"loginUri": {
"value": "https://login.windows.net"
},
"tenantId": {
"value": "common"
},
"resourceUri": {
"value": "https://graph.microsoft.com/"
}
}
}
}
},
"iconBrandColor": "#EB3C00",
"publisher": "Microsoft",
"policyTemplateInstances": [
{
"parameters": {
"x-ms-apimTemplate-operationName": [
"GetAttachments",
"ListThreadPosts",
"ListGroupThreads",
"ListConversationThreads",
"ListConversations"
],
"x-ms-apimTemplateParameter.nextLinkPropertyName": "@odata.nextLink"
},
"templateId": "updatenextlink",
"title": "Updates next link to make pagination work"
}
]
}
}

Просмотреть файл

@ -0,0 +1,56 @@
# Microsoft 365 Groups Mail Connector
Microsoft Graph REST API v1.0 allows users to create and manage Microsoft 365 Groups functionality. This connector exposes a subset of these APIs as operations in Microsoft Flow and PowerApps.
See more documentation [[here](https://docs.microsoft.com/en-us/graph/api/resources/groups-overview?view=graph-rest-1.0)].
## Pre-requisites
You will need the following to proceed:
- A Microsoft PowerApps or Microsoft Flow plan with custom connector feature.
- An Azure subscription
- The Power platform CLI tools
- Be a member of a Microsoft 365 Group
## Building the connector
Since the APIs used by the connector are secured by Azure Active Directory (AD), we first need to set up a few thing in Azure AD for connector to securely access them. After this setup, you can create and test the connector.
### Set up a new application in the Azure Active Directory for your custom connector
Since the connector uses OAuth as authentication type, we first need to register an application in Azure AD. This application will be used to get the authorization token required to invoke rest APIs used by the connector on user's behalf. You can read more about this [[here](https://docs.microsoft.com/en-us/azure/active-directory/develop/authentication-vs-authorization)] and follow the steps below:
1. Create an Azure AD application This can be done using [Azure Portal](https://portal.azure.com), by following the steps [[here](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app)]. Once created, note down the value of Application (Client) ID. You will need this later.
2. Configure (or update) your application to access the Azure Active Directory API This step will ensure that your application can successfully retrieve an access token on behalf of your users. To do this, follow the steps [[here](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-configure-app-access-web-apis)].
- For redirect URI, use `https://global.consent.azure-apim.net/redirect`
- For the credentials, use a **client secret** (and not certificates).
>Remember to note the secret down, you will need this later and it is shown only once.
### Deploying the connector
Run the following commands and follow the prompts:
```bash
paconn create --api-def apiDefinition.swagger.json --api-prop apiProperties.json --secret <client_secret>
```
## Supported Operations
The connector supports the following operations:
- `ListConversations`: Get all the conversations in this group.
- `GetGroupConversation`: Retrieves the properties of a particular conversation.
- `ListConversationThreads`: Get all the threads in a group conversation.
- `ListGroupThreads`: Get all the threads of a group.
- `GetConversationThread`: Get a specific thread that belongs to a group.
- `DeleteConversationThread`: Deletes the specified conversation thread.
- `ListThreadPosts`: Get all the posts of the specified conversation thread.
- `GetThreadPost`: Retrieves a post in a specified thread.
- `GetAttachments`: Retrieve a list of attachments that belong to a post.
- `ListGroups`: Retrieves all Microsoft 365 Groups the user is part of (operation with `internal` visibility used to populate the dropdowns).
## Notes
If you want that all users are able to sign in (and use the connector), instead of only admins, you can grant admin consent to the application. Follow instructions on how to grant admin consent to an application [[here](https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/grant-admin-consent)].