chat_sdk-teams 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5077208fda83c5941a590c7daa94b0d821399dcd49d92f3b5368498cd7e30f0b
4
- data.tar.gz: 6271ccca3f36db8cadb455bfa47ead36eccf5ab6b6363edc39342d223f39979d
3
+ metadata.gz: 26f507aa00b122a92a3b175ec79248a0cd4cf0d8a63d192ff5ada84eb8a4b307
4
+ data.tar.gz: 54295b00effe5c4d7b37b906209dbcbb2685068da76eee7f3a68c020cdf391e9
5
5
  SHA512:
6
- metadata.gz: 7a219d54aa4725525307540f3fec911ce6c956f3421faf2ba88ac2ab672972a46509b85128d044b1f8d48152ffe52973a3e241c5bc3a047c110edfef3f607ebd
7
- data.tar.gz: 19555fa3ae535a42cf93ebd79e3e7695221648880d19d42d2a1562550b29085db991f630a12f4b60424074a85941fb4c485bf4e6f67f39ffbb4025223289840e
6
+ metadata.gz: aeac84b76ec10f316e3836676d85826d708b026293897ca7abfe77b3532af466519d2acc267ac41a21429d02af91feac58623ce40c6146eeda3f9fc35a204d56
7
+ data.tar.gz: 3535fa1ecd603951f94d2df234f1fdc68239c66624cc0adf393be7def189168d910b377d8de1f6598178e60f94de5bdc05c1f630f9b3b35b2314540fa592bd59
@@ -4,11 +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
- :file_uploads, :streaming_edit, :typing_indicator
7
+ :file_uploads, :streaming_edit, :typing_indicator, :message_history
8
8
 
9
9
  attr_reader :client
10
10
 
11
- 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)
12
13
  @app_id = app_id || ENV["TEAMS_APP_ID"]
13
14
  @app_password = app_password || ENV["TEAMS_APP_PASSWORD"]
14
15
  @tenant_id = tenant_id || ENV["TEAMS_TENANT_ID"]
@@ -16,6 +17,11 @@ module ChatSDK
16
17
  raise ChatSDK::ConfigurationError, "Teams app_id required" unless @app_id
17
18
  raise ChatSDK::ConfigurationError, "Teams app_password required" unless @app_password
18
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
+
19
25
  @client = BotFrameworkClient.new(app_id: @app_id, app_password: @app_password)
20
26
  @jwt_verifier = JwtVerifier.new(app_id: @app_id)
21
27
  @renderer = AdaptiveCardRenderer.new
@@ -177,6 +183,20 @@ module ChatSDK
177
183
  end
178
184
  end
179
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
+
180
200
  # Store a service URL for a conversation (useful when sending proactive messages)
181
201
  def register_service_url(conversation_id, service_url)
182
202
  @service_urls[conversation_id] = service_url
@@ -211,6 +231,28 @@ module ChatSDK
211
231
  end
212
232
  url
213
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
214
256
  end
215
257
  end
216
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.6.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: