lex-microsoft_teams 0.5.2 → 0.5.4

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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -2
  3. data/CHANGELOG.md +34 -0
  4. data/CLAUDE.md +2 -2
  5. data/docs/plans/2026-03-19-teams-token-lifecycle-design.md +120 -0
  6. data/docs/plans/2026-03-19-teams-token-lifecycle-implementation.md +679 -0
  7. data/lib/legion/extensions/microsoft_teams/actors/auth_validator.rb +105 -0
  8. data/lib/legion/extensions/microsoft_teams/actors/cache_sync.rb +1 -5
  9. data/lib/legion/extensions/microsoft_teams/actors/direct_chat_poller.rb +2 -2
  10. data/lib/legion/extensions/microsoft_teams/actors/message_processor.rb +1 -1
  11. data/lib/legion/extensions/microsoft_teams/actors/observed_chat_poller.rb +1 -1
  12. data/lib/legion/extensions/microsoft_teams/actors/token_refresher.rb +103 -0
  13. data/lib/legion/extensions/microsoft_teams/client.rb +5 -2
  14. data/lib/legion/extensions/microsoft_teams/helpers/browser_auth.rb +1 -1
  15. data/lib/legion/extensions/microsoft_teams/helpers/callback_server.rb +7 -2
  16. data/lib/legion/extensions/microsoft_teams/helpers/client.rb +4 -0
  17. data/lib/legion/extensions/microsoft_teams/helpers/prompt_resolver.rb +2 -5
  18. data/lib/legion/extensions/microsoft_teams/helpers/subscription_registry.rb +1 -0
  19. data/lib/legion/extensions/microsoft_teams/helpers/token_cache.rb +66 -3
  20. data/lib/legion/extensions/microsoft_teams/local_cache/extractor.rb +1 -1
  21. data/lib/legion/extensions/microsoft_teams/local_cache/record_parser.rb +1 -1
  22. data/lib/legion/extensions/microsoft_teams/runners/bot.rb +4 -4
  23. data/lib/legion/extensions/microsoft_teams/runners/cache_ingest.rb +8 -9
  24. data/lib/legion/extensions/microsoft_teams/runners/channel_messages.rb +5 -5
  25. data/lib/legion/extensions/microsoft_teams/runners/channels.rb +6 -6
  26. data/lib/legion/extensions/microsoft_teams/runners/chats.rb +5 -5
  27. data/lib/legion/extensions/microsoft_teams/runners/meetings.rb +16 -16
  28. data/lib/legion/extensions/microsoft_teams/runners/messages.rb +5 -5
  29. data/lib/legion/extensions/microsoft_teams/runners/presence.rb +2 -2
  30. data/lib/legion/extensions/microsoft_teams/runners/subscriptions.rb +5 -5
  31. data/lib/legion/extensions/microsoft_teams/runners/teams.rb +3 -3
  32. data/lib/legion/extensions/microsoft_teams/runners/transcripts.rb +6 -6
  33. data/lib/legion/extensions/microsoft_teams/version.rb +1 -1
  34. metadata +5 -2
  35. data/lib/legion/extensions/microsoft_teams/transport.rb +0 -11
@@ -9,53 +9,53 @@ module Legion
9
9
  module Meetings
10
10
  include Legion::Extensions::MicrosoftTeams::Helpers::Client
11
11
 
12
- def list_meetings(user_id:, **)
13
- response = graph_connection(**).get("/users/#{user_id}/onlineMeetings")
12
+ def list_meetings(user_id: 'me', **)
13
+ response = graph_connection(**).get("#{user_path(user_id)}/onlineMeetings")
14
14
  { result: response.body }
15
15
  end
16
16
 
17
- def get_meeting(user_id:, meeting_id:, **)
18
- response = graph_connection(**).get("/users/#{user_id}/onlineMeetings/#{meeting_id}")
17
+ def get_meeting(meeting_id:, user_id: 'me', **)
18
+ response = graph_connection(**).get("#{user_path(user_id)}/onlineMeetings/#{meeting_id}")
19
19
  { result: response.body }
20
20
  end
21
21
 
