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,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Base
|
|
6
|
+
include ActiveModel::Validations
|
|
7
|
+
|
|
8
|
+
module Messaging
|
|
9
|
+
PRODUCT = "whatsapp"
|
|
10
|
+
RECIPIENT_TYPE = "individual"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @!attribute [rw] to
|
|
14
|
+
# @return [String]
|
|
15
|
+
attr_accessor :to
|
|
16
|
+
|
|
17
|
+
validates :to, presence: true
|
|
18
|
+
|
|
19
|
+
# @param to [String] The recipient's phone number.
|
|
20
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
21
|
+
def initialize(to:)
|
|
22
|
+
@to = to
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def serialize
|
|
26
|
+
raise NotImplementedError, "Subclasses must implement the serialize method"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
protected
|
|
30
|
+
|
|
31
|
+
# Builds the common message envelope shared by all message types.
|
|
32
|
+
# @param type [String] the WhatsApp message type (e.g. "text")
|
|
33
|
+
# @param body [Hash] the type-specific payload merged into the envelope
|
|
34
|
+
# @return [Hash]
|
|
35
|
+
def envelope(type:, **body)
|
|
36
|
+
{
|
|
37
|
+
messaging_product: Messaging::PRODUCT,
|
|
38
|
+
recipient_type: Messaging::RECIPIENT_TYPE,
|
|
39
|
+
to:,
|
|
40
|
+
type:,
|
|
41
|
+
**body,
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Contacts
|
|
6
|
+
# Represents a physical address entry in a contact message.
|
|
7
|
+
# All fields are optional.
|
|
8
|
+
class Address
|
|
9
|
+
include ActiveModel::Validations
|
|
10
|
+
|
|
11
|
+
module Types
|
|
12
|
+
HOME = "HOME"
|
|
13
|
+
WORK = "WORK"
|
|
14
|
+
OTHER = "OTHER"
|
|
15
|
+
|
|
16
|
+
ALL = [HOME, WORK, OTHER].freeze
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @!attribute [rw] street
|
|
20
|
+
# @return [String, nil]
|
|
21
|
+
attr_accessor :street
|
|
22
|
+
|
|
23
|
+
# @!attribute [rw] city
|
|
24
|
+
# @return [String, nil]
|
|
25
|
+
attr_accessor :city
|
|
26
|
+
|
|
27
|
+
# @!attribute [rw] state
|
|
28
|
+
# @return [String, nil]
|
|
29
|
+
attr_accessor :state
|
|
30
|
+
|
|
31
|
+
# @!attribute [rw] zip
|
|
32
|
+
# @return [String, nil]
|
|
33
|
+
attr_accessor :zip
|
|
34
|
+
|
|
35
|
+
# @!attribute [rw] country
|
|
36
|
+
# @return [String, nil]
|
|
37
|
+
attr_accessor :country
|
|
38
|
+
|
|
39
|
+
# @!attribute [rw] country_code
|
|
40
|
+
# @return [String, nil]
|
|
41
|
+
attr_accessor :country_code
|
|
42
|
+
|
|
43
|
+
# @!attribute [rw] type
|
|
44
|
+
# @return [String, nil]
|
|
45
|
+
attr_accessor :type
|
|
46
|
+
|
|
47
|
+
validates :type, inclusion: { in: Types::ALL }, allow_nil: true
|
|
48
|
+
|
|
49
|
+
# @param street [String, nil]
|
|
50
|
+
# @param city [String, nil]
|
|
51
|
+
# @param state [String, nil]
|
|
52
|
+
# @param zip [String, nil]
|
|
53
|
+
# @param country [String, nil]
|
|
54
|
+
# @param country_code [String, nil] ISO 3166-1 alpha-2 code (e.g. "US").
|
|
55
|
+
# @param type [String, nil] Address type. One of HOME, WORK, OTHER.
|
|
56
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
57
|
+
def initialize(street: nil, city: nil, state: nil, zip: nil, country: nil, country_code: nil, type: nil)
|
|
58
|
+
@street = street
|
|
59
|
+
@city = city
|
|
60
|
+
@state = state
|
|
61
|
+
@zip = zip
|
|
62
|
+
@country = country
|
|
63
|
+
@country_code = country_code
|
|
64
|
+
@type = type
|
|
65
|
+
|
|
66
|
+
validate!
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @return [Hash] The serialized address payload.
|
|
70
|
+
def serialize
|
|
71
|
+
{
|
|
72
|
+
street:,
|
|
73
|
+
city:,
|
|
74
|
+
state:,
|
|
75
|
+
zip:,
|
|
76
|
+
country:,
|
|
77
|
+
country_code:,
|
|
78
|
+
type:,
|
|
79
|
+
}.compact
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Contacts
|
|
6
|
+
# Represents a single contact entry within a contacts message.
|
|
7
|
+
class Contact
|
|
8
|
+
include ActiveModel::Validations
|
|
9
|
+
|
|
10
|
+
# @!attribute [rw] name
|
|
11
|
+
# @return [Name]
|
|
12
|
+
attr_accessor :name
|
|
13
|
+
|
|
14
|
+
# @!attribute [rw] phones
|
|
15
|
+
# @return [Array<Phone>]
|
|
16
|
+
attr_accessor :phones
|
|
17
|
+
|
|
18
|
+
# @!attribute [rw] emails
|
|
19
|
+
# @return [Array<Email>]
|
|
20
|
+
attr_accessor :emails
|
|
21
|
+
|
|
22
|
+
# @!attribute [rw] addresses
|
|
23
|
+
# @return [Array<Address>]
|
|
24
|
+
attr_accessor :addresses
|
|
25
|
+
|
|
26
|
+
# @!attribute [rw] org
|
|
27
|
+
# @return [Org, nil]
|
|
28
|
+
attr_accessor :org
|
|
29
|
+
|
|
30
|
+
# @!attribute [rw] urls
|
|
31
|
+
# @return [Array<Url>]
|
|
32
|
+
attr_accessor :urls
|
|
33
|
+
|
|
34
|
+
# @!attribute [rw] birthday
|
|
35
|
+
# @return [String, nil] Date in YYYY-MM-DD format.
|
|
36
|
+
attr_accessor :birthday
|
|
37
|
+
|
|
38
|
+
validates :name, presence: true
|
|
39
|
+
|
|
40
|
+
# @param name [Hash, Name] The contact's name. formatted_name is required.
|
|
41
|
+
# @param phones [Array<Hash, Phone>] Phone numbers.
|
|
42
|
+
# @param emails [Array<Hash, Email>] Email addresses.
|
|
43
|
+
# @param addresses [Array<Hash, Address>] Physical addresses.
|
|
44
|
+
# @param org [Hash, Org, nil] Organization details.
|
|
45
|
+
# @param urls [Array<Hash, Url>] URLs.
|
|
46
|
+
# @param birthday [String, nil] Birthday in YYYY-MM-DD format.
|
|
47
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
48
|
+
def initialize(name:, phones: [], emails: [], addresses: [], org: nil, urls: [], birthday: nil)
|
|
49
|
+
@name = name.is_a?(Name) ? name : Name.new(**name)
|
|
50
|
+
@phones = phones.map { |p| p.is_a?(Phone) ? p : Phone.new(**p) }
|
|
51
|
+
@emails = emails.map { |e| e.is_a?(Email) ? e : Email.new(**e) }
|
|
52
|
+
@addresses = addresses.map { |a| a.is_a?(Address) ? a : Address.new(**a) }
|
|
53
|
+
@org = if org
|
|
54
|
+
org.is_a?(Org) ? org : Org.new(**org)
|
|
55
|
+
end
|
|
56
|
+
@urls = urls.map { |u| u.is_a?(Url) ? u : Url.new(**u) }
|
|
57
|
+
@birthday = birthday
|
|
58
|
+
|
|
59
|
+
validate!
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @return [Hash] The serialized contact payload.
|
|
63
|
+
def serialize
|
|
64
|
+
payload = { name: name.serialize }
|
|
65
|
+
|
|
66
|
+
payload[:phones] = phones.map(&:serialize) if phones.any?
|
|
67
|
+
payload[:emails] = emails.map(&:serialize) if emails.any?
|
|
68
|
+
payload[:addresses] = addresses.map(&:serialize) if addresses.any?
|
|
69
|
+
payload[:org] = org.serialize if org
|
|
70
|
+
payload[:urls] = urls.map(&:serialize) if urls.any?
|
|
71
|
+
payload[:birthday] = birthday if birthday
|
|
72
|
+
|
|
73
|
+
payload
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Contacts
|
|
6
|
+
# Represents an email entry in a contact message.
|
|
7
|
+
class Email
|
|
8
|
+
include ActiveModel::Validations
|
|
9
|
+
|
|
10
|
+
module Types
|
|
11
|
+
HOME = "HOME"
|
|
12
|
+
WORK = "WORK"
|
|
13
|
+
OTHER = "OTHER"
|
|
14
|
+
|
|
15
|
+
ALL = [HOME, WORK, OTHER].freeze
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @!attribute [rw] email
|
|
19
|
+
# @return [String]
|
|
20
|
+
attr_accessor :email
|
|
21
|
+
|
|
22
|
+
# @!attribute [rw] type
|
|
23
|
+
# @return [String, nil]
|
|
24
|
+
attr_accessor :type
|
|
25
|
+
|
|
26
|
+
validates :email, presence: true
|
|
27
|
+
validates :type, inclusion: { in: Types::ALL }, allow_nil: true
|
|
28
|
+
|
|
29
|
+
# @param email [String] The email address.
|
|
30
|
+
# @param type [String, nil] Email type. One of HOME, WORK, OTHER.
|
|
31
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
32
|
+
def initialize(email:, type: nil)
|
|
33
|
+
@email = email
|
|
34
|
+
@type = type
|
|
35
|
+
|
|
36
|
+
validate!
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @return [Hash] The serialized email payload.
|
|
40
|
+
def serialize
|
|
41
|
+
{
|
|
42
|
+
email:,
|
|
43
|
+
type:,
|
|
44
|
+
}.compact
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Contacts
|
|
6
|
+
# Represents the name component of a contact message.
|
|
7
|
+
class Name
|
|
8
|
+
include ActiveModel::Validations
|
|
9
|
+
|
|
10
|
+
# @!attribute [rw] formatted_name
|
|
11
|
+
# @return [String] The contact's full display name. Required.
|
|
12
|
+
attr_accessor :formatted_name
|
|
13
|
+
|
|
14
|
+
# @!attribute [rw] first_name
|
|
15
|
+
# @return [String, nil]
|
|
16
|
+
attr_accessor :first_name
|
|
17
|
+
|
|
18
|
+
# @!attribute [rw] last_name
|
|
19
|
+
# @return [String, nil]
|
|
20
|
+
attr_accessor :last_name
|
|
21
|
+
|
|
22
|
+
# @!attribute [rw] middle_name
|
|
23
|
+
# @return [String, nil]
|
|
24
|
+
attr_accessor :middle_name
|
|
25
|
+
|
|
26
|
+
# @!attribute [rw] prefix
|
|
27
|
+
# @return [String, nil]
|
|
28
|
+
attr_accessor :prefix
|
|
29
|
+
|
|
30
|
+
# @!attribute [rw] suffix
|
|
31
|
+
# @return [String, nil]
|
|
32
|
+
attr_accessor :suffix
|
|
33
|
+
|
|
34
|
+
validates :formatted_name, presence: true
|
|
35
|
+
|
|
36
|
+
# @param formatted_name [String] The contact's full display name.
|
|
37
|
+
# @param first_name [String, nil]
|
|
38
|
+
# @param last_name [String, nil]
|
|
39
|
+
# @param middle_name [String, nil]
|
|
40
|
+
# @param prefix [String, nil]
|
|
41
|
+
# @param suffix [String, nil]
|
|
42
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
43
|
+
def initialize(formatted_name:, first_name: nil, last_name: nil, middle_name: nil, prefix: nil, suffix: nil)
|
|
44
|
+
@formatted_name = formatted_name
|
|
45
|
+
@first_name = first_name
|
|
46
|
+
@last_name = last_name
|
|
47
|
+
@middle_name = middle_name
|
|
48
|
+
@prefix = prefix
|
|
49
|
+
@suffix = suffix
|
|
50
|
+
|
|
51
|
+
validate!
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [Hash] The serialized name payload.
|
|
55
|
+
def serialize
|
|
56
|
+
{
|
|
57
|
+
formatted_name:,
|
|
58
|
+
first_name:,
|
|
59
|
+
last_name:,
|
|
60
|
+
middle_name:,
|
|
61
|
+
prefix:,
|
|
62
|
+
suffix:,
|
|
63
|
+
}.compact
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Contacts
|
|
6
|
+
# Represents the organization details of a contact message.
|
|
7
|
+
# All fields are optional.
|
|
8
|
+
class Org
|
|
9
|
+
# @!attribute [rw] company
|
|
10
|
+
# @return [String, nil]
|
|
11
|
+
attr_accessor :company
|
|
12
|
+
|
|
13
|
+
# @!attribute [rw] department
|
|
14
|
+
# @return [String, nil]
|
|
15
|
+
attr_accessor :department
|
|
16
|
+
|
|
17
|
+
# @!attribute [rw] title
|
|
18
|
+
# @return [String, nil]
|
|
19
|
+
attr_accessor :title
|
|
20
|
+
|
|
21
|
+
# @param company [String, nil]
|
|
22
|
+
# @param department [String, nil]
|
|
23
|
+
# @param title [String, nil]
|
|
24
|
+
def initialize(company: nil, department: nil, title: nil)
|
|
25
|
+
@company = company
|
|
26
|
+
@department = department
|
|
27
|
+
@title = title
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [Hash] The serialized org payload.
|
|
31
|
+
def serialize
|
|
32
|
+
{
|
|
33
|
+
company:,
|
|
34
|
+
department:,
|
|
35
|
+
title:,
|
|
36
|
+
}.compact
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Contacts
|
|
6
|
+
# Represents a phone number entry in a contact message.
|
|
7
|
+
class Phone
|
|
8
|
+
include ActiveModel::Validations
|
|
9
|
+
|
|
10
|
+
module Types
|
|
11
|
+
CELL = "CELL"
|
|
12
|
+
MAIN = "MAIN"
|
|
13
|
+
IPHONE = "IPHONE"
|
|
14
|
+
HOME = "HOME"
|
|
15
|
+
WORK = "WORK"
|
|
16
|
+
OTHER = "OTHER"
|
|
17
|
+
|
|
18
|
+
ALL = [CELL, MAIN, IPHONE, HOME, WORK, OTHER].freeze
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @!attribute [rw] phone
|
|
22
|
+
# @return [String]
|
|
23
|
+
attr_accessor :phone
|
|
24
|
+
|
|
25
|
+
# @!attribute [rw] type
|
|
26
|
+
# @return [String, nil]
|
|
27
|
+
attr_accessor :type
|
|
28
|
+
|
|
29
|
+
# @!attribute [rw] wa_id
|
|
30
|
+
# @return [String, nil]
|
|
31
|
+
attr_accessor :wa_id
|
|
32
|
+
|
|
33
|
+
validates :phone, presence: true
|
|
34
|
+
validates :type, inclusion: { in: Types::ALL }, allow_nil: true
|
|
35
|
+
|
|
36
|
+
# @param phone [String] The phone number, including country code.
|
|
37
|
+
# @param type [String, nil] Phone type. One of CELL, MAIN, IPHONE, HOME, WORK, OTHER.
|
|
38
|
+
# @param wa_id [String, nil] The WhatsApp ID for this phone number.
|
|
39
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
40
|
+
def initialize(phone:, type: nil, wa_id: nil)
|
|
41
|
+
@phone = phone
|
|
42
|
+
@type = type
|
|
43
|
+
@wa_id = wa_id
|
|
44
|
+
|
|
45
|
+
validate!
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [Hash] The serialized phone payload.
|
|
49
|
+
def serialize
|
|
50
|
+
{
|
|
51
|
+
phone:,
|
|
52
|
+
type:,
|
|
53
|
+
wa_id:,
|
|
54
|
+
}.compact
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Contacts
|
|
6
|
+
# Represents a URL entry in a contact message.
|
|
7
|
+
class Url
|
|
8
|
+
include ActiveModel::Validations
|
|
9
|
+
|
|
10
|
+
module Types
|
|
11
|
+
WEBSITE = "WEBSITE"
|
|
12
|
+
HOMEPAGE = "HOMEPAGE"
|
|
13
|
+
WORK = "WORK"
|
|
14
|
+
HOME = "HOME"
|
|
15
|
+
OTHER = "OTHER"
|
|
16
|
+
|
|
17
|
+
ALL = [WEBSITE, HOMEPAGE, WORK, HOME, OTHER].freeze
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @!attribute [rw] url
|
|
21
|
+
# @return [String]
|
|
22
|
+
attr_accessor :url
|
|
23
|
+
|
|
24
|
+
# @!attribute [rw] type
|
|
25
|
+
# @return [String, nil]
|
|
26
|
+
attr_accessor :type
|
|
27
|
+
|
|
28
|
+
validates :url, presence: true
|
|
29
|
+
validates :type, inclusion: { in: Types::ALL }, allow_nil: true
|
|
30
|
+
|
|
31
|
+
# @param url [String] The URL.
|
|
32
|
+
# @param type [String, nil] URL type. One of WEBSITE, HOMEPAGE, WORK, HOME, OTHER.
|
|
33
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
34
|
+
def initialize(url:, type: nil)
|
|
35
|
+
@url = url
|
|
36
|
+
@type = type
|
|
37
|
+
|
|
38
|
+
validate!
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @return [Hash] The serialized url payload.
|
|
42
|
+
def serialize
|
|
43
|
+
{
|
|
44
|
+
url:,
|
|
45
|
+
type:,
|
|
46
|
+
}.compact
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
# Contacts messages allow you to send rich contact information directly to WhatsApp users,
|
|
6
|
+
# such as names, phone numbers, physical addresses, and email addresses.
|
|
7
|
+
# Source: https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/contacts-messages
|
|
8
|
+
class Contacts < Base
|
|
9
|
+
module Defaults
|
|
10
|
+
TYPE = "contacts"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @!attribute [rw] contacts
|
|
14
|
+
# @return [Array<Contact>]
|
|
15
|
+
attr_accessor :contacts
|
|
16
|
+
|
|
17
|
+
validates :contacts, presence: true, length: { maximum: 1 }
|
|
18
|
+
|
|
19
|
+
# @param contacts [Array<Hash, Contact>] Array with exactly one contact.
|
|
20
|
+
# @param kwargs [Hash] Additional keyword arguments passed to Base (:to).
|
|
21
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
22
|
+
def initialize(contacts:, **)
|
|
23
|
+
super(**)
|
|
24
|
+
|
|
25
|
+
@contacts = contacts.map { |c| c.is_a?(Contact) ? c : Contact.new(**c) }
|
|
26
|
+
|
|
27
|
+
validate!
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Serializes the contacts message to a hash format suitable for the WhatsApp API.
|
|
31
|
+
# @return [Hash] The serialized contacts message.
|
|
32
|
+
def serialize
|
|
33
|
+
envelope(type: Defaults::TYPE, contacts: contacts.map(&:serialize))
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
# Document messages allow you to send a document file with an optional caption and custom filename.
|
|
6
|
+
# Source: https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/document-messages
|
|
7
|
+
#
|
|
8
|
+
# To send a document you must either:
|
|
9
|
+
# - Upload the document via Whatsapp::Media#upload to obtain a media_id, then pass it as `id`
|
|
10
|
+
# - Pass a publicly hosted URL as `link` (not recommended by Meta)
|
|
11
|
+
class Document < Base
|
|
12
|
+
module Defaults
|
|
13
|
+
TYPE = "document"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @!attribute [rw] id
|
|
17
|
+
# @return [String, nil]
|
|
18
|
+
attr_accessor :id
|
|
19
|
+
|
|
20
|
+
# @!attribute [rw] link
|
|
21
|
+
# @return [String, nil]
|
|
22
|
+
attr_accessor :link
|
|
23
|
+
|
|
24
|
+
# @!attribute [rw] caption
|
|
25
|
+
# @return [String, nil]
|
|
26
|
+
attr_accessor :caption
|
|
27
|
+
|
|
28
|
+
# @!attribute [rw] filename
|
|
29
|
+
# @return [String, nil]
|
|
30
|
+
attr_accessor :filename
|
|
31
|
+
|
|
32
|
+
validate :validate_id_or_link
|
|
33
|
+
validates :caption, length: { maximum: 1024 }, allow_nil: true
|
|
34
|
+
|
|
35
|
+
# @param id [String, nil] ID of the uploaded media asset (from Media#upload).
|
|
36
|
+
# @param link [String, nil] URL of the document hosted on a public server.
|
|
37
|
+
# @param caption [String, nil] Document caption text (maximum 1024 characters).
|
|
38
|
+
# @param filename [String, nil] Custom filename displayed in the chat (e.g. "invoice.pdf").
|
|
39
|
+
# @param kwargs [Hash] Additional keyword arguments passed to Base (:to).
|
|
40
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
41
|
+
def initialize(id: nil, link: nil, caption: nil, filename: nil, **)
|
|
42
|
+
super(**)
|
|
43
|
+
|
|
44
|
+
@id = id
|
|
45
|
+
@link = link
|
|
46
|
+
@caption = caption
|
|
47
|
+
@filename = filename
|
|
48
|
+
|
|
49
|
+
validate!
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Serializes the document message to a hash format suitable for the WhatsApp API.
|
|
53
|
+
# @return [Hash] The serialized document message.
|
|
54
|
+
def serialize
|
|
55
|
+
envelope(type: Defaults::TYPE, document: document_payload)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
# @return [Hash] The serialized document payload.
|
|
61
|
+
def document_payload
|
|
62
|
+
{
|
|
63
|
+
id:,
|
|
64
|
+
link:,
|
|
65
|
+
caption:,
|
|
66
|
+
filename:,
|
|
67
|
+
}.compact
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Validates that either id or link is present.
|
|
71
|
+
# @return [void]
|
|
72
|
+
def validate_id_or_link
|
|
73
|
+
return if id.present? || link.present?
|
|
74
|
+
|
|
75
|
+
errors.add(:base, "Either id or link must be present")
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
# Image messages display an image with an optional caption.
|
|
6
|
+
# Source: https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/image-messages
|
|
7
|
+
#
|
|
8
|
+
# To send an image you must either:
|
|
9
|
+
# - Upload the image via Whatsapp::Media#upload to obtain a media_id, then pass it as `id`
|
|
10
|
+
# - Pass a publicly hosted URL as `link` (not recommended by Meta)
|
|
11
|
+
class Image < Base
|
|
12
|
+
module Defaults
|
|
13
|
+
TYPE = "image"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @!attribute [rw] id
|
|
17
|
+
# @return [String, nil]
|
|
18
|
+
attr_accessor :id
|
|
19
|
+
|
|
20
|
+
# @!attribute [rw] link
|
|
21
|
+
# @return [String, nil]
|
|
22
|
+
attr_accessor :link
|
|
23
|
+
|
|
24
|
+
# @!attribute [rw] caption
|
|
25
|
+
# @return [String, nil]
|
|
26
|
+
attr_accessor :caption
|
|
27
|
+
|
|
28
|
+
validate :validate_id_or_link
|
|
29
|
+
validates :caption, length: { maximum: 1024 }, allow_nil: true
|
|
30
|
+
|
|
31
|
+
# @param id [String, nil] ID of the uploaded media asset (from Media#upload).
|
|
32
|
+
# @param link [String, nil] URL of the image hosted on a public server.
|
|
33
|
+
# @param caption [String, nil] Image caption text (maximum 1024 characters).
|
|
34
|
+
# @param kwargs [Hash] Additional keyword arguments passed to Base (:to).
|
|
35
|
+
# @raise [ActiveModel::ValidationError] if validation fails.
|
|
36
|
+
def initialize(id: nil, link: nil, caption: nil, **)
|
|
37
|
+
super(**)
|
|
38
|
+
|
|
39
|
+
@id = id
|
|
40
|
+
@link = link
|
|
41
|
+
@caption = caption
|
|
42
|
+
|
|
43
|
+
validate!
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Serializes the image message to a hash format suitable for the WhatsApp API.
|
|
47
|
+
# @return [Hash] The serialized image message.
|
|
48
|
+
def serialize
|
|
49
|
+
envelope(type: Defaults::TYPE, image: image_payload)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
# @return [Hash] The serialized image payload.
|
|
55
|
+
def image_payload
|
|
56
|
+
{
|
|
57
|
+
id:,
|
|
58
|
+
link:,
|
|
59
|
+
caption:,
|
|
60
|
+
}.compact
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Validates that either id or link is present.
|
|
64
|
+
# @return [void]
|
|
65
|
+
def validate_id_or_link
|
|
66
|
+
return if id.present? || link.present?
|
|
67
|
+
|
|
68
|
+
errors.add(:base, "Either id or link must be present")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Whatsapp
|
|
4
|
+
class Messages
|
|
5
|
+
class Interactive
|
|
6
|
+
class Base
|
|
7
|
+
include ActiveModel::Validations
|
|
8
|
+
|
|
9
|
+
def serialize
|
|
10
|
+
raise NotImplementedError, "Subclasses must implement the serialize method"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|