Class: Teams::ActivityContext
- Inherits:
-
Object
- Object
- Teams::ActivityContext
- Defined in:
- lib/teams/activity_context.rb
Instance Attribute Summary collapse
-
#activity ⇒ Object
readonly
Returns the value of attribute activity.
-
#app ⇒ Object
readonly
Returns the value of attribute app.
-
#conversation_reference ⇒ Object
readonly
Returns the value of attribute conversation_reference.
-
#extra ⇒ Object
readonly
Returns the value of attribute extra.
-
#stream ⇒ Object
readonly
Returns the value of attribute stream.
Instance Method Summary collapse
- #api ⇒ Object
-
#app_graph ⇒ Object
Microsoft Graph client with the app's own identity (app-only tokens).
-
#initialize(app:, activity:, conversation_reference:, extra: {}, stream: nil) ⇒ ActivityContext
constructor
A new instance of ActivityContext.
- #log ⇒ Object
-
#post(activity_or_text) ⇒ Object
The TypeScript, Python, and .NET SDKs call this operation
send. -
#quote(message_id, activity_or_text) ⇒ Object
Quoted replies are plain sends carrying the quote placeholder and entity, matching the TypeScript and Python SDKs; no replyToId is set.
- #ref ⇒ Object
- #reference ⇒ Object
- #reply(activity_or_text) ⇒ Object
-
#sign_in(connection_name: nil, oauth_card_text: "Please Sign In...", sign_in_button_text: "Sign In") ⇒ Object
Starts the user sign-in flow: returns the token if the user is already signed in, otherwise sends an OAuth card and returns nil.
-
#sign_out(connection_name: nil) ⇒ Object
Clears the user's token for the connection.
- #storage ⇒ Object
- #typing(text = nil) ⇒ Object
-
#update(activity_id, activity_or_text) ⇒ Object
Sugar over post: the SDKs update by sending an activity that already carries an id, and post does exactly that.
-
#user_graph(connection_name: nil) ⇒ Object
Microsoft Graph client with the signed-in user's token.
Constructor Details
#initialize(app:, activity:, conversation_reference:, extra: {}, stream: nil) ⇒ ActivityContext
Returns a new instance of ActivityContext.
10 11 12 13 14 15 16 |
# File 'lib/teams/activity_context.rb', line 10 def initialize(app:, activity:, conversation_reference:, extra: {}, stream: nil) @app = app @activity = activity @conversation_reference = conversation_reference @extra = extra @stream = stream end |
Instance Attribute Details
#activity ⇒ Object (readonly)
Returns the value of attribute activity.
8 9 10 |
# File 'lib/teams/activity_context.rb', line 8 def activity @activity end |
#app ⇒ Object (readonly)
Returns the value of attribute app.
8 9 10 |
# File 'lib/teams/activity_context.rb', line 8 def app @app end |
#conversation_reference ⇒ Object (readonly)
Returns the value of attribute conversation_reference.
8 9 10 |
# File 'lib/teams/activity_context.rb', line 8 def conversation_reference @conversation_reference end |
#extra ⇒ Object (readonly)
Returns the value of attribute extra.
8 9 10 |
# File 'lib/teams/activity_context.rb', line 8 def extra @extra end |
#stream ⇒ Object (readonly)
Returns the value of attribute stream.
8 9 10 |
# File 'lib/teams/activity_context.rb', line 8 def stream @stream end |
Instance Method Details
#api ⇒ Object
34 35 36 |
# File 'lib/teams/activity_context.rb', line 34 def api app.api end |
#app_graph ⇒ Object
Microsoft Graph client with the app's own identity (app-only tokens).
71 72 73 |
# File 'lib/teams/activity_context.rb', line 71 def app_graph app.graph end |
#log ⇒ Object
26 27 28 |
# File 'lib/teams/activity_context.rb', line 26 def log app.logger end |
#post(activity_or_text) ⇒ Object
The TypeScript, Python, and .NET SDKs call this operation send.
Ruby already defines Object#send for dynamic dispatch, so the public
Ruby API uses post to avoid shadowing a core language method.
41 42 43 |
# File 'lib/teams/activity_context.rb', line 41 def post(activity_or_text) app.send_activity(conversation_reference, apply_targeted_defaults(activity_or_text)) end |
#quote(message_id, activity_or_text) ⇒ Object
Quoted replies are plain sends carrying the quote placeholder and entity, matching the TypeScript and Python SDKs; no replyToId is set.
56 57 58 |
# File 'lib/teams/activity_context.rb', line 56 def quote(, activity_or_text) post(quoted_activity(, activity_or_text)) end |
#ref ⇒ Object
18 19 20 |
# File 'lib/teams/activity_context.rb', line 18 def ref conversation_reference end |
#reference ⇒ Object
22 23 24 |
# File 'lib/teams/activity_context.rb', line 22 def reference conversation_reference end |
#reply(activity_or_text) ⇒ Object
45 46 47 48 49 50 51 52 |
# File 'lib/teams/activity_context.rb', line 45 def reply(activity_or_text) return post(activity_or_text) unless activity.id # Replies to targeted inbound messages are targeted sends: no quoted # reply and no replyToId, matching the TypeScript and Python SDKs. return post(activity_or_text) if targeted_reply?(activity_or_text) quote(activity.id, activity_or_text) end |
#sign_in(connection_name: nil, oauth_card_text: "Please Sign In...", sign_in_button_text: "Sign In") ⇒ Object
Starts the user sign-in flow: returns the token if the user is already signed in, otherwise sends an OAuth card and returns nil. In group chats and channels the card is a targeted message visible only to the requesting user; channels omit the token exchange resource because channel scope cannot do the silent SSO exchange, so the card renders the sign-in button instead.
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/teams/activity_context.rb', line 100 def sign_in(connection_name: nil, oauth_card_text: "Please Sign In...", sign_in_button_text: "Sign In") connection_name ||= app.default_connection_name begin response = api.users.get_token( user_id: activity.from.id, connection_name:, channel_id: activity.channel_id ) return response.token if response.token && !response.token.to_s.empty? rescue HttpError # No token yet; continue with the OAuth card flow. end state = Base64.strict_encode64(JSON.generate( "connectionName" => connection_name, "conversation" => conversation_reference.to_h, "msAppId" => app.client_id )) resource = api.bots.sign_in.get_resource(state:) is_channel = activity.conversation.conversation_type == "channel" recipient = activity.from.to_h recipient = recipient.merge("isTargeted" => true) if activity.conversation.is_group card = { "text" => oauth_card_text, "connectionName" => connection_name, "tokenExchangeResource" => (resource.token_exchange_resource&.to_h unless is_channel), "tokenPostResource" => resource.token_post_resource&.to_h, "buttons" => [ { "type" => "signin", "title" => , "value" => resource.sign_in_link } ] }.compact payload = { "type" => "message", "recipient" => recipient, "attachments" => [ { "contentType" => "application/vnd.microsoft.card.oauth", "content" => card } ] } app.send_activity(conversation_reference, payload) nil end |
#sign_out(connection_name: nil) ⇒ Object
Clears the user's token for the connection. Failures are logged, not raised, matching the TypeScript/Python SDKs.
149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/teams/activity_context.rb', line 149 def sign_out(connection_name: nil) api.users.sign_out( user_id: activity.from.id, connection_name: connection_name || app.default_connection_name, channel_id: activity.channel_id ) nil rescue HttpError => error log&.error("Failed to sign out user: #{error.}") nil end |
#storage ⇒ Object
30 31 32 |
# File 'lib/teams/activity_context.rb', line 30 def storage app.storage end |
#typing(text = nil) ⇒ Object
66 67 68 |
# File 'lib/teams/activity_context.rb', line 66 def typing(text = nil) post(Api::TypingActivity.new(text)) end |
#update(activity_id, activity_or_text) ⇒ Object
Sugar over post: the SDKs update by sending an activity that already carries an id, and post does exactly that. See AGENTS.md.
62 63 64 |
# File 'lib/teams/activity_context.rb', line 62 def update(activity_id, activity_or_text) post(activity_with_id(activity_id, activity_or_text)) end |
#user_graph(connection_name: nil) ⇒ Object
Microsoft Graph client with the signed-in user's token. Raises when the user is not signed in, like the Python SDK's user_graph.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/teams/activity_context.rb', line 77 def user_graph(connection_name: nil) connection = connection_name || app.default_connection_name @user_graph ||= {} @user_graph[connection] ||= begin response = api.users.get_token( user_id: activity.from.id, connection_name: connection, channel_id: activity.channel_id ) raise Error, "User must be signed in to access the Graph client" if response.token.to_s.empty? Graph::Client.new(token: response.token, base_url_root: app.graph.base_url_root) rescue HttpError raise Error, "User must be signed in to access the Graph client" end end |