22
- def create_meeting(user_id:, subject:, start_time:, end_time:, **)
22
+ def create_meeting(subject:, start_time:, end_time:, user_id: 'me', **)
23
23
  payload = {
24
24
  subject: subject,
25
25
  startDateTime: start_time,
26
26
  endDateTime: end_time
27
27
  }
28
- response = graph_connection(**).post("/users/#{user_id}/onlineMeetings", payload)
28
+ response = graph_connection(**).post("#{user_path(user_id)}/onlineMeetings", payload)
29
29
  { result: response.body }
30
30
  end
31
31
 
32
- def update_meeting(user_id:, meeting_id:, subject: nil, start_time: nil, end_time: nil, **)
32
+ def update_meeting(meeting_id:, user_id: 'me', subject: nil, start_time: nil, end_time: nil, **)
33
33
  payload = {}
34
34
  payload[:subject] = subject if subject
35
35
  payload[:startDateTime] = start_time if start_time
36
36
  payload[:endDateTime] = end_time if end_time
37
- response = graph_connection(**).patch("/users/#{user_id}/onlineMeetings/#{meeting_id}", payload)
37
+ response = graph_connection(**).patch("#{user_path(user_id)}/onlineMeetings/#{meeting_id}", payload)
38
38
  { result: response.body }
39
39
  end
40
40
 
41
- def delete_meeting(user_id:, meeting_id:, **)
42
- response = graph_connection(**).delete("/users/#{user_id}/onlineMeetings/#{meeting_id}")
41
+ def delete_meeting(meeting_id:, user_id: 'me', **)
42
+ response = graph_connection(**).delete("#{user_path(user_id)}/onlineMeetings/#{meeting_id}")
43
43
  { result: response.body }
44
44
  end
45
45
 
