chat_sdk-gchat 1.1.0 → 1.3.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: c07828b323f52de29ac4f1fa5cd28a9ebc1991218919943ab098c282f12abf10
4
- data.tar.gz: df8107d2939c79638eb19e72f556f3b418022edb3edf92fda051396d1f4ec6e6
3
+ metadata.gz: '08f7bf3bc0128b23b9e9bb9d68431f7ce573179c6e40e6f61d942cf1c4770dea'
4
+ data.tar.gz: e13b88766dfe5be010298320aa8406d818068dfd7709298e3c2da958a6c2993a
5
5
  SHA512:
6
- metadata.gz: 827f9b4143159fd535cf282add46628591da26d2c1ba2cc83196622adf2f1ed76e8132e77291a13c7662673f7602be7fed0d02a9ac924472c6ec3d27426f81f5
7
- data.tar.gz: 9ac83233af904d852c3706b73b6694ba0b78a03997782923def45689e8bb417e84eca20c166c28d6d4843c760647d360a7522b4a29dd74464582fcd6671f8df9
6
+ metadata.gz: 9498945602865b18d40f6389afe9673a46460b0fc25fe56318d7b621901d2aa586fa189eb2159adde02358eb95c6ed67e04c1e713450bf981d71c7a2e56268ba
7
+ data.tar.gz: 87693f0e0e19e74e753ee79df79f20708a35e63182df5bd370cd970556e811e93ce273a10a61243f65fd843b4dcb0b73f8000077809487e7eec4d25e6e7b58fe
@@ -81,11 +81,11 @@ module ChatSDK
81
81
  build_response_message(result, channel_id, msg)
82
82
  end
83
83
 
84
- def edit_message(channel_id:, message_id:, message:)
84
+ def edit_message(channel_id:, message_id:, message:, **_options)
85
85
  require_capability!(:edit_messages)
86
86
  msg = ChatSDK::PostableMessage.from(message)
87
87
  request_body = build_message_body(msg)
88
- request_body[:name] = "spaces/#{channel_id}/messages/#{message_id}"
88
+ request_body[:name] = message_resource_name(channel_id, message_id)
89
89
 
90
90
  @client.update_message(
91
91
  message: request_body,
@@ -93,9 +93,9 @@ module ChatSDK
93
93
  )
94
94
  end
95
95
 
96
- def delete_message(channel_id:, message_id:)
96
+ def delete_message(channel_id:, message_id:, **_options)
97
97
  require_capability!(:delete_messages)
98
- @client.delete_message(name: "spaces/#{channel_id}/messages/#{message_id}")
98
+ @client.delete_message(name: message_resource_name(channel_id, message_id))
99
99
  end
100
100
 
101
101
  def post_ephemeral(channel_id:, user_id:, message:, thread_id: nil)
@@ -120,22 +120,22 @@ module ChatSDK
120
120
  super
121
121
  end
122
122
 
123
- def add_reaction(channel_id:, message_id:, emoji:)
123
+ def add_reaction(channel_id:, message_id:, emoji:, **_options)
124
124
  require_capability!(:reactions)
125
125
  @client.create_reaction(
126
- parent: "spaces/#{channel_id}/messages/#{message_id}",
126
+ parent: message_resource_name(channel_id, message_id),
127
127
  reaction: {
128
128
  emoji: {unicode: emoji}
129
129
  }
130
130
  )
131
131
  end
132
132
 
133
- def remove_reaction(channel_id:, message_id:, emoji:)
133
+ def remove_reaction(channel_id:, message_id:, emoji:, **_options)
134
134
  require_capability!(:reactions)
135
135
  # Google Chat requires the reaction resource name to delete
136
136
  # We construct it from the emoji unicode
137
137
  @client.delete_reaction(
138
- name: "spaces/#{channel_id}/messages/#{message_id}/reactions/#{emoji}"
138
+ name: "#{message_resource_name(channel_id, message_id)}/reactions/#{emoji}"
139
139
  )
140
140
  end
141
141
 
@@ -164,7 +164,7 @@ module ChatSDK
164
164
  super
165
165
  end
166
166
 
167
- def start_typing(channel_id:, thread_id: nil)
167
+ def start_typing(channel_id:, thread_id: nil, message_id: nil)
168
168
  super
169
169
  end
170
170
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "cgi"
4
+
3
5
  module ChatSDK
4
6
  module GChat
5
7
  class CardV2Renderer
@@ -24,10 +26,16 @@ module ChatSDK
24
26
  end
25
27
 
26
28
  def build_header(node)
27
- return nil unless node.attributes[:title]
29
+ image_url = node.attributes[:image_url]
30
+ has_image_url = image_url && !image_url.empty?
31
+ return nil unless node.attributes[:title] || has_image_url
28
32
 
29
- header = {title: node.attributes[:title]}
33
+ header = {title: node.attributes[:title] || ""}
30
34
  header[:subtitle] = node.attributes[:subtitle] if node.attributes[:subtitle]
35
+ if has_image_url
36
+ header[:imageUrl] = image_url
37
+ header[:imageType] = "SQUARE"
38
+ end
31
39
  header
32
40
  end
33
41
 
@@ -60,11 +68,13 @@ module ChatSDK
60
68
  def render_widget(node)
61
69
  case node.type
62
70
  when :text then render_text(node)
71
+ when :link then render_link(node)
63
72
  when :fields then render_fields(node)
64
73
  when :image then render_image(node)
65
74
  when :actions then render_actions(node)
66
75
  when :divider then {divider: {}}
67
76
  when :select then render_select(node)
77
+ when :radio_select then render_radio_select(node)
68
78
  end
69
79
  end
70
80
 
@@ -78,7 +88,15 @@ module ChatSDK
78
88
  end
