Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ Implements the Microsoft Office365 Graph API for the follow
* Place
- List Places
- Get Place
* Teams
- List channel messages
- Get channel message
- Send channel message


## Installation
Expand Down
45 changes: 45 additions & 0 deletions spec/chat_messages/channel_messages_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require "../spec_helper"

describe Office365::Places do
describe "list_messages" do
it "list_messages should return the list of messages in channel" do
SpecHelper.mock_client_auth
SpecHelper.mock_list_channel_msgs

team_id = "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b"
channel_id = "19:[email protected]"

client = Office365::Client.new(**SpecHelper.mock_credentials)

messages = client.list_channel_messages(team_id: team_id, channel_id: channel_id, top: 3)
messages.count.should eq(3)
messages.next_link.should_not be_nil
messages.value.size.should eq(3)
end

it "should get message in channel" do
SpecHelper.mock_client_auth
SpecHelper.mock_get_channel_msg

team_id = "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b"
channel_id = "19:[email protected]"
msg_id = "1614618259349"
client = Office365::Client.new(**SpecHelper.mock_credentials)

message = client.get_channel_message(team_id: team_id, channel_id: channel_id, message_id: msg_id)
message.id.should eq("1612289992105")
end

it "should send message in channel" do
SpecHelper.mock_client_auth
SpecHelper.mock_channel_send_msg

team_id = "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b"
channel_id = "19:[email protected]"
client = Office365::Client.new(**SpecHelper.mock_credentials)

resp = client.send_channel_message(team_id, channel_id, "Hello World")
resp.status_code.should eq(201)
end
end
end
144 changes: 144 additions & 0 deletions spec/chat_messages/messages.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#teams('fbe2bf47-16c8-47cf-b4a5-4b9b187c508b')/channels('19%3A4a95f7d8db4c4e7fae857bcebe0623e6%40thread.tacv2')/messages",
"@odata.count": 3,
"@odata.nextLink": "https://graph.microsoft.com/v1.0/teams/fbe2bf47-16c8-47cf-b4a5-4b9b187c508b/channels/19:[email protected]/messages?$skiptoken=...",
"value": [
{
"id": "1616965872395",
"replyToId": null,
"etag": "1616965872395",
"messageType": "message",
"createdDateTime": "2021-03-28T21:11:12.395Z",
"lastModifiedDateTime": "2021-03-28T21:11:12.395Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl": "https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6%40thread.tacv2/1616965872395?groupId=fbe2bf47-16c8-47cf-b4a5-4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-16eadd115d34&createdTime=1616965872395&parentMessageId=1616965872395",
"policyViolation": null,
"eventDetail": null,
"from": {
"application": null,
"device": null,
"user": {
"id": "8ea0e38b-efb3-4757-924a-5f94061cf8c2",
"displayName": "Robin Kline",
"userIdentityType": "aadUser"
}
},
"body": {
"contentType": "html",
"content": "Hello World <at id=\"0\">Jane Smith</at>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"attachments": [],
"mentions": [
{
"id": 0,
"mentionText": "Jane Smith",
"mentioned": {
"application": null,
"device": null,
"conversation": null,
"user": {
"id": "ef1c916a-3135-4417-ba27-8eb7bd084193",
"displayName": "Jane Smith",
"userIdentityType": "aadUser"
}
}
}
],
"reactions": [],
"messageHistory": []
},
{
"id": "1616963377068",
"replyToId": null,
"etag": "1616963377068",
"messageType": "message",
"createdDateTime": "2021-03-28T20:29:37.068Z",
"lastModifiedDateTime": "2021-03-28T20:29:37.068Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": "",
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl": "https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6%40thread.tacv2/1616963377068?groupId=fbe2bf47-16c8-47cf-b4a5-4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-16eadd115d34&createdTime=1616963377068&parentMessageId=1616963377068",
"policyViolation": null,
"eventDetail": null,
"from": {
"application": null,
"device": null,
"user": {
"id": "8ea0e38b-efb3-4757-924a-5f94061cf8c2",
"displayName": "Robin Kline",
"userIdentityType": "aadUser"
}
},
"body": {
"contentType": "html",
"content": "<div><span><img height=\"145\" src=\"https://graph.microsoft.com/v1.0/teams/...\" width=\"131\"></span></div>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"attachments": [],
"mentions": [],
"reactions": [],
"messageHistory": []
},
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "unknownFutureValue",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl": "https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"attachments": [],
"mentions": [],
"reactions": [],
"messageHistory": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.teamDescriptionUpdatedEventMessageDetail",
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"teamDescription": "Team for Microsoft Teams members",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
]
}
65 changes: 65 additions & 0 deletions spec/spec_helper.cr
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,71 @@ module SpecHelper
],
}
end

def mock_list_channel_msgs
WebMock.stub(:get, "https://graph.microsoft.com/v1.0/teams/fbe2bf47-16c8-47cf-b4a5-4b9b187c508b/channels/19%3A4a95f7d8db4c4e7fae857bcebe0623e6%40thread.tacv2/messages?%24top=3")
.to_return(body: mock_list_channel_messages)
end

def mock_list_channel_messages
File.read("spec/chat_messages/messages.json")
end

def mock_get_channel_msg
WebMock.stub(:get, "https://graph.microsoft.com/v1.0/teams/fbe2bf47-16c8-47cf-b4a5-4b9b187c508b/channels/19%3A4a95f7d8db4c4e7fae857bcebe0623e6%40thread.tacv2/messages/1614618259349")
.to_return(body: mock_get_channel_message)
end

def mock_get_channel_message
%(
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#chats('19%3A8ea0e38b-efb3-4757-924a-5f94061cf8c2_97f62344-57dc-409c-88ad-c4af14158ff5%40unq.gbl.spaces')/messages/$entity",
"id": "1612289992105",
"replyToId": null,
"etag": "1612289992105",
"messageType": "message",
"createdDateTime": "2021-02-02T18:19:52.105Z",
"lastModifiedDateTime": "2021-02-02T18:19:52.105Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": "19:8ea0e38b-efb3-4757-924a-5f94061cf8c2_97f62344-57dc-409c-88ad-c4af14158ff5@unq.gbl.spaces",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"channelIdentity": null,
"policyViolation": null,
"eventDetail": null,
"from": {
"application": null,
"device": null,
"conversation": null,
"user": {
"@odata.type": "#microsoft.graph.teamworkUserIdentity",
"id": "8ea0e38b-efb3-4757-924a-5f94061cf8c2",
"displayName": "Robin Kline",
"userIdentityType": "aadUser",
"tenantId": "e61ef81e-8bd8-476a-92e8-4a62f8426fca"
}
},
"body": {
"contentType": "text",
"content": "test"
},
"attachments": [],
"mentions": [],
"reactions": [],
"messageHistory": []
}
)
end

def mock_channel_send_msg
WebMock.stub(:post, "https://graph.microsoft.com/v1.0/teams/fbe2bf47-16c8-47cf-b4a5-4b9b187c508b/channels/19%3A4a95f7d8db4c4e7fae857bcebe0623e6%40thread.tacv2/messages")
.with(body: "{\"body\":{\"content\":\"Hello World\",\"contentType\":\"TEXT\"}}", headers: {"Authorization" => "Bearer access_token", "Content-Type" => "application/json", "Prefer" => "IdType=\"ImmutableId\""})
.to_return(status: 201, body: "")
end
end