46
- def get_meeting_by_join_url(user_id:, join_url:, **)
46
+ def get_meeting_by_join_url(join_url:, user_id: 'me', **)
47
47
  params = { '$filter' => "joinWebUrl eq '#{join_url.gsub("'", "''")}'" }
48
- response = graph_connection(**).get("/users/#{user_id}/onlineMeetings", params)
48
+ response = graph_connection(**).get("#{user_path(user_id)}/onlineMeetings", params)
49
49
  { result: response.body }
50
50
  end
51
51
 
52
- def list_attendance_reports(user_id:, meeting_id:, **)
53
- response = graph_connection(**).get("/users/#{user_id}/onlineMeetings/#{meeting_id}/attendanceReports")
52
+ def list_attendance_reports(meeting_id:, user_id: 'me', **)
53
+ response = graph_connection(**).get("#{user_path(user_id)}/onlineMeetings/#{meeting_id}/attendanceReports")
54
54
  { result: response.body }
55
55
  end
56
56
 
57
- def get_attendance_report(user_id:, meeting_id:, report_id:, **)
58
- response = graph_connection(**).get("/users/#{user_id}/onlineMeetings/#{meeting_id}/attendanceReports/#{report_id}")
57
+ def get_attendance_report(meeting_id:, report_id:, user_id: 'me', **)
58
+ response = graph_connection(**).get("#{user_path(user_id)}/onlineMeetings/#{meeting_id}/attendanceReports/#{report_id}")
59
59
  { result: response.body }
60
60
  end
61
61
 
@@ -11,31 +11,31 @@ module Legion
11
11
 
12
12
  def list_chat_messages(chat_id:, top: 50, **)
13
13
  params = { '$top' => top }
14
- response = graph_connection(**).get("/chats/#{chat_id}/messages", params)
14
+ response = graph_connection(**).get("chats/#{chat_id}/messages", params)
15
15
  { result: response.body }
16
16
  end
17
17
 
18
18
  def get_chat_message(chat_id:, message_id:, **)
19
- response = graph_connection(**).get("/chats/#{chat_id}/messages/#{message_id}")
19
+ response = graph_connection(**).get("chats/#{chat_id}/messages/#{message_id}")
20
20
  { result: response.body }
21
21
  end
22
22
 
23
23
  def send_chat_message(chat_id:, content:, content_type: 'text', attachments: [], **)
24
24
  payload = { body: { contentType: content_type, content: content } }
25
25
  payload[:attachments] = attachments unless attachments.empty?
26
- response = graph_connection(**).post("/chats/#{chat_id}/messages", payload)
26
+ response = graph_connection(**).post("chats/#{chat_id}/messages", payload)
27
27
  { result: response.body }
28
28
  end
29
29
 
30
30
  def reply_to_chat_message(chat_id:, message_id:, content:, content_type: 'text', **)
31
31
  payload = { body: { contentType: content_type, content: content } }
32
- response = graph_connection(**).post("/chats/#{chat_id}/messages/#{message_id}/replies", payload)
32
+ response = graph_connection(**).post("chats/#{chat_id}/messages/#{message_id}/replies", payload)
33
33
  { result: response.body }
34
34
  end
35
35
 
36
36
  def list_message_replies(chat_id:, message_id:, top: 50, **)
37
37
  params = { '$top' => top }
38
- response = graph_connection(**).get("/chats/#{chat_id}/messages/#{message_id}/replies", params)
38
+ response = graph_connection(**).get("chats/#{chat_id}/messages/#{message_id}/replies", params)
39
39
  { result: response.body }
40
40
  end
41
41
 
@@ -9,9 +9,9 @@ module Legion
9
9
  module Presence
10
10
  include Legion::Extensions::MicrosoftTeams::Helpers::Client
11
11
 
12
- def get_presence(user_id:, **)
12
+ def get_presence(user_id: 'me', **)
13
13
  conn = graph_connection(**)
14
- response = conn.get("/users/#{user_id}/presence")
14
+ response = conn.get("#{user_path(user_id)}/presence")
15
15
  body = response.body || {}
16
16
  {
17
17
  availability: body['availability'],
@@ -10,12 +10,12 @@ module Legion
10
10
  include Legion::Extensions::MicrosoftTeams::Helpers::Client
11
11
 
12
12
  def list_subscriptions(**)
13
- response = graph_connection(**).get('/subscriptions')
13
+ response = graph_connection(**).get('subscriptions')
14
14
  { result: response.body }
15
15
  end
16
16
 
17
17
  def get_subscription(subscription_id:, **)
18
- response = graph_connection(**).get("/subscriptions/#{subscription_id}")
18
+ response = graph_connection(**).get("subscriptions/#{subscription_id}")
19
19
  { result: response.body }
20
20
  end
21
21
 
@@ -29,18 +29,18 @@ module Legion
29
29
  includeResourceData: include_resource_data
30
30
  }
31
31
  payload[:clientState] = client_state if client_state
32
- response = graph_connection(**).post('/subscriptions', payload)
32
+ response = graph_connection(**).post('subscriptions', payload)
33
33
  { result: response.body }
34
34
  end
35
35
 
36
36
  def renew_subscription(subscription_id:, expiration:, **)
37
37
  payload = { expirationDateTime: expiration }
38
- response = graph_connection(**).patch("/subscriptions/#{subscription_id}", payload)
38
+ response = graph_connection(**).patch("subscriptions/#{subscription_id}", payload)
39
39
  { result: response.body }
40
40
  end
41
41
 
42
42
  def delete_subscription(subscription_id:, **)
43
- response = graph_connection(**).delete("/subscriptions/#{subscription_id}")
43
+ response = graph_connection(**).delete("subscriptions/#{subscription_id}")
44
44
  { result: response.body }
45
45
  end
46
46
 
@@ -10,17 +10,17 @@ module Legion
10
10
  include Legion::Extensions::MicrosoftTeams::Helpers::Client
11
11
 
12
12
  def list_joined_teams(user_id: 'me', **)
13
- response = graph_connection(**).get("/#{user_id}/joinedTeams")
13
+ response = graph_connection(**).get("#{user_path(user_id)}/joinedTeams")
14
14
  { result: response.body }
15
15
  end
16
16
 
17
17
  def get_team(team_id:, **)
18
- response = graph_connection(**).get("/teams/#{team_id}")
18
+ response = graph_connection(**).get("teams/#{team_id}")
19
19
  { result: response.body }
20
20
  end
21
21
 
22
22
  def list_team_members(team_id:, **)
23
- response = graph_connection(**).get("/teams/#{team_id}/members")
23
+ response = graph_connection(**).get("teams/#{team_id}/members")
24
24
  { result: response.body }
25
25
  end
26
26
 
@@ -14,22 +14,22 @@ module Legion
14
14
  docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
15
15
  }.freeze
16
16
 
17
- def list_transcripts(user_id:, meeting_id:, **)
18
- response = graph_connection(**).get("/users/#{user_id}/onlineMeetings/#{meeting_id}/transcripts")
17
+ def list_transcripts(meeting_id:, user_id: 'me', **)
18
+ response = graph_connection(**).get("#{user_path(user_id)}/onlineMeetings/#{meeting_id}/transcripts")
19
19
  { result: response.body }
20
20
  end
21
21
 
22
- def get_transcript(user_id:, meeting_id:, transcript_id:, **)
22
+ def get_transcript(meeting_id:, transcript_id:, user_id: 'me', **)
23
23
  response = graph_connection(**).get(
24
- "/users/#{user_id}/onlineMeetings/#{meeting_id}/transcripts/#{transcript_id}"
24
+ "#{user_path(user_id)}/onlineMeetings/#{meeting_id}/transcripts/#{transcript_id}"
25
25
  )
26
26
  { result: response.body }
27
27
  end
28
28
 
29
- def get_transcript_content(user_id:, meeting_id:, transcript_id:, format: :vtt, **)
29
+ def get_transcript_content(meeting_id:, transcript_id:, user_id: 'me', format: :vtt, **)
30
30
  accept = CONTENT_TYPES.fetch(format)
31
31
  response = graph_connection(**).get(
32
- "/users/#{user_id}/onlineMeetings/#{meeting_id}/transcripts/#{transcript_id}/content"
32
+ "#{user_path(user_id)}/onlineMeetings/#{meeting_id}/transcripts/#{transcript_id}/content"
33
33
  ) do |req|
34
34
  req.headers['Accept'] = accept
35
35
  end
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module MicrosoftTeams
6
- VERSION = '0.5.2'
6
+ VERSION = '0.5.4'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-microsoft_teams
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -71,13 +71,17 @@ files:
71
71
  - docs/plans/2026-03-15-meetings-transcripts-design.md
72
72
  - docs/plans/2026-03-16-delegated-oauth-browser-flow-design.md
73
73
  - docs/plans/2026-03-16-delegated-oauth-browser-flow-plan.md
74
+ - docs/plans/2026-03-19-teams-token-lifecycle-design.md
75
+ - docs/plans/2026-03-19-teams-token-lifecycle-implementation.md
74
76
  - lex-microsoft_teams.gemspec
75
77
  - lib/legion/extensions/microsoft_teams.rb
78
+ - lib/legion/extensions/microsoft_teams/actors/auth_validator.rb
76
79
  - lib/legion/extensions/microsoft_teams/actors/cache_bulk_ingest.rb
77
80
  - lib/legion/extensions/microsoft_teams/actors/cache_sync.rb
78
81
  - lib/legion/extensions/microsoft_teams/actors/direct_chat_poller.rb
79
82
  - lib/legion/extensions/microsoft_teams/actors/message_processor.rb
80
83
  - lib/legion/extensions/microsoft_teams/actors/observed_chat_poller.rb
84
+ - lib/legion/extensions/microsoft_teams/actors/token_refresher.rb
81
85
  - lib/legion/extensions/microsoft_teams/client.rb
82
86
  - lib/legion/extensions/microsoft_teams/helpers/browser_auth.rb
83
87
  - lib/legion/extensions/microsoft_teams/helpers/callback_server.rb
@@ -104,7 +108,6 @@ files:
104
108
  - lib/legion/extensions/microsoft_teams/runners/subscriptions.rb
105
109
  - lib/legion/extensions/microsoft_teams/runners/teams.rb
106
110
  - lib/legion/extensions/microsoft_teams/runners/transcripts.rb
107
- - lib/legion/extensions/microsoft_teams/transport.rb
108
111
  - lib/legion/extensions/microsoft_teams/transport/exchanges/messages.rb
109
112
  - lib/legion/extensions/microsoft_teams/transport/messages/teams_message.rb
110
113
  - lib/legion/extensions/microsoft_teams/transport/queues/messages_process.rb
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Legion
4
- module Extensions
5
- module MicrosoftTeams
6
- module Transport
7
- extend Legion::Extensions::Transport
8
- end
9
- end
10
- end
11
- end