flow_chat 0.4.1 → 0.5.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.
@@ -57,10 +57,10 @@ module FlowChat
57
57
  end
58
58
 
59
59
  buttons = [
60
- { id: "yes", title: "Yes" },
61
- { id: "no", title: "No" }
60
+ {id: "yes", title: "Yes"},
61
+ {id: "no", title: "No"}
62
62
  ]
63
- raise FlowChat::Interrupt::Prompt.new([:interactive_buttons, message, { buttons: buttons }])
63
+ raise FlowChat::Interrupt::Prompt.new([:interactive_buttons, message, {buttons: buttons}])
64
64
  end
65
65
 
66
66
  private
@@ -72,15 +72,15 @@ module FlowChat
72
72
 
73
73
  case media_type.to_sym
74
74
  when :image
75
- [:media_image, "", { url: url, caption: message }]
75
+ [:media_image, "", {url: url, caption: message}]
76
76
  when :document
77
- [:media_document, "", { url: url, caption: message, filename: filename }]
77
+ [:media_document, "", {url: url, caption: message, filename: filename}]
78
78
  when :audio
79
- [:media_audio, "", { url: url, caption: message }]
79
+ [:media_audio, "", {url: url, caption: message}]
80
80
  when :video
81
- [:media_video, "", { url: url, caption: message }]
81
+ [:media_video, "", {url: url, caption: message}]
82
82
  when :sticker
83
- [:media_sticker, "", { url: url }] # Stickers don't support captions
83
+ [:media_sticker, "", {url: url}] # Stickers don't support captions
84
84
  else
85
85
  raise ArgumentError, "Unsupported media type: #{media_type}"
86
86
  end
@@ -113,21 +113,19 @@ module FlowChat
113
113
  }
114
114
  end
115
115
 
116
- [:interactive_buttons, message, { buttons: buttons }]
116
+ [:interactive_buttons, message, {buttons: buttons}]
117
117
  end
118
118
 
119
119
  def build_list_prompt(message, choices)
120
120
  items = choices.map do |key, value|
121
121
  original_text = value.to_s
122
122
  truncated_title = truncate_text(original_text, 24)
123
-
123
+
124
124
  # If title was truncated, put full text in description (up to 72 chars)
125
125
  description = if original_text.length > 24
126
- truncate_text(original_text, 72)
127
- else
128
- nil
129
- end
130
-
126
+ truncate_text(original_text, 72)
127
+ end
128
+
131
129
  {
132
130
  id: key.to_s,
133
131
  title: truncated_title,
@@ -136,8 +134,8 @@ module FlowChat
136
134
  end
137
135
 
138
136
  # If 10 or fewer items, use single section
139
- if items.length <= 10
140
- sections = [
137
+ sections = if items.length <= 10
138
+ [
141
139
  {
142
140
  title: "Options",
143
141
  rows: items
@@ -145,10 +143,10 @@ module FlowChat
145
143
  ]
146
144
  else
147
145
  # Paginate into multiple sections (max 10 items per section)
148
- sections = items.each_slice(10).with_index.map do |section_items, index|
146
+ items.each_slice(10).with_index.map do |section_items, index|
149
147
  start_num = (index * 10) + 1
150
148
  end_num = start_num + section_items.length - 1
151
-
149
+
152
150
  {
153
151
  title: "#{start_num}-#{end_num}",
154
152
  rows: section_items
@@ -156,7 +154,7 @@ module FlowChat
156
154
  end
157
155
  end
158
156
 
159
- [:interactive_list, message, { sections: sections }]
157
+ [:interactive_list, message, {sections: sections}]
160
158
  end
161
159
 
162
160
  def process_input(input, transform, validate, convert)
@@ -178,8 +176,8 @@ module FlowChat
178
176
  end
179
177
 
180
178
  def process_selection(input, choices, transform, validate, convert)
181
- choice_hash = choices.is_a?(Array) ?
182
- choices.each_with_index.to_h { |choice, index| [index.to_s, choice] } :
179
+ choice_hash = choices.is_a?(Array) ?
180
+ choices.each_with_index.to_h { |choice, index| [index.to_s, choice] } :
183
181
  choices
184
182
 
185
183
  # Check if input matches a valid choice
@@ -199,13 +197,11 @@ module FlowChat
199
197
 
200
198
  def process_boolean(input, transform, validate, convert)
201
199
  boolean_value = case input.to_s.downcase
202
- when "yes", "y", "1", "true"
203
- true
204
- when "no", "n", "0", "false"
205
- false
206
- else
207
- nil
208
- end
200
+ when "yes", "y", "1", "true"
201
+ true
202
+ when "no", "n", "0", "false"
203
+ false
204
+ end
209
205
 
210
206
  if boolean_value.nil?
211
207
  raise FlowChat::Interrupt::Prompt.new([:text, "Please answer with Yes or No.", {}])
@@ -220,7 +216,7 @@ module FlowChat
220
216
  raise ArgumentError, "choices cannot be empty"
221
217
  end
222
218
 
223
- choice_count = choices.is_a?(Array) ? choices.length : choices.length
219
+ choice_count = choices.length
224
220
 
225
221
  # WhatsApp supports max 100 total items across all sections
226
222
  if choice_count > 100
@@ -248,4 +244,4 @@ module FlowChat
248
244
  end
249
245
  end
250
246
  end
251
- end
247
+ end
@@ -15,11 +15,11 @@ module FlowChat
15
15
  def perform_whatsapp_send(send_data)
16
16
  config = resolve_whatsapp_config(send_data)
17
17
  client = FlowChat::Whatsapp::Client.new(config)
18
-
18
+
19
19
  result = client.send_message(send_data[:msisdn], send_data[:response])
20
-
20
+
21
21
  if result
22
- Rails.logger.info "WhatsApp message sent successfully: #{result['messages']&.first&.dig('id')}"
22
+ Rails.logger.info "WhatsApp message sent successfully: #{result["messages"]&.first&.dig("id")}"
23
23
  on_whatsapp_send_success(send_data, result)
24
24
  else
25
25
  Rails.logger.error "Failed to send WhatsApp message to #{send_data[:msisdn]}"
@@ -47,20 +47,20 @@ module FlowChat
47
47
  def handle_whatsapp_send_error(error, send_data, config = nil)
48
48
  Rails.logger.error "WhatsApp send job error: #{error.message}"
49
49
  Rails.logger.error error.backtrace&.join("\n") if error.backtrace
50
-
50
+
51
51
  # Try to send error message to user if we have config
52
52
  if config
53
53
  begin
54
54
  client = FlowChat::Whatsapp::Client.new(config)
55
55
  client.send_text(
56
- send_data[:msisdn],
56
+ send_data[:msisdn],
57
57
  "⚠️ We're experiencing technical difficulties. Please try again in a few minutes."
58
58
  )
59
59
  rescue => send_error
60
60
  Rails.logger.error "Failed to send error message: #{send_error.message}"
61
61
  end
62
62
  end
63
-
63
+
64
64
  # Re-raise for job retry logic
65
65
  raise error
66
66
  end
@@ -76,4 +76,4 @@ module FlowChat
76
76
  end
77
77
  end
78
78
  end
79
- end
79
+ end
@@ -16,7 +16,7 @@ module FlowChat
16
16
  type: "template",
17
17
  template: {
18
18
  name: template_name,
19
- language: { code: language },
19
+ language: {code: language},
20
20
  components: components
21
21
  }
22
22
  }
@@ -27,7 +27,7 @@ module FlowChat
27
27
  # Common template structures
28
28
  def send_welcome_template(to:, name: nil)
29
29
  components = []
30
-
30
+
31
31
  if name
32
32
  components << {
33
33
  type: "header",
@@ -86,8 +86,8 @@ module FlowChat
86
86
  # Create a new template (requires approval from Meta)
87
87
  def create_template(name:, category:, language: "en_US", components: [])
88
88
  business_account_id = @config.business_account_id
89
- uri = URI("https://graph.facebook.com/v18.0/#{business_account_id}/message_templates")
90
-
89
+ uri = URI("#{FlowChat::Config.whatsapp.api_base_url}/#{business_account_id}/message_templates")
90
+
91
91
  template_data = {
92
92
  name: name,
93
93
  category: category, # AUTHENTICATION, MARKETING, UTILITY
@@ -110,8 +110,8 @@ module FlowChat
110
110
  # List all templates
111
111
  def list_templates
112
112
  business_account_id = @config.business_account_id
113
- uri = URI("https://graph.facebook.com/v18.0/#{business_account_id}/message_templates")
114
-
113
+ uri = URI("#{FlowChat::Config.whatsapp.api_base_url}/#{business_account_id}/message_templates")
114
+
115
115
  http = Net::HTTP.new(uri.host, uri.port)
116
116
  http.use_ssl = true
117
117
 
@@ -124,8 +124,8 @@ module FlowChat
124
124
 
125
125
  # Get template status
126
126
  def template_status(template_id)
127
- uri = URI("https://graph.facebook.com/v18.0/#{template_id}")
128
-
127
+ uri = URI("#{FlowChat::Config.whatsapp.api_base_url}/#{template_id}")
128
+
129
129
  http = Net::HTTP.new(uri.host, uri.port)
130
130
  http.use_ssl = true
131
131
 
@@ -149,7 +149,7 @@ module FlowChat
149
149
  request.body = message_data.to_json
150
150
 
151
151
  response = http.request(request)
152
-
152
+
153
153
  unless response.is_a?(Net::HTTPSuccess)
154
154
  Rails.logger.error "WhatsApp Template API error: #{response.body}"
155
155
  return nil
@@ -159,4 +159,4 @@ module FlowChat
159
159
  end
160
160
  end
161
161
  end
162
- end
162
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flow_chat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Froelich
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-06-04 00:00:00.000000000 Z
11
+ date: 2025-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -95,11 +95,13 @@ files:
95
95
  - LICENSE.txt
96
96
  - README.md
97
97
  - Rakefile
98
+ - SECURITY.md
98
99
  - bin/console
99
100
  - bin/setup
100
101
  - examples/initializer.rb
101
102
  - examples/media_prompts_examples.rb
102
103
  - examples/multi_tenant_whatsapp_controller.rb
104
+ - examples/simulator_controller.rb
103
105
  - examples/ussd_controller.rb
104
106
  - examples/whatsapp_controller.rb
105
107
  - examples/whatsapp_media_examples.rb