warb 0.1.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.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +8 -0
  4. data/CHANGELOG.md +25 -0
  5. data/README.md +135 -0
  6. data/Rakefile +12 -0
  7. data/docs/README.md +16 -0
  8. data/docs/components/README.md +24 -0
  9. data/docs/components/address.md +68 -0
  10. data/docs/components/button.md +61 -0
  11. data/docs/components/copy_code_button.md +57 -0
  12. data/docs/components/cta_action.md +13 -0
  13. data/docs/components/email.md +40 -0
  14. data/docs/components/list_action.md +29 -0
  15. data/docs/components/name.md +49 -0
  16. data/docs/components/org.md +42 -0
  17. data/docs/components/phone.md +57 -0
  18. data/docs/components/reply_button_action.md +32 -0
  19. data/docs/components/row.md +13 -0
  20. data/docs/components/section.md +30 -0
  21. data/docs/components/url.md +40 -0
  22. data/docs/components/url_button.md +57 -0
  23. data/docs/images/contact-with-wa_id.png +0 -0
  24. data/docs/images/contact-without-wa_id.png +0 -0
  25. data/docs/messages/README.md +80 -0
  26. data/docs/messages/audio.md +119 -0
  27. data/docs/messages/contact.md +134 -0
  28. data/docs/messages/document.md +122 -0
  29. data/docs/messages/flow.md +12 -0
  30. data/docs/messages/image.md +116 -0
  31. data/docs/messages/indicator.md +39 -0
  32. data/docs/messages/interactive_call_to_action_url.md +96 -0
  33. data/docs/messages/interactive_list.md +159 -0
  34. data/docs/messages/interactive_reply_button.md +67 -0
  35. data/docs/messages/location.md +34 -0
  36. data/docs/messages/location_request.md +21 -0
  37. data/docs/messages/reaction.md +23 -0
  38. data/docs/messages/sticker.md +116 -0
  39. data/docs/messages/template.md +327 -0
  40. data/docs/messages/text.md +47 -0
  41. data/docs/messages/video.md +116 -0
  42. data/docs/resources/currency.md +22 -0
  43. data/docs/resources/date_time.md +11 -0
  44. data/docs/resources/index.md +14 -0
  45. data/docs/resources/text.md +9 -0
  46. data/docs/setup.md +46 -0
  47. data/docs/webhook.md +24 -0
  48. data/examples/audio.rb +86 -0
  49. data/examples/document.rb +116 -0
  50. data/examples/image.rb +97 -0
  51. data/examples/interactive_call_to_action_url.rb +177 -0
  52. data/examples/interactive_list.rb +201 -0
  53. data/examples/interactive_reply_button.rb +174 -0
  54. data/examples/location.rb +85 -0
  55. data/examples/location_request.rb +55 -0
  56. data/examples/message.rb +61 -0
  57. data/examples/sticker.rb +86 -0
  58. data/examples/video.rb +96 -0
  59. data/examples/webhook.rb +144 -0
  60. data/lib/warb/client.rb +46 -0
  61. data/lib/warb/components/action.rb +121 -0
  62. data/lib/warb/components/address.rb +31 -0
  63. data/lib/warb/components/button.rb +29 -0
  64. data/lib/warb/components/component.rb +19 -0
  65. data/lib/warb/components/copy_code_button.rb +30 -0
  66. data/lib/warb/components/email.rb +21 -0
  67. data/lib/warb/components/name.rb +29 -0
  68. data/lib/warb/components/org.rb +23 -0
  69. data/lib/warb/components/phone.rb +23 -0
  70. data/lib/warb/components/quick_reply_button.rb +15 -0
  71. data/lib/warb/components/url.rb +21 -0
  72. data/lib/warb/components/url_button.rb +30 -0
  73. data/lib/warb/components/voice_call_button.rb +15 -0
  74. data/lib/warb/configuration.rb +13 -0
  75. data/lib/warb/connection.rb +47 -0
  76. data/lib/warb/dispatcher.rb +16 -0
  77. data/lib/warb/dispatcher_concern.rb +73 -0
  78. data/lib/warb/indicator_dispatcher.rb +31 -0
  79. data/lib/warb/language.rb +8 -0
  80. data/lib/warb/media_dispatcher.rb +46 -0
  81. data/lib/warb/resources/audio.rb +19 -0
  82. data/lib/warb/resources/contact.rb +89 -0
  83. data/lib/warb/resources/currency.rb +45 -0
  84. data/lib/warb/resources/date_time.rb +34 -0
  85. data/lib/warb/resources/document.rb +32 -0
  86. data/lib/warb/resources/flow.rb +34 -0
  87. data/lib/warb/resources/image.rb +31 -0
  88. data/lib/warb/resources/interactive_call_to_action_url.rb +48 -0
  89. data/lib/warb/resources/interactive_list.rb +36 -0
  90. data/lib/warb/resources/interactive_reply_button.rb +48 -0
  91. data/lib/warb/resources/location.rb +31 -0
  92. data/lib/warb/resources/location_request.rb +24 -0
  93. data/lib/warb/resources/reaction.rb +19 -0
  94. data/lib/warb/resources/resource.rb +59 -0
  95. data/lib/warb/resources/sticker.rb +19 -0
  96. data/lib/warb/resources/template.rb +166 -0
  97. data/lib/warb/resources/text.rb +47 -0
  98. data/lib/warb/resources/video.rb +31 -0
  99. data/lib/warb/template_dispatcher.rb +10 -0
  100. data/lib/warb/utils.rb +5 -0
  101. data/lib/warb/version.rb +5 -0
  102. data/lib/warb.rb +69 -0
  103. data/sig/warb.rbs +4 -0
  104. metadata +172 -0
