chat_sdk-teams 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/chat_sdk/teams/adapter.rb +45 -29
- data/lib/chat_sdk/teams/graph_client.rb +83 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 26f507aa00b122a92a3b175ec79248a0cd4cf0d8a63d192ff5ada84eb8a4b307
|
|
4
|
+
data.tar.gz: 54295b00effe5c4d7b37b906209dbcbb2685068da76eee7f3a68c020cdf391e9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aeac84b76ec10f316e3836676d85826d708b026293897ca7abfe77b3532af466519d2acc267ac41a21429d02af91feac58623ce40c6146eeda3f9fc35a204d56
|
|
7
|
+
data.tar.gz: 3535fa1ecd603951f94d2df234f1fdc68239c66624cc0adf393be7def189168d910b377d8de1f6598178e60f94de5bdc05c1f630f9b3b35b2314540fa592bd59
|
|
@@ -4,12 +4,12 @@ module ChatSDK
|
|
|
4
4
|
module Teams
|
|
5
5
|
class Adapter < ChatSDK::Adapter::Base
|
|
6
6
|
capabilities :edit_messages, :delete_messages, :threads, :direct_messages,
|
|
7
|
-
:
|
|
8
|
-
:typing_indicator
|
|
7
|
+
:file_uploads, :streaming_edit, :typing_indicator, :message_history
|
|
9
8
|
|
|
10
9
|
attr_reader :client
|
|
11
10
|
|
|
12
|
-
def initialize(app_id: nil, app_password: nil, tenant_id: nil
|
|
11
|
+
def initialize(app_id: nil, app_password: nil, tenant_id: nil,
|
|
12
|
+
graph_client_id: nil, graph_client_secret: nil, graph_tenant_id: nil)
|
|
13
13
|
@app_id = app_id || ENV["TEAMS_APP_ID"]
|
|
14
14
|
@app_password = app_password || ENV["TEAMS_APP_PASSWORD"]
|
|
15
15
|
@tenant_id = tenant_id || ENV["TEAMS_TENANT_ID"]
|
|
@@ -17,6 +17,11 @@ module ChatSDK
|
|
|
17
17
|
raise ChatSDK::ConfigurationError, "Teams app_id required" unless @app_id
|
|
18
18
|
raise ChatSDK::ConfigurationError, "Teams app_password required" unless @app_password
|
|
19
19
|
|
|
20
|
+
@graph_client_id = graph_client_id || ENV["TEAMS_GRAPH_CLIENT_ID"]
|
|
21
|
+
@graph_client_secret = graph_client_secret || ENV["TEAMS_GRAPH_CLIENT_SECRET"]
|
|
22
|
+
@graph_tenant_id = graph_tenant_id || ENV["TEAMS_GRAPH_TENANT_ID"]
|
|
23
|
+
@graph_client = GraphClient.new(@graph_client_id, @graph_client_secret, @graph_tenant_id) if @graph_client_id
|
|
24
|
+
|
|
20
25
|
@client = BotFrameworkClient.new(app_id: @app_id, app_password: @app_password)
|
|
21
26
|
@jwt_verifier = JwtVerifier.new(app_id: @app_id)
|
|
22
27
|
@renderer = AdaptiveCardRenderer.new
|
|
@@ -130,24 +135,6 @@ module ChatSDK
|
|
|
130
135
|
)
|
|
131
136
|
end
|
|
132
137
|
|
|
133
|
-
def add_reaction(channel_id:, message_id:, emoji:)
|
|
134
|
-
require_capability!(:reactions)
|
|
135
|
-
# Teams Bot Framework API does not support adding reactions programmatically
|
|
136
|
-
# The capability is declared because inbound reactions are parsed
|
|
137
|
-
raise ChatSDK::PlatformError.new(
|
|
138
|
-
"Teams Bot Framework API does not support adding reactions programmatically",
|
|
139
|
-
adapter_name: :teams
|
|
140
|
-
)
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def remove_reaction(channel_id:, message_id:, emoji:)
|
|
144
|
-
require_capability!(:reactions)
|
|
145
|
-
raise ChatSDK::PlatformError.new(
|
|
146
|
-
"Teams Bot Framework API does not support removing reactions programmatically",
|
|
147
|
-
adapter_name: :teams
|
|
148
|
-
)
|
|
149
|
-
end
|
|
150
|
-
|
|
151
138
|
def open_dm(user_id)
|
|
152
139
|
require_capability!(:direct_messages)
|
|
153
140
|
# To open a DM, we need a service URL. Use the first cached one.
|
|
@@ -171,15 +158,8 @@ module ChatSDK
|
|
|
171
158
|
conversation_id
|
|
172
159
|
end
|
|
173
160
|
|
|
174
|
-
def fetch_messages(channel_id:, thread_id: nil, cursor: nil, limit: 50)
|
|
175
|
-
require_capability!(:message_history)
|
|
176
|
-
# Teams Bot Framework doesn't provide a message history API
|
|
177
|
-
# Return empty to satisfy the interface
|
|
178
|
-
[[], nil]
|
|
179
|
-
end
|
|
180
|
-
|
|
181
161
|
def open_modal(trigger_id:, modal:)
|
|
182
|
-
super
|
|
162
|
+
super
|
|
183
163
|
end
|
|
184
164
|
|
|
185
165
|
def start_typing(channel_id:, thread_id: nil)
|
|
@@ -203,6 +183,20 @@ module ChatSDK
|
|
|
203
183
|
end
|
|
204
184
|
end
|
|
205
185
|
|
|
186
|
+
def fetch_messages(channel_id:, thread_id: nil, cursor: nil, limit: 50)
|
|
187
|
+
require_capability!(:message_history)
|
|
188
|
+
unless @graph_client
|
|
189
|
+
raise ChatSDK::ConfigurationError,
|
|
190
|
+
"Teams message history requires Graph API credentials " \
|
|
191
|
+
"(TEAMS_GRAPH_CLIENT_ID, TEAMS_GRAPH_CLIENT_SECRET, TEAMS_GRAPH_TENANT_ID)"
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
result = @graph_client.fetch_messages(chat_id: channel_id, limit: limit)
|
|
195
|
+
messages = (result["value"] || []).map { |m| parse_graph_message(m, channel_id) }
|
|
196
|
+
next_link = result["@odata.nextLink"]
|
|
197
|
+
[messages, next_link]
|
|
198
|
+
end
|
|
199
|
+
|
|
206
200
|
# Store a service URL for a conversation (useful when sending proactive messages)
|
|
207
201
|
def register_service_url(conversation_id, service_url)
|
|
208
202
|
@service_urls[conversation_id] = service_url
|
|
@@ -237,6 +231,28 @@ module ChatSDK
|
|
|
237
231
|
end
|
|
238
232
|
url
|
|
239
233
|
end
|
|
234
|
+
|
|
235
|
+
def parse_graph_message(data, channel_id)
|
|
236
|
+
from = data["from"] || {}
|
|
237
|
+
user = from["user"] || from["application"] || {}
|
|
238
|
+
is_bot = !from["application"].nil?
|
|
239
|
+
|
|
240
|
+
ChatSDK::Message.new(
|
|
241
|
+
id: data["id"],
|
|
242
|
+
text: data.dig("body", "content") || "",
|
|
243
|
+
author: ChatSDK::Author.new(
|
|
244
|
+
id: user["id"] || "unknown",
|
|
245
|
+
name: user["displayName"] || "unknown",
|
|
246
|
+
platform: :teams,
|
|
247
|
+
bot: is_bot
|
|
248
|
+
),
|
|
249
|
+
thread_id: data["replyToId"] || data["id"],
|
|
250
|
+
channel_id: channel_id,
|
|
251
|
+
platform: :teams,
|
|
252
|
+
timestamp: data["createdDateTime"],
|
|
253
|
+
raw: data
|
|
254
|
+
)
|
|
255
|
+
end
|
|
240
256
|
end
|
|
241
257
|
end
|
|
242
258
|
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ChatSDK
|
|
4
|
+
module Teams
|
|
5
|
+
class GraphClient
|
|
6
|
+
TOKEN_URL_TEMPLATE = "https://login.microsoftonline.com/%s/oauth2/v2.0/token"
|
|
7
|
+
GRAPH_BASE_URL = "https://graph.microsoft.com/v1.0"
|
|
8
|
+
SCOPE = "https://graph.microsoft.com/.default"
|
|
9
|
+
|
|
10
|
+
def initialize(client_id, client_secret, tenant_id)
|
|
11
|
+
@client_id = client_id
|
|
12
|
+
@client_secret = client_secret
|
|
13
|
+
@tenant_id = tenant_id
|
|
14
|
+
@access_token = nil
|
|
15
|
+
@token_expires_at = nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def fetch_messages(chat_id:, limit: 50)
|
|
19
|
+
token = fetch_token
|
|
20
|
+
url = "#{GRAPH_BASE_URL}/chats/#{chat_id}/messages?$top=#{limit}&$orderby=createdDateTime desc"
|
|
21
|
+
|
|
22
|
+
response = api_connection.get(url) do |req|
|
|
23
|
+
req.headers["Authorization"] = "Bearer #{token}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
unless response.success?
|
|
27
|
+
raise ChatSDK::PlatformError.new(
|
|
28
|
+
"Graph API error: #{response.status}",
|
|
29
|
+
status: response.status,
|
|
30
|
+
body: response.body,
|
|
31
|
+
adapter_name: :teams
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
response.body
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def fetch_token
|
|
39
|
+
return @access_token if @access_token && @token_expires_at && Time.now < @token_expires_at
|
|
40
|
+
|
|
41
|
+
token_url = format(TOKEN_URL_TEMPLATE, @tenant_id)
|
|
42
|
+
|
|
43
|
+
response = token_connection.post(token_url, {
|
|
44
|
+
grant_type: "client_credentials",
|
|
45
|
+
client_id: @client_id,
|
|
46
|
+
client_secret: @client_secret,
|
|
47
|
+
scope: SCOPE
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
unless response.success?
|
|
51
|
+
raise ChatSDK::PlatformError.new(
|
|
52
|
+
"Failed to acquire Graph API token: #{response.status}",
|
|
53
|
+
status: response.status,
|
|
54
|
+
body: response.body,
|
|
55
|
+
adapter_name: :teams
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
data = JSON.parse(response.body)
|
|
60
|
+
@access_token = data["access_token"]
|
|
61
|
+
@token_expires_at = Time.now + (data["expires_in"].to_i - 60)
|
|
62
|
+
@access_token
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def token_connection
|
|
68
|
+
@token_connection ||= Faraday.new do |f|
|
|
69
|
+
f.request :url_encoded
|
|
70
|
+
f.adapter :net_http
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def api_connection
|
|
75
|
+
@api_connection ||= Faraday.new do |f|
|
|
76
|
+
f.request :json
|
|
77
|
+
f.response :json
|
|
78
|
+
f.adapter :net_http
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: chat_sdk-teams
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Quentin Rousseau
|
|
@@ -63,6 +63,7 @@ files:
|
|
|
63
63
|
- lib/chat_sdk/teams/adapter.rb
|
|
64
64
|
- lib/chat_sdk/teams/adaptive_card_renderer.rb
|
|
65
65
|
- lib/chat_sdk/teams/bot_framework_client.rb
|
|
66
|
+
- lib/chat_sdk/teams/graph_client.rb
|
|
66
67
|
- lib/chat_sdk/teams/jwt_verifier.rb
|
|
67
68
|
homepage: https://github.com/rootlyhq/chat-sdk
|
|
68
69
|
licenses:
|