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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 799f1b70fcdec6365e02ec7fd3920c83f171f60d37abc00caafb370f4250336f
4
- data.tar.gz: f75bd7b4950741c194ec432e82689caf59d911591cb1fe21ea236ffccf6b98a3
3
+ metadata.gz: 26f507aa00b122a92a3b175ec79248a0cd4cf0d8a63d192ff5ada84eb8a4b307
4
+ data.tar.gz: 54295b00effe5c4d7b37b906209dbcbb2685068da76eee7f3a68c020cdf391e9
5
5
  SHA512:
6
- metadata.gz: '091619ca8e40cfedc334ed3a14a7d7922ebc84d58f5a9072aacf71ba8cebbb3e8c758c51a8a06320644ed0b5a21e600def9ede392bffa692beb5d82b6a8abcce'
7
- data.tar.gz: 71523b1aa4925c80c695ba3838dca729a5fa33468c86437aa4bedd3bf8e027ea5b610f97161bc40184aa117eda1bb82e32ee89955aadf745e50273248a17b71f
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
- :message_history, :reactions, :file_uploads, :streaming_edit,
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 # raises NotSupportedError
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.5.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: