TEAMS 채팅방 생성 및 메시지 발송까지
우선 시작하기에 앞서서 TEAMS의 graph api는 application의 채팅방 생성(Create chat)을 지원하지 않습니다. 이를 해결하기 위해서 진행한 내용을 정리했습니다.
1. 채팅방 생성을 하고, 메시지를 발송하는 역할의 계정을 생성
해야 합니다.
계정의 Access token을 이용해서 채팅방을 생성하고 메시지 발송을 하는 teams graph api를 호출합니다.
2. 계정 생성이 완료 되었으면, 채팅 관련 권한을 할당합니다.
권한 할당은 graph-explorer를 통해서 쉽게 할 수 있습니다.
3. 사용자의 Access token을 저장하는 프로그램을 작성합니다.
시작에도 이야기 했듯이 Teams graph api의 Create chat기능은 Delegated를 통해서만 사용이 가능합니다.
Permission type | Permissions (from least to most privileged) |
---|---|
Delegated (work or school account) | Chat.Create, Chat.ReadWrite |
Delegated (personal Microsoft account) | Not supported. |
Application | Not supported. |
따라서 사용자의 Access token을 받아오는 프로그램이 필요합니다.
여기에는 2가지 옵션이 있습니다.
- app 을 생성해서 등록 후 Access token을 생성하는 방법
- graph-explorer를 통해서 Access token을 획득하는 방법
기본적으로 사용자의 로그인 행위(위임) 없이는 원하는 Access token 생성이 불가능 합니다.
제 경우는 puppeteer와 graph-explorer 서비스를 활용해 Access token을 서버에 저장 후 사용했습니다.
Access token은 1시간 동안 유효합니다.
매 50분마다 Access token 재할당 받아 서버에 저장하도록 처리했습니다.
4. 채팅방 생성
채팅방을 생성 할때 가장 중요한 옵션은 그룹 대화방
과 일대일 대화방
에 대한 결정입니다.
- 일대일 대화방은 다른 사용자를 초대하지 못합니다.
- 그룹 대화방의 경우 다른 사용자를 초대 / 제외가 가능합니다. 다만, graph api 를 이용해서 채팅방을 생성시 이전 대화목록을 보여주는 옵션을 현재까진 지원하지 않습니다.
기본 형식
POST /chats
요청 예제
- “https://graph.microsoft.com/v1.0/users(‘kk.lim@gsretail.com’)” 에서 users 이후 이메일 정보를 입력해도 됩니다. 사용자 id의 경우 사용자 정보를 조회 하면 알 수 있습니다.
- members에 Access token의 소유자는 무조건 포함되어야 합니다.
POST https://graph.microsoft.com/v1.0/chats
Content-Type: application/json
{
"chatType": "oneOnOne", // 그룹일 경우 'group'로 설정해야합니다.
"members": [
{
"@odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": ["owner"],
"user@odata.bind": "https://graph.microsoft.com/v1.0/users('kk.lim@gsretail.com')"
},
{
"@odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": ["owner"],
"user@odata.bind": "https://graph.microsoft.com/v1.0/users('82af01c5-f7cc-4a2e-a728-3a5df21afd9d')"
}
]
}
응답 예제
HTTP/1.1 201 Created
Content-Type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#chats/$entity",
"id": "19:82fe7758-5bb3-4f0d-a43f-e555fd399c6f_8c0a1a67-50ce-4114-bb6c-da9c5dbcf6ca@unq.gbl.spaces",
"topic": null,
"createdDateTime": "2020-12-04T23:10:28.51Z",
"lastUpdatedDateTime": "2020-12-04T23:10:28.51Z",
"chatType": "oneOnOne"
}
일대일 채팅방은 다시 채팅방을 생성하여도 동일한 id로 응답합니다.
id
값은 메시지를 전송하거나, 다른 사람을 초대 / 제외 시 사용됩니다.
아래 예제 부터는 그룹 채팅방을 생성하고
19:2da4c29f6d7041eca70b638b43d45437@thread.v2
을 응답 id로 받았을 경우입니다.
5. 메시지 전송 처리
메세지 전송을 위해서는 아래와 같은 권한이 필요합니다.
Permission type | Permissions (from least to most privileged) |
---|---|
Delegated (work or school account) | ChatMessage.Send, Chat.ReadWrite |
Delegated (personal Microsoft account) | Not supported. |
Application | Not supported. |
기본 형식
POST /chats/{chat-id}/messages
요청 예제
POST https://graph.microsoft.com/v1.0/chats/19:2da4c29f6d7041eca70b638b43d45437@thread.v2/messages
Content-type: application/json
{
"body": {
"content": "Hello world",
"contentType": "text" // 기본 값은 text 이며, "html"으로 설정하면 html 형식으로 전송이 가능합니다.
}
}
응답 예제
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#chats('19%3A2da4c29f6d7041eca70b638b43d45437%40thread.v2')/messages/$entity",
"id": "1616991463150",
"replyToId": null,
"etag": "1616991463150",
"messageType": "message",
"createdDateTime": "2021-03-29T04:17:43.15Z",
"lastModifiedDateTime": "2021-03-29T04:17:43.15Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": "19:2da4c29f6d7041eca70b638b43d45437@thread.v2",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"channelIdentity": null,
"policyViolation": null,
"from": {
"application": null,
"device": null,
"conversation": null,
"user": {
"id": "8ea0e38b-efb3-4757-924a-5f94061cf8c2",
"displayName": "Robin Kline",
"userIdentityType": "aadUser"
}
},
"body": {
"contentType": "text",
"content": "Hello World"
},
"attachments": [],
"mentions": [],
"reactions": []
}
6. 멤버 초대 처리
기본 형식
POST /chats/{chat-id}/members
요청 예제
POST https://graph.microsoft.com/v1.0/chats/19:cf66807577b149cca1b7af0c32eec122@thread.v2/members
content-type: application/json
{
"@odata.type": "#microsoft.graph.aadUserConversationMember",
"user@odata.bind": "https://graph.microsoft.com/v1.0/users/8b081ef6-4792-4def-b2c9-c363a1bf41d5",
"visibleHistoryStartDateTime": "2019-04-18T23:51:43.255Z",
"roles": ["owner"]
}
응답 예제
HTTP/1.1 201 Created
Location: /chats/19:cf66807577b149cca1b7af0c32eec122@thread.v2/members/MCMjMjQzMmI1N2ItMGFiZC00M2RiLWFhN2ItMTZlYWRkMTE1ZDM0IyMxOTpiZDlkYTQ2MzIzYWY0MjUzOTZkMGZhNjcyMDAyODk4NEB0aHJlYWQudjIjIzQ4YmY5ZDUyLWRjYTctNGE1Zi04Mzk4LTM3Yjk1Y2M3YmQ4Mw==
7. 멤버 제외 처리
멤버 제외의 경우 채팅방의 멤버 id를 조회 하고 해당 id를 DELETE 호출을 해야 합니다.
7.1 멤버 조회
기본 형식
GET /chats/{chat-id}/members
GET /users/{user-id | user-principal-name}/chats/{chat-id}/members
요청 예제
GET https://graph.microsoft.com/v1.0/me/chats/19:8b081ef6-4792-4def-b2c9-c363a1bf41d5_5031bb31-22c0-4f6f-9f73-91d34ab2b32d@unq.gbl.spaces/members
응답 예제
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users('8b081ef6-4792-4def-b2c9-c363a1bf41d5')/chats('19%3A8b081ef6-4792-4def-b2c9-c363a1bf41d5_5031bb31-22c0-4f6f-9f73-91d34ab2b32d%40unq.gbl.spaces')/members",
"@odata.count":3,
"value":[
{
"@odata.type":"#microsoft.graph.aadUserConversationMember",
"id":"8b081ef6-4792-4def-b2c9-c363a1bf41d5",
"roles":[
"owner"
],
"displayName":"John Doe",
"userId":"8b081ef6-4792-4def-b2c9-c363a1bf41d5",
"email":"kk.lim@gsretail.com",
"tenantId":"6e5147da-6a35-4275-b3f3-fc069456b6eb",
"visibleHistoryStartDateTime":"2019-04-18T23:51:43.255Z"
},
{
"@odata.type":"#microsoft.graph.aadUserConversationMember",
"id":"2de87aaf-844d-4def-9dee-2c317f0be1b3",
"roles":[
"owner"
],
"displayName":"Bart Hogan",
"userId":"2de87aaf-844d-4def-9dee-2c317f0be1b3",
"email":"abc.def@gsretail.com",
"tenantId":"6e5147da-6a35-4275-b3f3-fc069456b6eb",
"visibleHistoryStartDateTime":"0001-01-01T00:00:00Z"
},
{
"@odata.type":"#microsoft.graph.aadUserConversationMember",
"id":"07ad17ad-ada5-4f1f-a650-7a963886a8a7",
"roles":[
"owner"
],
"displayName":"Minna Pham",
"userId":"07ad17ad-ada5-4f1f-a650-7a963886a8a7",
"email":"ghi.hkl@gsretail.com",
"tenantId":"6e5147da-6a35-4275-b3f3-fc069456b6eb",
"visibleHistoryStartDateTime":"2019-04-18T23:51:43.255Z"
}
]
}
7.2 멤버 제외
채팅창의 멤버정보를 조회 후 원하는 제외를 원하는 멤버의 email
정보와 함게 제공되는 id
값으로 삭제를 진행합니다.
기본 형식
DELETE /chats/{chat-id}/members/{membership-id}
요청 예제
DELETE https://graph.microsoft.com/v1.0/chats/19:cf66807577b149cca1b7af0c32eec122@thread.v2/members/MCMjMjQzMmI1N2ItMGFiZC00M2RiLWFhN2ItMTZlYWRkMTE1ZDM0IyMxOTpiZDlkYTQ2MzIzYWY0MjUzOTZkMGZhNjcyMDAyODk4NEB0aHJlYWQudjIjIzQ4YmY5ZDUyLWRjYTctNGE1Zi04Mzk4LTM3Yjk1Y2M3YmQ4Mw==
응담 예제
HTTP/1.1 204 No Content
7. 마치며
현재 Teams graph api는 app이 처리 할수 있는 역할이 매우 제한적입니다.
기존에 workplace에서 사용하던 방식이 필요하여 고민하고 처리한 내용을 정리 했습니다. teams를 사용하는 분들에게 도움이 되었으면 좋겠네요.
또한 Teams graph api에서 많은 기능을 제공하는 업데이트를 기대하고 있습니다.