teams_rb 2.0.1
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 +7 -0
- data/CHANGELOG.md +47 -0
- data/LICENSE +21 -0
- data/README.md +500 -0
- data/docs/README.md +40 -0
- data/docs/essentials/README.md +13 -0
- data/docs/essentials/api-client.md +62 -0
- data/docs/essentials/app-authentication.md +27 -0
- data/docs/essentials/app-basics.md +50 -0
- data/docs/essentials/graph.md +41 -0
- data/docs/essentials/on-activity.md +72 -0
- data/docs/essentials/on-event.md +29 -0
- data/docs/essentials/proactive-messaging.md +44 -0
- data/docs/essentials/sending-messages.md +76 -0
- data/docs/essentials/sovereign-cloud.md +26 -0
- data/docs/getting-started/README.md +7 -0
- data/docs/getting-started/code-basics.md +61 -0
- data/docs/getting-started/quickstart.md +54 -0
- data/docs/getting-started/running-in-teams.md +44 -0
- data/docs/in-depth-guides/README.md +14 -0
- data/docs/in-depth-guides/adaptive-cards.md +62 -0
- data/docs/in-depth-guides/dialogs.md +77 -0
- data/docs/in-depth-guides/feedback.md +29 -0
- data/docs/in-depth-guides/meeting-events.md +27 -0
- data/docs/in-depth-guides/message-extensions.md +77 -0
- data/docs/in-depth-guides/message-reactions.md +29 -0
- data/docs/in-depth-guides/observability.md +28 -0
- data/docs/in-depth-guides/streaming.md +52 -0
- data/docs/in-depth-guides/tabs.md +59 -0
- data/docs/in-depth-guides/user-authentication.md +60 -0
- data/lib/teams/activity.rb +160 -0
- data/lib/teams/activity_context.rb +278 -0
- data/lib/teams/api/account.rb +90 -0
- data/lib/teams/api/activity_value.rb +49 -0
- data/lib/teams/api/bot_sign_in_client.rb +54 -0
- data/lib/teams/api/channel_data.rb +86 -0
- data/lib/teams/api/channel_info.rb +19 -0
- data/lib/teams/api/citation_appearance.rb +83 -0
- data/lib/teams/api/client.rb +28 -0
- data/lib/teams/api/conversation_account.rb +40 -0
- data/lib/teams/api/conversation_client.rb +156 -0
- data/lib/teams/api/conversation_reference.rb +83 -0
- data/lib/teams/api/conversation_resource.rb +19 -0
- data/lib/teams/api/meeting_client.rb +57 -0
- data/lib/teams/api/meeting_info.rb +26 -0
- data/lib/teams/api/meeting_notification_response.rb +29 -0
- data/lib/teams/api/meeting_participant.rb +33 -0
- data/lib/teams/api/message_activity.rb +201 -0
- data/lib/teams/api/message_extension.rb +110 -0
- data/lib/teams/api/model.rb +49 -0
- data/lib/teams/api/notification_info.rb +28 -0
- data/lib/teams/api/paged_members_result.rb +16 -0
- data/lib/teams/api/quoted_reply_entity.rb +65 -0
- data/lib/teams/api/reaction_client.rb +34 -0
- data/lib/teams/api/sent_activity.rb +48 -0
- data/lib/teams/api/task_module.rb +83 -0
- data/lib/teams/api/team_client.rb +45 -0
- data/lib/teams/api/team_details.rb +36 -0
- data/lib/teams/api/team_info.rb +44 -0
- data/lib/teams/api/tenant_info.rb +11 -0
- data/lib/teams/api/token.rb +81 -0
- data/lib/teams/api/typing_activity.rb +19 -0
- data/lib/teams/api/user_client.rb +83 -0
- data/lib/teams/app.rb +602 -0
- data/lib/teams/auth/client_secret_credentials.rb +7 -0
- data/lib/teams/auth/jwt_validator.rb +148 -0
- data/lib/teams/auth/token.rb +39 -0
- data/lib/teams/auth/token_manager.rb +68 -0
- data/lib/teams/cards/generated.rb +1764 -0
- data/lib/teams/cards/generated_base.rb +105 -0
- data/lib/teams/cards.rb +81 -0
- data/lib/teams/cloud_environment.rb +41 -0
- data/lib/teams/common/hashes.rb +20 -0
- data/lib/teams/common/http_client.rb +111 -0
- data/lib/teams/common/retry.rb +31 -0
- data/lib/teams/errors.rb +50 -0
- data/lib/teams/function_context.rb +82 -0
- data/lib/teams/graph/client.rb +73 -0
- data/lib/teams/http_stream.rb +460 -0
- data/lib/teams/rack_app.rb +62 -0
- data/lib/teams/response.rb +9 -0
- data/lib/teams/router.rb +171 -0
- data/lib/teams/storage/memory_store.rb +27 -0
- data/lib/teams/version.rb +5 -0
- data/lib/teams.rb +70 -0
- metadata +217 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Teams
|
|
4
|
+
module Api
|
|
5
|
+
# An attachment in a message extension result; preview: carries the
|
|
6
|
+
# optional preview card shown in the result list.
|
|
7
|
+
class MessagingExtensionAttachment
|
|
8
|
+
def initialize(content_type: nil, content: nil, content_url: nil, name: nil,
|
|
9
|
+
thumbnail_url: nil, preview: nil)
|
|
10
|
+
@content_type = content_type
|
|
11
|
+
@content = content
|
|
12
|
+
@content_url = content_url
|
|
13
|
+
@name = name
|
|
14
|
+
@thumbnail_url = thumbnail_url
|
|
15
|
+
@preview = preview
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_h
|
|
19
|
+
body = {}
|
|
20
|
+
body["contentType"] = @content_type if @content_type
|
|
21
|
+
body["content"] = serialize(@content) if @content
|
|
22
|
+
body["contentUrl"] = @content_url if @content_url
|
|
23
|
+
body["name"] = @name if @name
|
|
24
|
+
body["thumbnailUrl"] = @thumbnail_url if @thumbnail_url
|
|
25
|
+
body["preview"] = serialize(@preview) if @preview
|
|
26
|
+
body
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def serialize(value)
|
|
32
|
+
value = value.to_h if value.respond_to?(:to_h) && !value.is_a?(Hash)
|
|
33
|
+
value.is_a?(Hash) ? Common::Hashes.deep_stringify_keys(value) : value
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# type: "result", "auth", "config", "message", "botMessagePreview", or
|
|
38
|
+
# "silentAuth"; attachment_layout: "list" or "grid".
|
|
39
|
+
class MessagingExtensionResult
|
|
40
|
+
def initialize(type: nil, attachment_layout: nil, attachments: nil,
|
|
41
|
+
suggested_actions: nil, text: nil, activity_preview: nil)
|
|
42
|
+
@type = type
|
|
43
|
+
@attachment_layout = attachment_layout
|
|
44
|
+
@attachments = attachments
|
|
45
|
+
@suggested_actions = suggested_actions
|
|
46
|
+
@text = text
|
|
47
|
+
@activity_preview = activity_preview
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_h
|
|
51
|
+
body = {}
|
|
52
|
+
body["type"] = @type if @type
|
|
53
|
+
body["attachmentLayout"] = @attachment_layout if @attachment_layout
|
|
54
|
+
body["attachments"] = @attachments.map { |attachment| serialize(attachment) } if @attachments
|
|
55
|
+
body["suggestedActions"] = serialize(@suggested_actions) if @suggested_actions
|
|
56
|
+
body["text"] = @text if @text
|
|
57
|
+
body["activityPreview"] = serialize(@activity_preview) if @activity_preview
|
|
58
|
+
body
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def serialize(value)
|
|
64
|
+
value = value.to_h if value.respond_to?(:to_h) && !value.is_a?(Hash)
|
|
65
|
+
value.is_a?(Hash) ? Common::Hashes.deep_stringify_keys(value) : value
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Response for the query-style message extension invokes (query,
|
|
70
|
+
# selectItem, queryLink, querySettingUrl, setting).
|
|
71
|
+
class MessagingExtensionResponse
|
|
72
|
+
def initialize(compose_extension, cache_info: nil)
|
|
73
|
+
@compose_extension = compose_extension
|
|
74
|
+
@cache_info = cache_info
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def to_h
|
|
78
|
+
body = {}
|
|
79
|
+
if @compose_extension
|
|
80
|
+
body["composeExtension"] =
|
|
81
|
+
@compose_extension.respond_to?(:to_h) ? @compose_extension.to_h : @compose_extension
|
|
82
|
+
end
|
|
83
|
+
body["cacheInfo"] = Common::Hashes.deep_stringify_keys(@cache_info) if @cache_info
|
|
84
|
+
body
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Response for the action-style invokes (submitAction, fetchTask):
|
|
89
|
+
# either a dialog via task: (a TaskModuleContinueResponse /
|
|
90
|
+
# TaskModuleMessageResponse) or a result via compose_extension:.
|
|
91
|
+
class MessagingExtensionActionResponse
|
|
92
|
+
def initialize(task: nil, compose_extension: nil, cache_info: nil)
|
|
93
|
+
@task = task
|
|
94
|
+
@compose_extension = compose_extension
|
|
95
|
+
@cache_info = cache_info
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def to_h
|
|
99
|
+
body = {}
|
|
100
|
+
body["task"] = @task.respond_to?(:to_h) ? @task.to_h : @task if @task
|
|
101
|
+
if @compose_extension
|
|
102
|
+
body["composeExtension"] =
|
|
103
|
+
@compose_extension.respond_to?(:to_h) ? @compose_extension.to_h : @compose_extension
|
|
104
|
+
end
|
|
105
|
+
body["cacheInfo"] = Common::Hashes.deep_stringify_keys(@cache_info) if @cache_info
|
|
106
|
+
body
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Teams
|
|
4
|
+
module Api
|
|
5
|
+
class Model
|
|
6
|
+
attr_reader :raw
|
|
7
|
+
|
|
8
|
+
def initialize(raw = {})
|
|
9
|
+
@raw = normalize_hash(raw)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_h
|
|
13
|
+
raw.dup
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def read(*keys)
|
|
19
|
+
keys.each do |key|
|
|
20
|
+
return raw[key] if raw.key?(key)
|
|
21
|
+
return raw[key.to_s] if raw.key?(key.to_s)
|
|
22
|
+
return raw[key.to_sym] if raw.key?(key.to_sym)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def normalize_hash(value)
|
|
29
|
+
value = value.to_h if value.respond_to?(:to_h)
|
|
30
|
+
return {} if value.nil?
|
|
31
|
+
|
|
32
|
+
value.each_with_object({}) do |(key, item), result|
|
|
33
|
+
result[key.to_s] = normalize_value(item)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def normalize_value(value)
|
|
38
|
+
case value
|
|
39
|
+
when Hash
|
|
40
|
+
normalize_hash(value)
|
|
41
|
+
when Array
|
|
42
|
+
value.map { |item| normalize_value(item) }
|
|
43
|
+
else
|
|
44
|
+
value
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Teams
|
|
4
|
+
module Api
|
|
5
|
+
class NotificationInfo < Model
|
|
6
|
+
def alert
|
|
7
|
+
read("alert")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def alert_in_meeting
|
|
11
|
+
read("alertInMeeting", "alert_in_meeting")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def external_resource_url
|
|
15
|
+
read("externalResourceUrl", "external_resource_url")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_h
|
|
19
|
+
body = raw.dup
|
|
20
|
+
body["alertInMeeting"] = alert_in_meeting unless alert_in_meeting.nil?
|
|
21
|
+
body["externalResourceUrl"] = external_resource_url if external_resource_url
|
|
22
|
+
body.delete("alert_in_meeting")
|
|
23
|
+
body.delete("external_resource_url")
|
|
24
|
+
body
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Teams
|
|
4
|
+
module Api
|
|
5
|
+
class PagedMembersResult < Model
|
|
6
|
+
def members
|
|
7
|
+
Array(read("members")).map { |member| Account.new(member) }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Token to fetch the next page of members; nil on the last page.
|
|
11
|
+
def continuation_token
|
|
12
|
+
read("continuationToken", "continuation_token")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Teams
|
|
4
|
+
module Api
|
|
5
|
+
class QuotedReplyData < Model
|
|
6
|
+
def message_id
|
|
7
|
+
read("messageId", "message_id")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def sender_id
|
|
11
|
+
read("senderId", "sender_id")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def sender_name
|
|
15
|
+
read("senderName", "sender_name")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def preview
|
|
19
|
+
read("preview")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def time
|
|
23
|
+
read("time")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def is_reply_deleted
|
|
27
|
+
read("isReplyDeleted", "is_reply_deleted")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def validated_message_reference
|
|
31
|
+
read("validatedMessageReference", "validated_message_reference")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_h
|
|
35
|
+
body = {}
|
|
36
|
+
body["messageId"] = message_id if message_id
|
|
37
|
+
body["senderId"] = sender_id if sender_id
|
|
38
|
+
body["senderName"] = sender_name if sender_name
|
|
39
|
+
body["preview"] = preview if preview
|
|
40
|
+
body["time"] = time if time
|
|
41
|
+
body["isReplyDeleted"] = is_reply_deleted unless is_reply_deleted.nil?
|
|
42
|
+
body["validatedMessageReference"] = validated_message_reference unless validated_message_reference.nil?
|
|
43
|
+
body
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class QuotedReplyEntity < Model
|
|
48
|
+
def type
|
|
49
|
+
"quotedReply"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def quoted_reply
|
|
53
|
+
value = read("quotedReply", "quoted_reply")
|
|
54
|
+
value.is_a?(QuotedReplyData) ? value : QuotedReplyData.new(value || {})
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def to_h
|
|
58
|
+
{
|
|
59
|
+
"type" => type,
|
|
60
|
+
"quotedReply" => quoted_reply.to_h
|
|
61
|
+
}
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
|
|
5
|
+
module Teams
|
|
6
|
+
module Api
|
|
7
|
+
class ReactionClient
|
|
8
|
+
attr_reader :service_url, :http
|
|
9
|
+
|
|
10
|
+
def initialize(service_url:, http:)
|
|
11
|
+
@service_url = service_url.sub(%r{/+\z}, "")
|
|
12
|
+
@http = http
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def add(conversation_id, activity_id, reaction_type)
|
|
16
|
+
http.put(path(conversation_id, activity_id, reaction_type))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def delete(conversation_id, activity_id, reaction_type)
|
|
20
|
+
http.delete(path(conversation_id, activity_id, reaction_type))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def path(conversation_id, activity_id, reaction_type)
|
|
26
|
+
"#{service_url}/v3/conversations/#{escape(conversation_id)}/activities/#{escape(activity_id)}/reactions/#{escape(reaction_type)}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def escape(value)
|
|
30
|
+
URI.encode_www_form_component(value.to_s)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Teams
|
|
4
|
+
module Api
|
|
5
|
+
# Represents an activity that was sent: the outbound activity merged with
|
|
6
|
+
# the server response, so the server-assigned id is always available.
|
|
7
|
+
# Mirrors the SDKs' SentActivity.
|
|
8
|
+
class SentActivity
|
|
9
|
+
attr_reader :raw
|
|
10
|
+
|
|
11
|
+
def self.merge(activity, response)
|
|
12
|
+
activity_hash = activity.respond_to?(:to_h) ? activity.to_h : activity
|
|
13
|
+
activity_hash = {} unless activity_hash.is_a?(Hash)
|
|
14
|
+
response_hash = response.is_a?(Hash) ? response : {}
|
|
15
|
+
|
|
16
|
+
new(activity_hash.merge(response_hash))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def initialize(raw = {})
|
|
20
|
+
@raw = raw
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def id
|
|
24
|
+
raw["id"] || raw[:id]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def type
|
|
28
|
+
raw["type"]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def text
|
|
32
|
+
raw["text"]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def conversation_id
|
|
36
|
+
raw.dig("conversation", "id")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def [](key)
|
|
40
|
+
raw[key]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def to_h
|
|
44
|
+
raw.dup
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Teams
|
|
4
|
+
module Api
|
|
5
|
+
# Dialog (task module) content definition: either a card dialog (card:)
|
|
6
|
+
# or a webpage dialog (url:). height/width take "small"/"medium"/"large"
|
|
7
|
+
# or pixel integers.
|
|
8
|
+
class TaskModuleTaskInfo
|
|
9
|
+
def initialize(title: nil, height: nil, width: nil, url: nil, card: nil,
|
|
10
|
+
fallback_url: nil, completion_bot_id: nil)
|
|
11
|
+
@title = title
|
|
12
|
+
@height = height
|
|
13
|
+
@width = width
|
|
14
|
+
@url = url
|
|
15
|
+
@card = card
|
|
16
|
+
@fallback_url = fallback_url
|
|
17
|
+
@completion_bot_id = completion_bot_id
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_h
|
|
21
|
+
body = {}
|
|
22
|
+
body["title"] = @title if @title
|
|
23
|
+
body["height"] = @height if @height
|
|
24
|
+
body["width"] = @width if @width
|
|
25
|
+
body["url"] = @url if @url
|
|
26
|
+
body["card"] = card_attachment(@card) if @card
|
|
27
|
+
body["fallbackUrl"] = @fallback_url if @fallback_url
|
|
28
|
+
body["completionBotId"] = @completion_bot_id if @completion_bot_id
|
|
29
|
+
body
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
# Accepts a ready attachment hash, or a card (Cards::AdaptiveCard or
|
|
35
|
+
# hash) which is wrapped like MessageActivity#add_card.
|
|
36
|
+
def card_attachment(card)
|
|
37
|
+
card = card.to_h if card.respond_to?(:to_h) && !card.is_a?(Hash)
|
|
38
|
+
return Common::Hashes.deep_stringify_keys(card) if card.is_a?(Hash) && card.key?("contentType")
|
|
39
|
+
|
|
40
|
+
{
|
|
41
|
+
"contentType" => "application/vnd.microsoft.card.adaptive",
|
|
42
|
+
"content" => card.is_a?(Hash) ? Common::Hashes.deep_stringify_keys(card) : card
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class TaskModuleContinueResponse
|
|
48
|
+
def initialize(value)
|
|
49
|
+
@value = value
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def to_h
|
|
53
|
+
{
|
|
54
|
+
"type" => "continue",
|
|
55
|
+
"value" => @value.respond_to?(:to_h) ? @value.to_h : @value
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class TaskModuleMessageResponse
|
|
61
|
+
def initialize(value)
|
|
62
|
+
@value = value
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def to_h
|
|
66
|
+
{ "type" => "message", "value" => @value.to_s }
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
class TaskModuleResponse
|
|
71
|
+
def initialize(task, cache_info: nil)
|
|
72
|
+
@task = task
|
|
73
|
+
@cache_info = cache_info
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def to_h
|
|
77
|
+
body = { "task" => @task.respond_to?(:to_h) ? @task.to_h : @task }
|
|
78
|
+
body["cacheInfo"] = Common::Hashes.deep_stringify_keys(@cache_info) if @cache_info
|
|
79
|
+
body
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
|
|
5
|
+
module Teams
|
|
6
|
+
module Api
|
|
7
|
+
class TeamClient
|
|
8
|
+
attr_reader :service_url, :http
|
|
9
|
+
|
|
10
|
+
def initialize(service_url:, http:, logger: nil)
|
|
11
|
+
@service_url = service_url.sub(%r{/+\z}, "")
|
|
12
|
+
@http = http
|
|
13
|
+
@logger = logger
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def get_by_id(team_id, service_url: nil)
|
|
17
|
+
path = "/v3/teams/#{escape(team_id)}"
|
|
18
|
+
url = absolute(path, service_url:)
|
|
19
|
+
@logger&.debug("Teams API GET #{url}")
|
|
20
|
+
TeamDetails.new(http.get(url))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns the team's channels; the service wraps them in a
|
|
24
|
+
# "conversations" envelope, which all the SDKs unwrap.
|
|
25
|
+
def get_conversations(team_id, service_url: nil)
|
|
26
|
+
path = "/v3/teams/#{escape(team_id)}/conversations"
|
|
27
|
+
url = absolute(path, service_url:)
|
|
28
|
+
@logger&.debug("Teams API GET #{url}")
|
|
29
|
+
response = http.get(url)
|
|
30
|
+
conversations = response.is_a?(Hash) ? Array(response["conversations"]) : []
|
|
31
|
+
conversations.map { |channel| ChannelInfo.new(channel) }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def absolute(path, service_url: nil)
|
|
37
|
+
"#{(service_url || self.service_url).sub(%r{/+\z}, "")}#{path}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def escape(value)
|
|
41
|
+
URI.encode_www_form_component(value.to_s)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Teams
|
|
4
|
+
module Api
|
|
5
|
+
class TeamDetails < Model
|
|
6
|
+
def id
|
|
7
|
+
read("id")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def name
|
|
11
|
+
read("name")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# "standard", "sharedChannel", or "privateChannel".
|
|
15
|
+
def type
|
|
16
|
+
read("type")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def aad_group_id
|
|
20
|
+
read("aadGroupId", "aad_group_id")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def channel_count
|
|
24
|
+
read("channelCount", "channel_count")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def member_count
|
|
28
|
+
read("memberCount", "member_count")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def tenant_id
|
|
32
|
+
read("tenantId", "tenant_id")
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Teams
|
|
4
|
+
module Api
|
|
5
|
+
class TeamInfo < Model
|
|
6
|
+
def id
|
|
7
|
+
read("id")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def name
|
|
11
|
+
read("name")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def team_type
|
|
15
|
+
read("teamType", "team_type")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def member_count
|
|
19
|
+
read("memberCount", "member_count")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def channel_count
|
|
23
|
+
read("channelCount", "channel_count")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def aad_group_id
|
|
27
|
+
read("aadGroupId", "aad_group_id")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_h
|
|
31
|
+
body = raw.dup
|
|
32
|
+
body["teamType"] = team_type if team_type
|
|
33
|
+
body["memberCount"] = member_count if member_count
|
|
34
|
+
body["channelCount"] = channel_count if channel_count
|
|
35
|
+
body["aadGroupId"] = aad_group_id if aad_group_id
|
|
36
|
+
body.delete("team_type")
|
|
37
|
+
body.delete("member_count")
|
|
38
|
+
body.delete("channel_count")
|
|
39
|
+
body.delete("aad_group_id")
|
|
40
|
+
body
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Teams
|
|
4
|
+
module Api
|
|
5
|
+
class TokenResponse < Model
|
|
6
|
+
def channel_id
|
|
7
|
+
read("channelId", "channel_id")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def connection_name
|
|
11
|
+
read("connectionName", "connection_name")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def token
|
|
15
|
+
read("token")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def expiration
|
|
19
|
+
read("expiration")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def properties
|
|
23
|
+
read("properties")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class TokenStatus < Model
|
|
28
|
+
def channel_id
|
|
29
|
+
read("channelId", "channel_id")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def connection_name
|
|
33
|
+
read("connectionName", "connection_name")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def has_token
|
|
37
|
+
read("hasToken", "has_token")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def service_provider_display_name
|
|
41
|
+
read("serviceProviderDisplayName", "service_provider_display_name")
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class TokenExchangeResource < Model
|
|
46
|
+
def id
|
|
47
|
+
read("id")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def uri
|
|
51
|
+
read("uri")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def provider_id
|
|
55
|
+
read("providerId", "provider_id")
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class TokenPostResource < Model
|
|
60
|
+
def sas_url
|
|
61
|
+
read("sasUrl", "sas_url")
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class SignInUrlResponse < Model
|
|
66
|
+
def sign_in_link
|
|
67
|
+
read("signInLink", "sign_in_link")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def token_exchange_resource
|
|
71
|
+
value = read("tokenExchangeResource", "token_exchange_resource")
|
|
72
|
+
value ? TokenExchangeResource.new(value) : nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def token_post_resource
|
|
76
|
+
value = read("tokenPostResource", "token_post_resource")
|
|
77
|
+
value ? TokenPostResource.new(value) : nil
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Teams
|
|
4
|
+
module Api
|
|
5
|
+
class TypingActivity
|
|
6
|
+
attr_reader :text
|
|
7
|
+
|
|
8
|
+
def initialize(text = nil)
|
|
9
|
+
@text = text
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_h
|
|
13
|
+
body = { "type" => "typing" }
|
|
14
|
+
body["text"] = text if text
|
|
15
|
+
body
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|