@@ -0,0 +1,73 @@
1
+ module Warb
2
+ module DispatcherConcern
3
+ def message
4
+ @message ||= Dispatcher.new Resources::Text, dispatcher
5
+ end
6
+
7
+ def image
8
+ @image ||= MediaDispatcher.new Resources::Image, dispatcher
9
+ end
10
+
11
+ def video
12
+ @video ||= MediaDispatcher.new Resources::Video, dispatcher
13
+ end
14
+
15
+ def audio
16
+ @audio ||= MediaDispatcher.new Resources::Audio, dispatcher
17
+ end
18
+
19
+ def document
20
+ @document ||= MediaDispatcher.new Resources::Document, dispatcher
21
+ end
22
+
23
+ def location
24
+ @location ||= Dispatcher.new Resources::Location, dispatcher
25
+ end
26
+
27
+ def location_request
28
+ @location_request ||= Dispatcher.new Resources::LocationRequest, dispatcher
29
+ end
30
+
31
+ def interactive_reply_button
32
+ @interactive_reply_button ||= Dispatcher.new Resources::InteractiveReplyButton, dispatcher
33
+ end
34
+
35
+ def interactive_list
36
+ @interactive_list ||= Dispatcher.new Resources::InteractiveList, dispatcher
37
+ end
38
+
39
+ def interactive_call_to_action_url
40
+ @interactive_call_to_action_url ||= Dispatcher.new Resources::InteractiveCallToActionUrl, dispatcher
41
+ end
42
+
43
+ def sticker
44
+ @sticker ||= MediaDispatcher.new Resources::Sticker, dispatcher
45
+ end
46
+
47
+ def reaction
48
+ @reaction ||= Dispatcher.new Resources::Reaction, dispatcher
49
+ end
50
+
51
+ def indicator
52
+ @indicator ||= IndicatorDispatcher.new dispatcher
53
+ end
54
+
55
+ def contact
56
+ @contact ||= Dispatcher.new Resources::Contact, dispatcher
57
+ end
58
+
59
+ def template
60
+ @template ||= TemplateDispatcher.new Resources::Template, dispatcher
61
+ end
62
+
63
+ def flow
64
+ @flow ||= Dispatcher.new Resources::Flow, dispatcher
65
+ end
66
+
67
+ private
68
+
69
+ def dispatcher
70
+ is_a?(Client) ? self : Warb.client
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ class IndicatorDispatcher
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ def send_typing_indicator(message_id)
10
+ data = common_indicator_params(message_id).merge(typing_indicator: { type: "text" })
11
+
12
+ @client.post("messages", data)
13
+ end
14
+
15
+ def mark_as_read(message_id)
16
+ data = common_indicator_params(message_id)
17
+
18
+ @client.post("messages", data)
19
+ end
20
+
21
+ private
22
+
23
+ def common_indicator_params(message_id)
24
+ {
25
+ messaging_product: Warb::MESSAGING_PRODUCT,
26
+ message_id: message_id,
27
+ status: "read"
28
+ }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ module Language
5
+ ENGLISH_US = "en_US"
6
+ PORTUGUESE_BR = "pt_BR"
7
+ end
8
+ end
@@ -0,0 +1,46 @@
1
+ module Warb
2
+ class MediaDispatcher < Dispatcher
3
+ def upload(file_path:, file_type: "text/plain")
4
+ file = Faraday::UploadIO.new(file_path, file_type)
5
+
6
+ data = { file:, messaging_product: Warb::MESSAGING_PRODUCT }
7
+
8
+ @client.post("media", data, multipart: true).body["id"]
9
+ end
10
+
11
+ def download(file_path:, media_url: nil, media_id: nil)
12
+ media_url ||= retrieve(media_id)["url"]
13
+
14
+ resp = downloaded_media_response(media_url)
15
+
16
+ File.open(file_path, "wb") do |file|
17
+ file.write(resp.body)
18
+ end
19
+ end
20
+
21
+ def retrieve(media_id)
22
+ @client.get(media_id, endpoint_prefix: nil).body
23
+ end
24
+
25
+ def delete(media_id)
26
+ response_body = @client.delete(media_id, endpoint_prefix: nil).body
27
+
28
+ return response_body["success"] if response_body["success"]
29
+
30
+ response_body["error"]["message"]
31
+ end
32
+
33
+ private
34
+
35
+ def downloaded_media_response(url)
36
+ uri = URI(url)
37
+
38
+ request = Net::HTTP::Get.new(uri)
39
+ request["Authorization"] = "Bearer #{@client.access_token}"
40
+
41
+ Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
42
+ http.request(request)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ module Resources
5
+ class Audio < Resource
6
+ attr_accessor :media_id, :link
7
+
8
+ def build_payload
9
+ {
10
+ type: "audio",
11
+ audio: {
12
+ id: media_id || @params[:media_id],
13
+ link: link || @params[:link]
14
+ }
15
+ }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../components/address"
4
+ require_relative "../components/name"
5
+ require_relative "../components/email"
6
+ require_relative "../components/org"
7
+ require_relative "../components/phone"
8
+ require_relative "../components/url"
9
+
10
+ module Warb
11
+ module Resources
12
+ class Contact < Resource
13
+ attr_accessor :addresses, :emails, :phones, :urls, :name, :org, :birthday
14
+
15
+ def initialize(**params)
16
+ super(**params)
17
+
18
+ @org = @params[:org]
19
+ @name = @params[:name]
20
+ @birthday = @params[:birthday]
21
+ @addresses = @params.fetch(:addresses, [])
22
+ @emails = @params.fetch(:emails, [])
23
+ @phones = @params.fetch(:phones, [])
24
+ @urls = @params.fetch(:urls, [])
25
+ end
26
+
27
+ def build_payload
28
+ {
29
+ type: "contacts",
30
+ contacts: [
31
+ {
32
+ birthday: birthday,
33
+ org: org.to_h,
34
+ name: name.to_h,
35
+ urls: urls.map(&:to_h),
36
+ emails: emails.map(&:to_h),
37
+ phones: phones.map(&:to_h),
38
+ addresses: addresses.map(&:to_h)
39
+ }
40
+ ]
41
+ }
42
+ end
43
+
44
+ def add_address(**params, &block)
45
+ address = Components::Address.new(**params)
46
+
47
+ @addresses << address
48
+
49
+ block_given? ? address.tap(&block) : address
50
+ end
51
+
52
+ def add_email(**params, &block)
53
+ email = Components::Email.new(**params)
54
+
55
+ @emails << email
56
+
57
+ block_given? ? email.tap(&block) : email
58
+ end
59
+
60
+ def add_phone(**params, &block)
61
+ phone = Components::Phone.new(**params)
62
+
63
+ @phones << phone
64
+
65
+ block_given? ? phone.tap(&block) : phone
66
+ end
67
+
68
+ def add_url(**params, &block)
69
+ url = Components::URL.new(**params)
70
+
71
+ @urls << url
72
+
73
+ block_given? ? url.tap(&block) : url
74
+ end
75
+
76
+ def build_name(**params, &block)
77
+ @name = Warb::Components::Name.new(**params)
78
+
79
+ block_given? ? @name.tap(&block) : @name
80
+ end
81
+
82
+ def build_org(**params, &block)
83
+ @org = Warb::Components::Org.new(**params)
84
+
85
+ block_given? ? @org.tap(&block) : @org
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ module Resources
5
+ class Currency < Resource
6
+ BRL = "BRL"
7
+ USD = "USD"
8
+
9
+ attr_accessor :amount, :code, :fallback
10
+
11
+ def initialize(**params)
12
+ super(**params)
13
+
14
+ @code = params[:code]
15
+ @amount = params[:amount]
16
+ @fallback = params[:fallback]
17
+ end
18
+
19
+ def build_template_named_parameter(parameter_name)
20
+ common_currency_params.merge(parameter_name: parameter_name)
21
+ end
22
+
23
+ def build_template_positional_parameter
24
+ common_currency_params
25
+ end
26
+
27
+ private
28
+
29
+ def common_currency_params
30
+ {
31
+ type: "currency",
32
+ currency: {
33
+ amount_1000: amount * 1000,
34
+ code: code,
35
+ fallback_value: fallback || default_fallback_value
36
+ }
37
+ }
38
+ end
39
+
40
+ def default_fallback_value
41
+ "#{amount} (#{code})"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ module Resources
5
+ class DateTime < Resource
6
+ attr_accessor :date_time
7
+
8
+ def initialize(date_time = nil, **params)
9
+ super(**params)
10
+
11
+ @date_time = date_time || params[:date_time]
12
+ end
13
+
14
+ def build_template_named_parameter(parameter_name)
15
+ common_date_time_params.merge(parameter_name: parameter_name)
16
+ end
17
+
18
+ def build_template_positional_parameter
19
+ common_date_time_params
20
+ end
21
+
22
+ private
23
+
24
+ def common_date_time_params
25
+ {
26
+ type: "date_time",
27
+ date_time: {
28
+ fallback_value: date_time
29
+ }
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ module Resources
5
+ class Document < Resource
6
+ attr_accessor :media_id, :link, :filename, :caption
7
+
8
+ def build_header
9
+ common_document_params
10
+ end
11
+
12
+ def build_payload
13
+ params = common_document_params
14
+ params[:document][:caption] = caption || @params[:caption]
15
+ params
16
+ end
17
+
18
+ private
19
+
20
+ def common_document_params
21
+ {
22
+ type: "document",
23
+ document: {
24
+ id: media_id || @params[:media_id],
25
+ filename: filename || @params[:filename],
26
+ link: link || @params[:link]
27
+ }
28
+ }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ module Resources
5
+ class Flow < Resource
6
+ attr_accessor :flow_id, :screen
7
+
8
+ def build_payload
9
+ {
10
+ type: "interactive",
11
+ interactive: {
12
+ type: "flow",
13
+ body: {
14
+ text: "Not shown in draft mode"
15
+ },
16
+ action: {
17
+ name: "flow",
18
+ parameters: {
19
+ flow_message_version: "3",
20
+ flow_action: "navigate",
21
+ flow_id: flow_id || @params[:flow_id],
22
+ flow_cta: "Not shown in draft mode",
23
+ mode: "draft",
24
+ flow_action_payload: {
25
+ screen: screen || @params[:screen]
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ module Resources
5
+ class Image < Resource
6
+ attr_accessor :media_id, :link, :caption
7
+
8
+ def build_header
9
+ common_image_params
10
+ end
11
+
12
+ def build_payload
13
+ params = common_image_params
14
+ params[:image][:caption] = caption || @params[:caption]
15
+ params
16
+ end
17
+
18
+ private
19
+
20
+ def common_image_params
21
+ {
22
+ type: "image",
23
+ image: {
24
+ id: media_id || @params[:media_id],
25
+ link: link || @params[:link]
26
+ }
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ module Resources
5
+ class InteractiveCallToActionUrl < Resource
6
+ attr_accessor :header, :body, :footer, :action
7
+
8
+ def build_payload
9
+ {
10
+ type: "interactive",
11
+ interactive: {
12
+ type: "cta_url",
13
+ header: header || @params[:header]&.to_h,
14
+ body: {
15
+ text: body || @params[:body]
16
+ },
17
+ footer: {
18
+ text: footer || @params[:footer]
19
+ },
20
+ action: (action || @params[:action])&.to_h
21
+ }
22
+ }
23
+ end
24
+
25
+ def set_text_header(text)
26
+ @header = Warb::Resources::Text.new(text:).build_header
27
+ end
28
+
29
+ def set_image_header(link: nil)
30
+ @header = Warb::Resources::Image.new(link:).build_header
31
+ end
32
+
33
+ def set_video_header(link: nil)
34
+ @header = Warb::Resources::Video.new(link:).build_header
35
+ end
36
+
37
+ def set_document_header(link: nil, filename: nil)
38
+ @header = Warb::Resources::Document.new(link:, filename:).build_header
39
+ end
40
+
41
+ def build_action(**params, &block)
42
+ @action = Warb::Components::CTAAction.new(**params)
43
+
44
+ block_given? ? @action.tap(&block) : @action
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ module Resources
5
+ class InteractiveList < Resource
6
+ attr_accessor :header, :body, :footer, :action
7
+
8
+ def build_payload
9
+ {
10
+ type: "interactive",
11
+ interactive: {
12
+ type: "list",
13
+ header: header || @params[:header]&.to_h,
14
+ body: {
15
+ text: body || @params[:body]
16
+ },
17
+ footer: {
18
+ text: footer || @params[:footer]
19
+ },
20
+ action: (action || @params[:action])&.to_h
21
+ }
22
+ }
23
+ end
24
+
25
+ def set_text_header(text)
26
+ @header = Warb::Resources::Text.new(text:).build_header
27
+ end
28
+
29
+ def build_action(**params, &block)
30
+ @action = Warb::Components::ListAction.new(**params)
31
+
32
+ block_given? ? @action.tap(&block) : @action
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ module Resources
5
+ class InteractiveReplyButton < Resource
6
+ attr_accessor :header, :body, :footer, :action
7
+
8
+ def build_payload
9
+ {
10
+ type: "interactive",
11
+ interactive: {
12
+ type: "button",
13
+ header: header || @params[:header]&.to_h,
14
+ body: {
15
+ text: body || @params[:body]
16
+ },
17
+ footer: {
18
+ text: footer || @params[:footer]
19
+ },
20
+ action: (action || @params[:action])&.to_h
21
+ }
22
+ }
23
+ end
24
+
25
+ def set_text_header(text)
26
+ @header = Warb::Resources::Text.new(text:).build_header
27
+ end
28
+
29
+ def set_image_header(media_id: nil, link: nil)
30
+ @header = Warb::Resources::Image.new(media_id:, link:).build_header
31
+ end
32
+
33
+ def set_video_header(media_id: nil, link: nil)
34
+ @header = Warb::Resources::Video.new(media_id:, link:).build_header
35
+ end
36
+
37
+ def set_document_header(media_id: nil, link: nil, filename: nil)
38
+ @header = Warb::Resources::Document.new(media_id:, link:, filename:).build_header
39
+ end
40
+
41
+ def build_action(**params, &block)
42
+ @action = Warb::Components::ReplyButtonAction.new(**params)
43
+
44
+ block_given? ? @action.tap(&block) : @action
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ module Resources
5
+ class Location < Resource
6
+ attr_accessor :latitude, :longitude, :name, :address
7
+
8
+ def build_header
9
+ common_location_params
10
+ end
11
+
12
+ def build_payload
13
+ common_location_params
14
+ end
15
+
16
+ private
17
+
18
+ def common_location_params
19
+ {
20
+ type: "location",
21
+ location: {
22
+ latitude: latitude || @params[:latitude],
23
+ longitude: longitude || @params[:longitude],
24
+ name: name || @params[:name],
25
+ address: address || @params[:address]
26
+ }
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ module Resources
5
+ class LocationRequest < Resource
6
+ attr_accessor :body_text
7
+
8
+ def build_payload
9
+ {
10
+ type: "interactive",
11
+ interactive: {
12
+ type: "location_request_message",
13
+ body: {
14
+ text: body_text || @params[:body_text]
15
+ },
16
+ action: {
17
+ name: "send_location"
18
+ }
19
+ }
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Warb
4
+ module Resources
5
+ class Reaction < Resource
6
+ attr_accessor :message_id, :emoji
7
+
8
+ def build_payload
9
+ {
10
+ type: "reaction",
11
+ reaction: {
12
+ message_id: message_id || @params[:message_id],
13
+ emoji: emoji || @params[:emoji]
14
+ }
15
+ }
16
+ end
17
+ end
18
+ end
19
+ end