ruby-whatsapp 0.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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +54 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +15 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +643 -0
- data/Rakefile +12 -0
- data/lib/ruby/whatsapp/client.rb +82 -0
- data/lib/ruby/whatsapp/configuration.rb +79 -0
- data/lib/ruby/whatsapp/instrumentation.rb +34 -0
- data/lib/ruby/whatsapp/media.rb +134 -0
- data/lib/ruby/whatsapp/message_templates/button/base.rb +26 -0
- data/lib/ruby/whatsapp/message_templates/button/copy_code.rb +59 -0
- data/lib/ruby/whatsapp/message_templates/button/otp/supported_app.rb +44 -0
- data/lib/ruby/whatsapp/message_templates/button/otp.rb +138 -0
- data/lib/ruby/whatsapp/message_templates/button/phone_number.rb +45 -0
- data/lib/ruby/whatsapp/message_templates/button/quick_reply.rb +38 -0
- data/lib/ruby/whatsapp/message_templates/button/url.rb +110 -0
- data/lib/ruby/whatsapp/message_templates/button.rb +56 -0
- data/lib/ruby/whatsapp/message_templates/categories.rb +47 -0
- data/lib/ruby/whatsapp/message_templates/component/base.rb +112 -0
- data/lib/ruby/whatsapp/message_templates/component/body.rb +139 -0
- data/lib/ruby/whatsapp/message_templates/component/buttons.rb +95 -0
- data/lib/ruby/whatsapp/message_templates/component/carousel/card.rb +100 -0
- data/lib/ruby/whatsapp/message_templates/component/carousel.rb +71 -0
- data/lib/ruby/whatsapp/message_templates/component/footer.rb +99 -0
- data/lib/ruby/whatsapp/message_templates/component/header.rb +188 -0
- data/lib/ruby/whatsapp/message_templates/component/limited_time_offer.rb +57 -0
- data/lib/ruby/whatsapp/message_templates/component.rb +62 -0
- data/lib/ruby/whatsapp/message_templates/component_set.rb +221 -0
- data/lib/ruby/whatsapp/message_templates/example.rb +148 -0
- data/lib/ruby/whatsapp/message_templates/library_template/body_inputs.rb +81 -0
- data/lib/ruby/whatsapp/message_templates/library_template/button_inputs.rb +146 -0
- data/lib/ruby/whatsapp/message_templates/library_template.rb +114 -0
- data/lib/ruby/whatsapp/message_templates/parameter_formats.rb +49 -0
- data/lib/ruby/whatsapp/message_templates/placeholders.rb +86 -0
- data/lib/ruby/whatsapp/message_templates/response/collection.rb +74 -0
- data/lib/ruby/whatsapp/message_templates/response/created.rb +65 -0
- data/lib/ruby/whatsapp/message_templates/response/node.rb +152 -0
- data/lib/ruby/whatsapp/message_templates/response/paging.rb +39 -0
- data/lib/ruby/whatsapp/message_templates/response/quality_score.rb +49 -0
- data/lib/ruby/whatsapp/message_templates/response/summary.rb +68 -0
- data/lib/ruby/whatsapp/message_templates/response.rb +22 -0
- data/lib/ruby/whatsapp/message_templates/statuses.rb +66 -0
- data/lib/ruby/whatsapp/message_templates/template.rb +180 -0
- data/lib/ruby/whatsapp/message_templates/value_object.rb +62 -0
- data/lib/ruby/whatsapp/message_templates.rb +283 -0
- data/lib/ruby/whatsapp/messages/address.rb +103 -0
- data/lib/ruby/whatsapp/messages/audio.rb +64 -0
- data/lib/ruby/whatsapp/messages/base.rb +46 -0
- data/lib/ruby/whatsapp/messages/contacts/address.rb +84 -0
- data/lib/ruby/whatsapp/messages/contacts/contact.rb +78 -0
- data/lib/ruby/whatsapp/messages/contacts/email.rb +49 -0
- data/lib/ruby/whatsapp/messages/contacts/name.rb +68 -0
- data/lib/ruby/whatsapp/messages/contacts/org.rb +41 -0
- data/lib/ruby/whatsapp/messages/contacts/phone.rb +59 -0
- data/lib/ruby/whatsapp/messages/contacts/url.rb +51 -0
- data/lib/ruby/whatsapp/messages/contacts.rb +37 -0
- data/lib/ruby/whatsapp/messages/document.rb +79 -0
- data/lib/ruby/whatsapp/messages/image.rb +72 -0
- data/lib/ruby/whatsapp/messages/interactive/base.rb +15 -0
- data/lib/ruby/whatsapp/messages/interactive/body.rb +39 -0
- data/lib/ruby/whatsapp/messages/interactive/footer.rb +40 -0
- data/lib/ruby/whatsapp/messages/interactive/header.rb +102 -0
- data/lib/ruby/whatsapp/messages/interactive/list_buttons/section/row.rb +66 -0
- data/lib/ruby/whatsapp/messages/interactive/list_buttons/section.rb +64 -0
- data/lib/ruby/whatsapp/messages/interactive/list_buttons.rb +63 -0
- data/lib/ruby/whatsapp/messages/interactive/media_carousel/card/button/quick_reply.rb +50 -0
- data/lib/ruby/whatsapp/messages/interactive/media_carousel/card/button.rb +47 -0
- data/lib/ruby/whatsapp/messages/interactive/media_carousel/card.rb +78 -0
- data/lib/ruby/whatsapp/messages/interactive/media_carousel.rb +50 -0
- data/lib/ruby/whatsapp/messages/interactive/product_carousel/card.rb +55 -0
- data/lib/ruby/whatsapp/messages/interactive/product_carousel.rb +50 -0
- data/lib/ruby/whatsapp/messages/interactive/reply_buttons/button.rb +59 -0
- data/lib/ruby/whatsapp/messages/interactive/reply_buttons.rb +47 -0
- data/lib/ruby/whatsapp/messages/interactive/url_button.rb +68 -0
- data/lib/ruby/whatsapp/messages/interactive.rb +112 -0
- data/lib/ruby/whatsapp/messages/location.rb +67 -0
- data/lib/ruby/whatsapp/messages/location_request.rb +41 -0
- data/lib/ruby/whatsapp/messages/mark_message_as_read.rb +42 -0
- data/lib/ruby/whatsapp/messages/reaction.rb +61 -0
- data/lib/ruby/whatsapp/messages/response/contacts.rb +36 -0
- data/lib/ruby/whatsapp/messages/response/messages.rb +27 -0
- data/lib/ruby/whatsapp/messages/response.rb +49 -0
- data/lib/ruby/whatsapp/messages/sticker.rb +62 -0
- data/lib/ruby/whatsapp/messages/template/component.rb +67 -0
- data/lib/ruby/whatsapp/messages/template/language.rb +55 -0
- data/lib/ruby/whatsapp/messages/template/parameter.rb +113 -0
- data/lib/ruby/whatsapp/messages/template.rb +62 -0
- data/lib/ruby/whatsapp/messages/text.rb +43 -0
- data/lib/ruby/whatsapp/messages/video.rb +68 -0
- data/lib/ruby/whatsapp/messages.rb +116 -0
- data/lib/ruby/whatsapp/railtie.rb +14 -0
- data/lib/ruby/whatsapp/request_error.rb +5 -0
- data/lib/ruby/whatsapp/response_handling.rb +44 -0
- data/lib/ruby/whatsapp/utils/language_codes.rb +96 -0
- data/lib/ruby/whatsapp/version.rb +5 -0
- data/lib/ruby/whatsapp/webhook/account_alerts.rb +58 -0
- data/lib/ruby/whatsapp/webhook/account_review_update.rb +27 -0
- data/lib/ruby/whatsapp/webhook/account_update/ban_info.rb +33 -0
- data/lib/ruby/whatsapp/webhook/account_update.rb +46 -0
- data/lib/ruby/whatsapp/webhook/automatic_events.rb +43 -0
- data/lib/ruby/whatsapp/webhook/business_capability_update.rb +36 -0
- data/lib/ruby/whatsapp/webhook/change.rb +61 -0
- data/lib/ruby/whatsapp/webhook/contact.rb +36 -0
- data/lib/ruby/whatsapp/webhook/entry.rb +35 -0
- data/lib/ruby/whatsapp/webhook/error.rb +47 -0
- data/lib/ruby/whatsapp/webhook/history.rb +54 -0
- data/lib/ruby/whatsapp/webhook/installer.rb +61 -0
- data/lib/ruby/whatsapp/webhook/message/audio.rb +28 -0
- data/lib/ruby/whatsapp/webhook/message/base.rb +61 -0
- data/lib/ruby/whatsapp/webhook/message/button.rb +33 -0
- data/lib/ruby/whatsapp/webhook/message/contacts/address.rb +68 -0
- data/lib/ruby/whatsapp/webhook/message/contacts/contact.rb +68 -0
- data/lib/ruby/whatsapp/webhook/message/contacts/email.rb +35 -0
- data/lib/ruby/whatsapp/webhook/message/contacts/name.rb +62 -0
- data/lib/ruby/whatsapp/webhook/message/contacts/org.rb +40 -0
- data/lib/ruby/whatsapp/webhook/message/contacts/phone.rb +40 -0
- data/lib/ruby/whatsapp/webhook/message/contacts/url.rb +35 -0
- data/lib/ruby/whatsapp/webhook/message/contacts.rb +31 -0
- data/lib/ruby/whatsapp/webhook/message/context.rb +49 -0
- data/lib/ruby/whatsapp/webhook/message/document.rb +32 -0
- data/lib/ruby/whatsapp/webhook/message/image.rb +18 -0
- data/lib/ruby/whatsapp/webhook/message/interactive.rb +53 -0
- data/lib/ruby/whatsapp/webhook/message/location.rb +49 -0
- data/lib/ruby/whatsapp/webhook/message/media.rb +54 -0
- data/lib/ruby/whatsapp/webhook/message/order/product_item.rb +50 -0
- data/lib/ruby/whatsapp/webhook/message/order.rb +43 -0
- data/lib/ruby/whatsapp/webhook/message/reaction.rb +37 -0
- data/lib/ruby/whatsapp/webhook/message/referral.rb +80 -0
- data/lib/ruby/whatsapp/webhook/message/sticker.rb +32 -0
- data/lib/ruby/whatsapp/webhook/message/system.rb +49 -0
- data/lib/ruby/whatsapp/webhook/message/text.rb +28 -0
- data/lib/ruby/whatsapp/webhook/message/unknown.rb +39 -0
- data/lib/ruby/whatsapp/webhook/message/video.rb +18 -0
- data/lib/ruby/whatsapp/webhook/message.rb +39 -0
- data/lib/ruby/whatsapp/webhook/message_template_components_update.rb +53 -0
- data/lib/ruby/whatsapp/webhook/message_template_quality_update.rb +59 -0
- data/lib/ruby/whatsapp/webhook/message_template_status_update.rb +54 -0
- data/lib/ruby/whatsapp/webhook/messages.rb +55 -0
- data/lib/ruby/whatsapp/webhook/metadata.rb +35 -0
- data/lib/ruby/whatsapp/webhook/notification.rb +36 -0
- data/lib/ruby/whatsapp/webhook/partner_solutions.rb +36 -0
- data/lib/ruby/whatsapp/webhook/payment_configuration_update.rb +51 -0
- data/lib/ruby/whatsapp/webhook/phone_number_name_update.rb +51 -0
- data/lib/ruby/whatsapp/webhook/phone_number_quality_update.rb +45 -0
- data/lib/ruby/whatsapp/webhook/security.rb +41 -0
- data/lib/ruby/whatsapp/webhook/signature.rb +28 -0
- data/lib/ruby/whatsapp/webhook/smb_app_state_sync/state_sync.rb +38 -0
- data/lib/ruby/whatsapp/webhook/smb_app_state_sync.rb +33 -0
- data/lib/ruby/whatsapp/webhook/smb_message_echoes.rb +48 -0
- data/lib/ruby/whatsapp/webhook/status/conversation.rb +42 -0
- data/lib/ruby/whatsapp/webhook/status/pricing.rb +38 -0
- data/lib/ruby/whatsapp/webhook/status.rb +65 -0
- data/lib/ruby/whatsapp/webhook/template_category_update.rb +64 -0
- data/lib/ruby/whatsapp/webhook/templates/webhooks_controller.rb.tt +31 -0
- data/lib/ruby/whatsapp/webhook/unknown_field.rb +37 -0
- data/lib/ruby/whatsapp/webhook/user_preferences.rb +47 -0
- data/lib/ruby/whatsapp/webhook/verification.rb +27 -0
- data/lib/ruby/whatsapp/webhook.rb +8 -0
- data/lib/ruby/whatsapp.rb +49 -0
- data/lib/tasks/whatsapp.rake +10 -0
- data/sig/ruby/whatsapp.rbs +6 -0
- metadata +267 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Interactive
|
|
6
|
+
class ProductCarousel < Base
|
|
7
|
+
module Defaults
|
|
8
|
+
MIN_CARDS_COUNT = 2
|
|
9
|
+
MAX_CARDS_COUNT = 10
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @!attribute [rw] cards
|
|
13
|
+
# @return [Array<Hash>]
|
|
14
|
+
attr_accessor :cards
|
|
15
|
+
|
|
16
|
+
validates :cards, presence: true, length: { minimum: Defaults::MIN_CARDS_COUNT,
|
|
17
|
+
maximum: Defaults::MAX_CARDS_COUNT, }
|
|
18
|
+
|
|
19
|
+
# @param cards [Array<Hash>] The cards of the product carousel.
|
|
20
|
+
def initialize(cards:)
|
|
21
|
+
@cards = cards
|
|
22
|
+
|
|
23
|
+
validate!
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class << self
|
|
27
|
+
# @return [Hash] Serialized representation of the ProductCarousel.
|
|
28
|
+
def serialize(cards:)
|
|
29
|
+
new(cards:).serialize
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [Hash] Serialized representation of the ProductCarousel.
|
|
34
|
+
def serialize
|
|
35
|
+
{
|
|
36
|
+
cards: serialized_cards,
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
# @return [Array<Hash>] Serialized cards.
|
|
43
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
44
|
+
def serialized_cards
|
|
45
|
+
cards.map.with_index { |card, index| Card.serialize(card_index: index, **card) }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Interactive
|
|
6
|
+
class ReplyButtons
|
|
7
|
+
class Button
|
|
8
|
+
include ActiveModel::Validations
|
|
9
|
+
|
|
10
|
+
module Defaults
|
|
11
|
+
TYPE = "reply"
|
|
12
|
+
MAX_ID_LENGTH = 256
|
|
13
|
+
MAX_TITLE_LENGTH = 20
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @!attribute [rw] id
|
|
17
|
+
# @return [String]
|
|
18
|
+
attr_accessor :id
|
|
19
|
+
|
|
20
|
+
# @!attribute [rw] title
|
|
21
|
+
# @return [String]
|
|
22
|
+
attr_accessor :title
|
|
23
|
+
|
|
24
|
+
validates :id, presence: true, length: { maximum: Defaults::MAX_ID_LENGTH }
|
|
25
|
+
validates :title, presence: true, length: { maximum: Defaults::MAX_TITLE_LENGTH }
|
|
26
|
+
|
|
27
|
+
# @param id [String] The ID of the button.
|
|
28
|
+
# @param title [String] The title of the button.
|
|
29
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
30
|
+
def initialize(id:, title:)
|
|
31
|
+
@id = id
|
|
32
|
+
@title = title
|
|
33
|
+
|
|
34
|
+
validate!
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class << self
|
|
38
|
+
# @return [Hash] Serialized representation of the Button.
|
|
39
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
40
|
+
def serialize(id:, title:)
|
|
41
|
+
new(id:, title:).serialize
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @return [Hash] Serialized representation of the Button.
|
|
46
|
+
def serialize
|
|
47
|
+
{
|
|
48
|
+
type: Defaults::TYPE,
|
|
49
|
+
reply: {
|
|
50
|
+
id:,
|
|
51
|
+
title:,
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Interactive
|
|
6
|
+
class ReplyButtons < Base
|
|
7
|
+
module Defaults
|
|
8
|
+
MAX_BUTTONS = 3
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @!attribute [rw] buttons
|
|
12
|
+
# @return [Array<Hash>]
|
|
13
|
+
attr_accessor :buttons
|
|
14
|
+
|
|
15
|
+
validates :buttons, presence: true, length: { maximum: Defaults::MAX_BUTTONS }
|
|
16
|
+
|
|
17
|
+
# @param buttons [Array<Hash>] The buttons of the reply buttons.
|
|
18
|
+
def initialize(buttons:)
|
|
19
|
+
@buttons = buttons
|
|
20
|
+
|
|
21
|
+
validate!
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class << self
|
|
25
|
+
# @return [Hash] Serialized representation of the ReplyButtons.
|
|
26
|
+
def serialize(buttons:)
|
|
27
|
+
new(buttons:).serialize
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @return [Hash] Serialized representation of the ReplyButtons.
|
|
32
|
+
def serialize
|
|
33
|
+
{
|
|
34
|
+
buttons: serialized_buttons,
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
# @return [Array<Hash>] Serialized buttons.
|
|
41
|
+
def serialized_buttons
|
|
42
|
+
buttons.map { |button| Button.serialize(**button) }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Interactive
|
|
6
|
+
# Interactive call-to-action (CTA) URL button message. Maps a URL to a
|
|
7
|
+
# button so the raw URL does not have to appear in the message body.
|
|
8
|
+
# Source: https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/interactive-cta-url-messages
|
|
9
|
+
class UrlButton < Base
|
|
10
|
+
module Defaults
|
|
11
|
+
MAX_NAME_LENGTH = 20
|
|
12
|
+
MAX_DISPLAY_TEXT_LENGTH = 20
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @!attribute [rw] name
|
|
16
|
+
# @return [String]
|
|
17
|
+
attr_accessor :name
|
|
18
|
+
|
|
19
|
+
# @!attribute [rw] display_text
|
|
20
|
+
# @return [String]
|
|
21
|
+
attr_accessor :display_text
|
|
22
|
+
|
|
23
|
+
# @!attribute [rw] url
|
|
24
|
+
# @return [String]
|
|
25
|
+
attr_accessor :url
|
|
26
|
+
|
|
27
|
+
validates :name, presence: true, length: { maximum: Defaults::MAX_NAME_LENGTH }
|
|
28
|
+
validates :display_text, presence: true, length: { maximum: Defaults::MAX_DISPLAY_TEXT_LENGTH }
|
|
29
|
+
|
|
30
|
+
# @param name [String] The name of the URL button.
|
|
31
|
+
# @param display_text [String] The text displayed on the button.
|
|
32
|
+
# @param url [String] The URL that the button links to.
|
|
33
|
+
def initialize(name:, display_text:, url:)
|
|
34
|
+
@name = name
|
|
35
|
+
@display_text = display_text
|
|
36
|
+
@url = url
|
|
37
|
+
|
|
38
|
+
validate!
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class << self
|
|
42
|
+
# @return [Hash] Serialized representation of the URL button.
|
|
43
|
+
def serialize(**url_button)
|
|
44
|
+
new(**url_button).serialize
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [Hash] Serialized representation of the URL button.
|
|
49
|
+
def serialize
|
|
50
|
+
{
|
|
51
|
+
name:,
|
|
52
|
+
parameters:,
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
# @return [Hash] Serialized parameters for the URL button.
|
|
59
|
+
def parameters
|
|
60
|
+
{
|
|
61
|
+
display_text:,
|
|
62
|
+
url:,
|
|
63
|
+
}.compact
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Interactive < Base
|
|
6
|
+
module Defaults
|
|
7
|
+
TYPE = "interactive"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Maps a public action kind to its implementing class and the WhatsApp
|
|
11
|
+
# `interactive.type` value emitted in the payload. Resolution goes through
|
|
12
|
+
# this frozen whitelist — never `const_get` on caller input.
|
|
13
|
+
#
|
|
14
|
+
# NOTE: the carousel `api_type` values ("carousel"/"product_list") should be
|
|
15
|
+
# verified against the Meta docs for your API version before relying on them.
|
|
16
|
+
ACTION_TYPES = {
|
|
17
|
+
reply_buttons: { klass: ReplyButtons, api_type: "button" },
|
|
18
|
+
list_buttons: { klass: ListButtons, api_type: "list" },
|
|
19
|
+
url_button: { klass: UrlButton, api_type: "cta_url" },
|
|
20
|
+
media_carousel: { klass: MediaCarousel, api_type: "carousel" },
|
|
21
|
+
product_carousel: { klass: ProductCarousel, api_type: "product_list" },
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
# @!attribute [rw] type
|
|
25
|
+
# @return [Symbol] The action kind (e.g. :reply_buttons, :list_buttons).
|
|
26
|
+
attr_accessor :type
|
|
27
|
+
|
|
28
|
+
# @!attribute [rw] header
|
|
29
|
+
# @return [Hash, nil]
|
|
30
|
+
attr_accessor :header
|
|
31
|
+
|
|
32
|
+
# @!attribute [rw] body
|
|
33
|
+
# @return [String]
|
|
34
|
+
attr_accessor :body
|
|
35
|
+
|
|
36
|
+
# @!attribute [rw] footer
|
|
37
|
+
# @return [Hash, nil]
|
|
38
|
+
attr_accessor :footer
|
|
39
|
+
|
|
40
|
+
# @!attribute [rw] action
|
|
41
|
+
# @return [Hash]
|
|
42
|
+
attr_accessor :action
|
|
43
|
+
|
|
44
|
+
validates :type, presence: true, inclusion: { in: ACTION_TYPES.keys }
|
|
45
|
+
validates :body, presence: true
|
|
46
|
+
validates :action, presence: true
|
|
47
|
+
|
|
48
|
+
# @param type [Symbol, String] The action kind (see {ACTION_TYPES}).
|
|
49
|
+
# @param body [String] The body text of the interactive message.
|
|
50
|
+
# @param action [Hash] The action content, forwarded to the action class.
|
|
51
|
+
# @param header [Hash, nil] The header content (optional).
|
|
52
|
+
# @param footer [Hash, nil] The footer content (optional).
|
|
53
|
+
# @param kwargs [Hash] Additional keyword arguments (e.g. :to).
|
|
54
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
55
|
+
def initialize(type:, body:, action:, header: nil, footer: nil, **)
|
|
56
|
+
super(**)
|
|
57
|
+
|
|
58
|
+
@type = type.to_sym
|
|
59
|
+
@body = body
|
|
60
|
+
@action = action
|
|
61
|
+
@header = header
|
|
62
|
+
@footer = footer
|
|
63
|
+
|
|
64
|
+
validate!
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @return [Hash] Serialized representation of the Interactive message.
|
|
68
|
+
def serialize
|
|
69
|
+
envelope(type: Defaults::TYPE, interactive: interactive_payload)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
# @return [Hash] The serialized `interactive` payload.
|
|
75
|
+
def interactive_payload
|
|
76
|
+
{
|
|
77
|
+
type: action_config[:api_type],
|
|
78
|
+
header: serialized_header,
|
|
79
|
+
body: serialized_body,
|
|
80
|
+
footer: serialized_footer,
|
|
81
|
+
action: action_config[:klass].serialize(**action),
|
|
82
|
+
}.compact
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# @return [Hash] The registry entry for the current action kind.
|
|
86
|
+
def action_config
|
|
87
|
+
ACTION_TYPES.fetch(type)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# @return [Hash, nil] The serialized header information.
|
|
91
|
+
def serialized_header
|
|
92
|
+
return unless header
|
|
93
|
+
|
|
94
|
+
Header.serialize(**header)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @return [Hash, nil] The serialized footer information.
|
|
98
|
+
def serialized_footer
|
|
99
|
+
return unless footer
|
|
100
|
+
|
|
101
|
+
Footer.serialize(**footer)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# @return [Hash, nil] The serialized body information.
|
|
105
|
+
def serialized_body
|
|
106
|
+
return unless body
|
|
107
|
+
|
|
108
|
+
Body.serialize(body)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
# Location messages allow you to send a location's latitude and longitude coordinates to a WhatsApp user.
|
|
6
|
+
# Source: https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/location-messages
|
|
7
|
+
class Location < Base
|
|
8
|
+
module Defaults
|
|
9
|
+
TYPE = "location"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @!attribute [rw] latitude
|
|
13
|
+
# @return [Float]
|
|
14
|
+
attr_accessor :latitude
|
|
15
|
+
|
|
16
|
+
# @!attribute [rw] longitude
|
|
17
|
+
# @return [Float]
|
|
18
|
+
attr_accessor :longitude
|
|
19
|
+
|
|
20
|
+
# @!attribute [rw] name
|
|
21
|
+
# @return [String, nil]
|
|
22
|
+
attr_accessor :name
|
|
23
|
+
|
|
24
|
+
# @!attribute [rw] address
|
|
25
|
+
# @return [String, nil]
|
|
26
|
+
attr_accessor :address
|
|
27
|
+
|
|
28
|
+
validates :latitude, presence: true, numericality: true
|
|
29
|
+
validates :longitude, presence: true, numericality: true
|
|
30
|
+
|
|
31
|
+
# @param latitude [Float] The latitude of the location.
|
|
32
|
+
# @param longitude [Float] The longitude of the location.
|
|
33
|
+
# @param name [String, nil] The name of the location.
|
|
34
|
+
# @param address [String, nil] The address of the location.
|
|
35
|
+
# @param kwargs [Hash] Additional keyword arguments (e.g. :to).
|
|
36
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
37
|
+
def initialize(latitude:, longitude:, name: nil, address: nil, **)
|
|
38
|
+
super(**)
|
|
39
|
+
|
|
40
|
+
@latitude = latitude
|
|
41
|
+
@longitude = longitude
|
|
42
|
+
@name = name
|
|
43
|
+
@address = address
|
|
44
|
+
|
|
45
|
+
validate!
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Serializes the location message to a hash format suitable for the WhatsApp API.
|
|
49
|
+
# @return [Hash] The serialized location message.
|
|
50
|
+
def serialize
|
|
51
|
+
envelope(type: Defaults::TYPE, location: location_payload)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
# @return [Hash] The serialized location information.
|
|
57
|
+
def location_payload
|
|
58
|
+
{
|
|
59
|
+
latitude:,
|
|
60
|
+
longitude:,
|
|
61
|
+
name:,
|
|
62
|
+
address:,
|
|
63
|
+
}.compact
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class LocationRequest < Base
|
|
6
|
+
module Defaults
|
|
7
|
+
TYPE = "interactive"
|
|
8
|
+
INTERACTIVE_TYPE = "location_request_message"
|
|
9
|
+
ACTION_NAME = "send_location"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @!attribute [rw] body
|
|
13
|
+
# @return [Hash]
|
|
14
|
+
attr_accessor :body
|
|
15
|
+
|
|
16
|
+
validates :body, presence: true, length: { maximum: 1024 }
|
|
17
|
+
|
|
18
|
+
# @param body [String] The body text of the location request message.
|
|
19
|
+
# @param kwargs [Hash] Additional keyword arguments.
|
|
20
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
21
|
+
def initialize(body:, **)
|
|
22
|
+
super(**)
|
|
23
|
+
|
|
24
|
+
@body = body
|
|
25
|
+
|
|
26
|
+
validate!
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def serialize
|
|
30
|
+
envelope(
|
|
31
|
+
type: Defaults::TYPE,
|
|
32
|
+
interactive: {
|
|
33
|
+
type: Defaults::INTERACTIVE_TYPE,
|
|
34
|
+
body:,
|
|
35
|
+
action: { name: Defaults::ACTION_NAME },
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
# Marks a previously received message (and every earlier message in the
|
|
6
|
+
# conversation) as read. Unlike every other message class, this has no
|
|
7
|
+
# recipient or type envelope — it targets an existing message by ID.
|
|
8
|
+
# Meta requires this within 30 days of receipt.
|
|
9
|
+
# Source: https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/mark-message-as-read
|
|
10
|
+
class MarkMessageAsRead
|
|
11
|
+
include ActiveModel::Validations
|
|
12
|
+
|
|
13
|
+
module Defaults
|
|
14
|
+
MESSAGING_PRODUCT = "whatsapp"
|
|
15
|
+
STATUS = "read"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @!attribute [rw] message_id
|
|
19
|
+
# @return [String]
|
|
20
|
+
attr_accessor :message_id
|
|
21
|
+
|
|
22
|
+
validates :message_id, presence: true
|
|
23
|
+
|
|
24
|
+
# @param message_id [String] The WhatsApp message ID (WAMID) to mark as read.
|
|
25
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
26
|
+
def initialize(message_id:)
|
|
27
|
+
@message_id = message_id
|
|
28
|
+
|
|
29
|
+
validate!
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @return [Hash] Serialized representation for the WhatsApp API.
|
|
33
|
+
def serialize
|
|
34
|
+
{
|
|
35
|
+
messaging_product: Defaults::MESSAGING_PRODUCT,
|
|
36
|
+
status: Defaults::STATUS,
|
|
37
|
+
message_id:,
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
# Reaction messages are emoji-reactions applied to a WhatsApp message you have received.
|
|
6
|
+
# Source: https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/reaction-messages
|
|
7
|
+
class Reaction < Base
|
|
8
|
+
module Defaults
|
|
9
|
+
TYPE = "reaction"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @!attribute [rw] message_id
|
|
13
|
+
# @return [String]
|
|
14
|
+
attr_accessor :message_id
|
|
15
|
+
|
|
16
|
+
# @!attribute [rw] emoji
|
|
17
|
+
# @return [String]
|
|
18
|
+
attr_accessor :emoji
|
|
19
|
+
|
|
20
|
+
validates :message_id, presence: true
|
|
21
|
+
validate :emoji_unicode
|
|
22
|
+
|
|
23
|
+
# @param message_id [String] The ID of the message being reacted to.
|
|
24
|
+
# @param emoji [String] The emoji used for the reaction.
|
|
25
|
+
# @param kwargs [Hash] Additional keyword arguments.
|
|
26
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
27
|
+
def initialize(message_id:, emoji:, **)
|
|
28
|
+
super(**)
|
|
29
|
+
|
|
30
|
+
@message_id = message_id
|
|
31
|
+
@emoji = emoji
|
|
32
|
+
|
|
33
|
+
validate!
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Serializes the reaction message to a hash format suitable for the WhatsApp API.
|
|
37
|
+
# @return [Hash] The serialized reaction message.
|
|
38
|
+
def serialize
|
|
39
|
+
envelope(type: Defaults::TYPE, reaction: { message_id:, emoji: })
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# Validates that the emoji is a valid Unicode emoji character.
|
|
45
|
+
# @return [void]
|
|
46
|
+
# @raise [ActiveModel::ValidationError] if the emoji is not valid.
|
|
47
|
+
def emoji_unicode
|
|
48
|
+
if @emoji.nil?
|
|
49
|
+
errors.add(:emoji, "can't be nil")
|
|
50
|
+
return
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# An empty string is valid: it removes a previously sent reaction.
|
|
54
|
+
return if @emoji.empty?
|
|
55
|
+
return if @emoji.match?(/\p{Emoji}/)
|
|
56
|
+
|
|
57
|
+
errors.add(:emoji, "must be a valid emoji character")
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Response
|
|
6
|
+
class Contacts
|
|
7
|
+
# @!attribute [rw] input
|
|
8
|
+
# @return [String]
|
|
9
|
+
attr_accessor :input
|
|
10
|
+
|
|
11
|
+
# @!attribute [rw] wa_id
|
|
12
|
+
# @return [String]
|
|
13
|
+
attr_accessor :wa_id
|
|
14
|
+
|
|
15
|
+
# @param input [String] The input value of the contact.
|
|
16
|
+
# @param wa_id [String] The WhatsApp ID of the contact.
|
|
17
|
+
def initialize(input:, wa_id:)
|
|
18
|
+
@input = input
|
|
19
|
+
@wa_id = wa_id
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
# Deserializes a hash into a Messages::Response::Contacts object.
|
|
24
|
+
# @param data [Hash] The hash representation of the contact response.
|
|
25
|
+
# @return [Messages::Response::Contacts] The deserialized contact response object.
|
|
26
|
+
def deserialize(data)
|
|
27
|
+
new(
|
|
28
|
+
input: data["input"],
|
|
29
|
+
wa_id: data["wa_id"]
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Response
|
|
6
|
+
class Messages
|
|
7
|
+
# @!attribute [rw] id
|
|
8
|
+
# @return [String]
|
|
9
|
+
attr_accessor :id
|
|
10
|
+
|
|
11
|
+
# @param id [String] The unique identifier of the message.
|
|
12
|
+
def initialize(id:)
|
|
13
|
+
@id = id
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
# Deserializes a hash into a Messages::Response::Messages object.
|
|
18
|
+
# @param data [Hash] The hash representation of the message response.
|
|
19
|
+
# @return [Messages::Response::Messages] The deserialized message response object.
|
|
20
|
+
def deserialize(data)
|
|
21
|
+
new(id: data["id"])
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Response
|
|
6
|
+
# @!attribute [rw] messaging_product
|
|
7
|
+
# @return [String]
|
|
8
|
+
attr_accessor :messaging_product
|
|
9
|
+
|
|
10
|
+
# @!attribute [rw] contacts
|
|
11
|
+
# @return [Array<Contacts>]
|
|
12
|
+
attr_accessor :contacts
|
|
13
|
+
|
|
14
|
+
# @!attribute [rw] messages
|
|
15
|
+
# @return [Array<Messages>]
|
|
16
|
+
attr_accessor :messages
|
|
17
|
+
|
|
18
|
+
# @!attribute [rw] success
|
|
19
|
+
# @return [Boolean, nil] Present on status-update responses (e.g. mark-message-as-read);
|
|
20
|
+
# nil on normal message-send responses.
|
|
21
|
+
attr_accessor :success
|
|
22
|
+
|
|
23
|
+
# @param messaging_product [String] The messaging product used (e.g., "whatsapp").
|
|
24
|
+
# @param contacts [Array<Contacts>] The list of contact responses.
|
|
25
|
+
# @param messages [Array<Messages>] The list of message responses.
|
|
26
|
+
# @param success [Boolean, nil] The status-update success flag, if present.
|
|
27
|
+
def initialize(messaging_product:, contacts:, messages:, success: nil)
|
|
28
|
+
@messaging_product = messaging_product
|
|
29
|
+
@contacts = contacts
|
|
30
|
+
@messages = messages
|
|
31
|
+
@success = success
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class << self
|
|
35
|
+
# Deserializes a hash into a Messages::Response object.
|
|
36
|
+
# @param data [Hash] The hash representation of the message response.
|
|
37
|
+
# @return [Messages::Response] The deserialized message response object.
|
|
38
|
+
def deserialize(data)
|
|
39
|
+
new(
|
|
40
|
+
messaging_product: data["messaging_product"],
|
|
41
|
+
contacts: Array(data["contacts"]).map { |contact_data| Contacts.deserialize(contact_data) },
|
|
42
|
+
messages: Array(data["messages"]).map { |message_data| Messages.deserialize(message_data) },
|
|
43
|
+
success: data["success"]
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|