79
89
 
80
90
  def render_text(node)
81
- {textParagraph: {text: node.attributes[:content]}}
91
+ text = node.attributes[:content]
92
+ text = "*#{text}*" if node.attributes[:style] == :bold
93
+ {textParagraph: {text: text}}
94
+ end
95
+
96
+ def render_link(node)
97
+ url = CGI.escapeHTML(node.attributes[:url].to_s)
98
+ label = CGI.escapeHTML(node.attributes[:label].to_s)
99
+ {textParagraph: {text: %(<a href="#{url}">#{label}</a>)}}
82
100
  end
83
101
 
84
102
  def render_fields(node)
@@ -106,10 +124,15 @@ module ChatSDK
106
124
  widgets = []
107
125
  buttons = []
108
126
  node.children.each do |child|
109
- if child.type == :select
127
+ if %i[select radio_select].include?(child.type)
110
128
  widgets << render_button_list(buttons) unless buttons.empty?
111
129
  buttons = []
112
- widgets << render_select(child)
130
+ widget = if child.type == :radio_select
131
+ render_radio_select(child)
132
+ else
133
+ render_select(child)
134
+ end
135
+ widgets << widget
113
136
  else
114
137
  btn = render_action_element(child)
115
138
  buttons << btn if btn
@@ -152,36 +175,56 @@ module ChatSDK
152
175
  elsif node.attributes[:style] == :danger
153
176
  btn[:color] = {red: 0.87, green: 0.17, blue: 0.17, alpha: 1.0}
154
177
  end
178
+ btn[:disabled] = true if node.attributes[:disabled]
155
179
 
156
180
  btn
157
181
  end
158
182
 
159
183
  def render_link_button(node)
160
- {
184
+ button = {
161
185
  text: node.attributes[:text],
162
186
  onClick: {
163
187
  openLink: {url: node.attributes[:url]}
164
188
  }
165
189
  }
190
+ if node.attributes[:style] == :primary
191
+ button[:color] = {red: 0.0, green: 0.53, blue: 0.87, alpha: 1.0}
192
+ elsif node.attributes[:style] == :danger
193
+ button[:color] = {red: 0.87, green: 0.17, blue: 0.17, alpha: 1.0}
194
+ end
195
+ button
166
196
  end
167
197
 
168
198
  def render_select(node)
199
+ render_selection_input(node, type: "DROPDOWN")
200
+ end
201
+
202
+ def render_radio_select(node)
203
+ render_selection_input(node, type: "RADIO_BUTTON")
204
+ end
205
+
206
+ def render_selection_input(node, type:)
169
207
  {
170
208
  selectionInput: {
171
209
  name: node.attributes[:id],
172
- label: node.attributes[:placeholder] || "Select",
173
- type: "DROPDOWN",
174
- items: node.children.map { |opt| render_select_option(opt) }
210
+ label: node.attributes[:label] || node.attributes[:placeholder] || "Select",
211
+ type: type,
212
+ items: node.children.map { |option| render_select_option(option, node.attributes[:initial_option]) }
175
213
  }
176
214
  }
177
215
  end
178
216
 
179
- def render_select_option(node)
180
- {
217
+ def render_select_option(node, initial_option)
218
+ option = {
181
219
  text: node.attributes[:text],
182
- value: node.attributes[:value],
183
- selected: false
220
+ value: node.attributes[:value]
184
221
  }
222
+ if initial_option.nil?
223
+ option[:selected] = false
224
+ elsif node.attributes[:value] == initial_option
225
+ option[:selected] = true
226
+ end
227
+ option
185
228
  end
186
229
  end
187
230
  end
@@ -3,10 +3,40 @@
3
3
  module ChatSDK
4
4
  module GChat
5
5
  module ResourceName
6
+ MESSAGE_ID_PATTERN = /\A[A-Za-z0-9_.-]+\z/
7
+ SPACE_ID_PATTERN = /\A[A-Za-z0-9_-]+\z/
8
+
6
9
  def extract_id(resource_name)
7
10
  return resource_name unless resource_name.is_a?(String)
8
11
  resource_name.split("/").last || resource_name
9
12
  end
13
+
14
+ def message_resource_name(channel_id, message_id)
15
+ space_id = channel_id.to_s
16
+ unless channel_id.is_a?(String) && SPACE_ID_PATTERN.match?(space_id)
17
+ raise ChatSDK::Error, "Invalid Google Chat space ID: #{channel_id.inspect}"
18
+ end
19
+
20
+ unless message_id.is_a?(String)
21
+ raise ChatSDK::Error, "Invalid Google Chat message ID: #{message_id.inspect}"
22
+ end
23
+
24
+ space_name = "spaces/#{space_id}"
25
+ prefix = "#{space_name}/messages/"
26
+ message_name = message_id
27
+ message_name = "#{prefix}#{message_name}" if MESSAGE_ID_PATTERN.match?(message_name)
28
+
29
+ unless message_name.start_with?(prefix)
30
+ raise ChatSDK::Error, "Invalid Google Chat message ID: #{message_id.inspect}"
31
+ end
32
+
33
+ id = message_name.delete_prefix(prefix)
34
+ unless MESSAGE_ID_PATTERN.match?(id) && id != "." && id != ".."
35
+ raise ChatSDK::Error, "Invalid Google Chat message ID: #{message_id.inspect}"
36
+ end
37
+
38
+ "#{prefix}#{id}"
39
+ end
10
40
  end
11
41
  end
12
42
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chat_sdk-gchat
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Quentin Rousseau
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '0.1'
18
+ version: '1.3'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: '0.1'
25
+ version: '1.3'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: google-apps-chat-v1
28
28
  requirement: !ruby/object:Gem::Requirement