Spec.before_each do
Expand Down
8 changes: 4 additions & 4 deletions src/attachments.cr
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module Office365::Attachments
name : String,
content_bytes : String,
calendar_group_id : String? = nil,
calendar_id : String? = nil
calendar_id : String? = nil,
)
attachment = Attachment.new(name, content_bytes)
endpoint = event_attachment_path(mailbox, event_id, calendar_group_id, calendar_id)
Expand Down Expand Up @@ -57,7 +57,7 @@ module Office365::Attachments
mailbox : String,
event_id : String,
calendar_group_id : String? = nil,
calendar_id : String? = nil
calendar_id : String? = nil,
)
endpoint = "#{event_attachment_path(mailbox, event_id, calendar_group_id, calendar_id)}/#{id}"
graph_http_request(request_method: "GET", path: endpoint)
Expand All @@ -83,7 +83,7 @@ module Office365::Attachments
mailbox : String,
event_id : String,
calendar_group_id : String? = nil,
calendar_id : String? = nil
calendar_id : String? = nil,
)
endpoint = "#{event_attachment_path(mailbox, event_id, calendar_group_id, calendar_id)}/#{id}"

Expand All @@ -109,7 +109,7 @@ module Office365::Attachments
mailbox : String,
event_id : String,
calendar_group_id : String? = nil,
calendar_id : String? = nil
calendar_id : String? = nil,
)
endpoint = ""

Expand Down
58 changes: 58 additions & 0 deletions src/channel_messages.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
module Office365::ChannelMessages
def list_channel_messages_request(team_id : String, channel_id : String, filter : String? = nil, match : String? = nil, top : Int32? = nil, skip : Int32? = nil, count : Bool? = nil)
query_params = URI::Params.new

if top
query_params["$top"] = top.to_s
end

if count
query_params["$count"] = count.to_s
end

if filter
query_params["$filter"] = filter
end

if match
query_params["$select"] = match
end

if skip
query_params["$skip"] = skip.to_s
end

graph_http_request(request_method: "GET", path: "/v1.0/teams/#{team_id}/channels/#{channel_id}/messages", query: query_params)
end

def list_channel_messages(*args, **opts)
request = list_channel_messages_request(*args, **opts)
response = graph_request(request)

list_channel_messages(response)
end

def list_channel_messages(response : HTTP::Client::Response)
ChatMessageList.from_json(response.body)
end

def get_channel_message(team_id : String, channel_id : String, message_id : String)
request = graph_http_request(request_method: "GET", path: "/v1.0/teams/#{team_id}/channels/#{channel_id}/messages/#{message_id}")
response = graph_request(request)
ChatMessage.from_json(response.body)
end

def send_channel_message(team_id : String, channel_id : String, message : String | IO)
body = message.is_a?(IO) ? message.gets_to_end : message
chat = ChatMessage.new(body: body)
request = graph_http_request(request_method: "POST", path: "/v1.0/teams/#{team_id}/channels/#{channel_id}/messages", data: chat.to_json)
graph_request(request)
end

def send_channel_message(team_id : String, channel_id : String, message : String | IO, content_type : String)
body = message.is_a?(IO) ? message.gets_to_end : message
chat = ChatMessage.new(content: body, content_type: content_type)
request = graph_http_request(request_method: "POST", path: "/v1.0/teams/#{team_id}/channels/#{channel_id}/messages", data: chat.to_json)
graph_request(request)
end
end
4 changes: 3 additions & 1 deletion src/client.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require "./subscriptions"
require "./odata"
require "./password_credentials"
require "./places"
require "./channel_messages"

module Office365
USERS_BASE = "/v1.0/users"
Expand All @@ -27,6 +28,7 @@ module Office365
include Office365::OData
include Office365::PasswordCredentials
include Office365::Places
include Office365::ChannelMessages

LOGIN_URI = URI.parse("https://login.microsoftonline.com")
GRAPH_URI = URI.parse("https://graph.microsoft.com/")
Expand Down Expand Up @@ -114,7 +116,7 @@ module Office365
path : String,
data : String? = nil,
query : URI::Params? = nil,
headers : HTTP::Headers = default_headers
headers : HTTP::Headers = default_headers,
) : HTTP::Request
uri = if query && !query.empty?
"#{URI.encode_path(URI.decode(path))}?#{query}"
Expand Down
Loading