Commit 733805cc authored by 曾坤's avatar 曾坤 :flag_cn:
Browse files

Initial commit

parents
No related merge requests found
Showing with 690 additions and 0 deletions
+690 -0
# typed: false
# frozen_string_literal: true
module WhatsappSdk
module Resource
class Location
# Returns the latitude of the location.
#
# @returns latitude [Float].
attr_accessor :latitude
# Returns the longitude of the location.
#
# @returns longitude [Float].
attr_accessor :longitude
# Returns the name of the location.
#
# @returns name [String].
attr_accessor :name
# Returns the address of the location.
#
# @returns address [String].
attr_accessor :address
def initialize(latitude:, longitude:, name:, address:)
@latitude = latitude
@longitude = longitude
@name = name
@address = address
end
def to_json
{
latitude: latitude,
longitude: longitude,
name: name,
address: address
}
end
end
end
end
# frozen_string_literal: true
module WhatsappSdk
module Resource
class Media
module Type
AUDIO = 'audio'
DOCUMENT = 'document'
IMAGE = 'image'
VIDEO = 'video'
STICKER = 'sticker'
end
attr_accessor :file_size, :id, :messaging_product, :mime_type, :sha256, :url
def self.from_hash(hash)
media = new
media.id = hash["id"]
media.file_size = hash["file_size"]
media.messaging_product = hash["messaging_product"]
media.mime_type = hash["mime_type"]
media.sha256 = hash["sha256"]
media.url = hash["url"]
media
end
def ==(other)
id == other.id &&
file_size == other.file_size &&
messaging_product == other.messaging_product &&
mime_type == other.mime_type &&
sha256 == other.sha256 &&
url == other.url
end
end
end
end
# frozen_string_literal: true
# The media used by a component (button, header, body, footer) etc.
module WhatsappSdk
module Resource
class MediaComponent
class InvalidMedia < StandardError
attr_reader :field, :message
def initialize(field, message)
@field = field
@message = message
super(message)
end
end
# Returns media id.
#
# @returns id [String].
attr_accessor :id
module Type
AUDIO = 'audio'
DOCUMENT = 'document'
IMAGE = 'image'
VIDEO = 'video'
STICKER = 'sticker'
end
# @returns type [String]. Valid options ar audio, document, image, video and sticker.
attr_accessor :type
# The protocol and URL of the media to be sent. Use only with HTTP/HTTPS URLs.
# Do not use this field when the message type is set to text.
#
# @returns link [String].
attr_accessor :link
# Describes the specified document or image media.
#
# @returns caption [String].
attr_accessor :caption
# Describes the filename for the specific document. Use only with document media.
#
# @returns filename [String].
attr_accessor :filename
def initialize(type:, id: nil, link: nil, caption: nil, filename: nil)
@type = type
@id = id
@link = link
@caption = caption
@filename = filename
validate_media
end
def to_json
json = {}
json[:id] = id unless id.nil?
json[:link] = link unless link.nil?
json[:caption] = caption unless caption.nil?
json[:filename] = filename unless filename.nil?
json
end
private
def validate_media
raise InvalidMedia.new(:filename, "filename can only be used with document") if filename && !supports_filename?
if caption && !supports_caption?
raise InvalidMedia.new(:caption, "caption can only be used with document or image")
end
true
end
def supports_filename?
type == Type::DOCUMENT
end
def supports_caption?
type == Type::DOCUMENT || type == Type::IMAGE
end
end
end
end
# frozen_string_literal: true
module WhatsappSdk
module Resource
class MediaTypes
# The media types supported by Whatsapp. The list contains all the types defined in the Whatsapp API
# documentation: https://developers.facebook.com/docs/whatsapp/cloud-api/reference/media#supported-media-types
#
# The media type is used as a content-type header when downloading the file with MediasApi#download_file.
# The content-type header matches with the media type using Internet Assigned Numbers Authority (IANA).
# Media type list defined by IANA https://www.iana.org/assignments/media-types/media-types.xhtml
#
# NOTE: Cloud API may decide to allow more media types to be downloaded, since the support differs depending on
# the used client.
AUDIO_TYPES = %w[audio/aac audio/mp4 audio/mpeg audio/amr audio/ogg].freeze
DOCUMENT_TYPES = %w[
text/plain application/pdf application/vnd.ms-powerpoint application/msword application/vnd.ms-excel
application/vnd.openxmlformats-officedocument.wordprocessingml.document
application/vnd.openxmlformats-officedocument.presentationml.presentation
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
].freeze
IMAGE_TYPES = %w[image/jpeg image/png].freeze
STICKER_TYPES = %w[image/webp].freeze
VIDEO_TYPES = %w[video/mp4 video/3gp].freeze
SUPPORTED_MEDIA_TYPES = [AUDIO_TYPES + DOCUMENT_TYPES + IMAGE_TYPES + STICKER_TYPES + VIDEO_TYPES].flatten.freeze
end
end
end
# frozen_string_literal: true
module WhatsappSdk
module Resource
class Message
attr_reader :id
def initialize(id:)
@id = id
end
end
end
end
# frozen_string_literal: true
module WhatsappSdk
module Resource
class MessageTemplateNamespace
attr_accessor :id, :message_template_namespace
def self.from_hash(hash)
message_template_namespace = new
message_template_namespace.id = hash["id"]
message_template_namespace.message_template_namespace = hash["message_template_namespace"]
message_template_namespace
end
end
end
end
# frozen_string_literal: true
module WhatsappSdk
module Resource
class Name
attr_accessor :formatted_name, :first_name, :last_name, :middle_name, :suffix, :prefix
def initialize(
formatted_name: nil, first_name: nil,
last_name: nil, middle_name: nil, suffix: nil, prefix: nil
)
@formatted_name = formatted_name
@first_name = first_name
@last_name = last_name
@middle_name = middle_name
@suffix = suffix
@prefix = prefix
end
def to_h
{
formatted_name: @formatted_name,
first_name: @first_name,
last_name: @last_name,
middle_name: @middle_name,
suffix: @suffix,
prefix: @prefix
}
end
end
end
end
# frozen_string_literal: true
module WhatsappSdk
module Resource
class Org
attr_accessor :company, :department, :title
def initialize(company:, department:, title:)
@company = company
@department = department
@title = title
end
def to_h
{
company: @company,
department: @department,
title: @title
}
end
end
end
end
# frozen_string_literal: true
module WhatsappSdk
module Resource
class ParameterObject
class InvalidType < StandardError
attr_accessor :message
def initialize(type)
@message = "invalid type #{type}. type should be text, currency, date_time, image, document or video"
super
end
end
# Returns the parameter type.
#
# @returns type [String] Valid options are text, currency, date_time, image, document, video.
attr_accessor :type
module Type
TEXT = "text"
CURRENCY = "currency"
DATE_TIME = "date_time"
IMAGE = "image"
DOCUMENT = "document"
VIDEO = "video"
LOCATION = "location"
TYPES = [
TEXT,
CURRENCY,
DATE_TIME,
IMAGE,
DOCUMENT,
VIDEO,
LOCATION
].freeze
def self.valid?(type)
TYPES.include?(type)
end
end
# Returns Text string if the parameter object type is text.
# For the header component, the character limit is 60 characters.
# For the body component, the character limit is 1024 characters.
#
# @returns text [String]
attr_accessor :text
# Returns Currency if the parameter object type is currency.
#
# @returns currency [Currency]
attr_accessor :currency
# Returns date_time if the parameter object type is date_time.
#
# @returns date_time [DateTime]
attr_accessor :date_time
# Returns image if the parameter object type is image.
#
# @returns image [Media]
attr_accessor :image
# Returns document if the parameter object type is document.
#
# @returns document [Media]
attr_accessor :document
# Returns video if the parameter object type is video.
#
# @returns video [Media]
attr_accessor :video
# Returns location if the parameter object type is location
#
# @returns location [Location]
attr_accessor :location
def initialize(
type:,
text: nil,
currency: nil,
date_time: nil,
image: nil,
document: nil,
video: nil,
location: nil
)
@type = type
@text = text
@currency = currency
@date_time = date_time
@image = image
@document = document
@video = video
@location = location
validate
end
def to_json
json = { type: type }
json[type.to_sym] = case type
when "text"
text
when "currency"
currency.to_json
when "date_time"
date_time.to_json
when "image"
image.to_json
when "document"
document.to_json
when "video"
video.to_json
when "location"
location.to_json
else
raise "Invalid type: #{type}"
end
json
end
private
def validate
validate_attributes
validate_type
end
def validate_type
return if Type.valid?(type)
raise InvalidType, type
end
def validate_attributes
[
[Type::TEXT, text],
[Type::CURRENCY, currency],
[Type::DATE_TIME, date_time],
[Type::IMAGE, image],
[Type::DOCUMENT, document],
[Type::VIDEO, video],
[Type::LOCATION, location]
].each do |type_b, value|
next unless type == type_b
next unless value.nil?
raise Errors::MissingValue.new(
type,
"#{type_b} is required when the type is #{type_b}"
)
end
end
end
end
end
# frozen_string_literal: true
module WhatsappSdk
module Resource
class PhoneNumber
attr_accessor :id, :verified_name, :display_phone_number, :quality_rating, :is_pin_enabled,
:is_official_business_account, :account_mode, :certificate, :code_verification_status,
:eligibility_for_api_business_global_search, :name_status, :new_name_status, :status,
:search_visibility, :messaging_limit_tier # , :phone, :wa_id, :type
def self.from_hash(hash)
phone_number = PhoneNumber.new
phone_number.id = hash["id"]
phone_number.verified_name = hash["verified_name"]
phone_number.display_phone_number = hash["display_phone_number"]
phone_number.quality_rating = hash["quality_rating"]
phone_number.is_pin_enabled = hash["is_pin_enabled"]
phone_number.is_official_business_account = hash["is_official_business_account"]
phone_number.account_mode = hash["account_mode"]
phone_number.certificate = hash["certificate"]
phone_number.code_verification_status = hash["code_verification_status"]
phone_number.eligibility_for_api_business_global_search = hash["eligibility_for_api_business_global_search"]
phone_number.name_status = hash["name_status"]
phone_number.new_name_status = hash["new_name_status"]
phone_number.status = hash["status"]
phone_number.search_visibility = hash["search_visibility"]
phone_number.messaging_limit_tier = hash["messaging_limit_tier"]
phone_number
end
# rubocop:disable Metrics/PerceivedComplexity
def ==(other)
id == other.id &&
verified_name == other.verified_name &&
display_phone_number == other.display_phone_number &&
quality_rating == other.quality_rating &&
is_pin_enabled == other.is_pin_enabled &&
is_official_business_account == other.is_official_business_account &&
account_mode == other.account_mode &&
certificate == other.certificate &&
code_verification_status == other.code_verification_status &&
eligibility_for_api_business_global_search == other.eligibility_for_api_business_global_search &&
name_status == other.name_status &&
new_name_status == other.new_name_status &&
status == other.status &&
search_visibility == other.search_visibility &&
messaging_limit_tier == other.messaging_limit_tier
end
# rubocop:enable Metrics/PerceivedComplexity
end
end
end
# frozen_string_literal: true
# The media used by a component (button, header, body, footer) etc.
module WhatsappSdk
module Resource
class PhoneNumberComponent
attr_accessor :phone, :wa_id, :type
def initialize(phone:, type:, wa_id:)
@phone = phone
@type = type
@wa_id = wa_id
end
def to_h
{
phone: @phone,
type: @type,
wa_id: @wa_id
}
end
end
end
end
# frozen_string_literal: true
module WhatsappSdk
module Resource
class Template
module Status
PENDING_DELETION = "PENDING_DELETION"
APPROVED = "APPROVED"
PENDING = "PENDING"
REJECTED = "REJECTED"
STATUSES = [PENDING_DELETION, APPROVED, PENDING, REJECTED].freeze
def valid?(status)
STATUSES.include?(status)
end
def serialize(status)
STATUSES.include?(status) ? status : nil
end
end
module Category
AUTHENTICATION = "AUTHENTICATION"
MARKETING = "MARKETING"
UTILITY = "UTILITY"
CATEGORIES = [AUTHENTICATION, MARKETING, UTILITY].freeze
def self.valid?(category)
CATEGORIES.include?(category)
end
def self.serialize(category)
CATEGORIES.include?(category) ? category : nil
end
end
attr_accessor :id, :status, :category, :language, :name, :components_json
def initialize(id:, status:, category:, language: nil, name: nil, components_json: nil)
@id = id
@status = status
@category = category
@language = language
@name = name
@components_json = components_json
end
def self.from_hash(hash)
new(
id: hash["id"],
status: hash["status"],
category: hash["category"],
language: hash["language"],
name: hash["name"],
components_json: hash["components"]
)
end
def ==(other)
id == other.id &&
status == other.status &&
category == other.category &&
language == other.language &&
name == other.name &&
components_json == other.components_json
end
end
end
end
# frozen_string_literal: true
module WhatsappSdk
module Resource
class Url
attr_accessor :url, :type
def initialize(url:, type:)
@url = url
@type = type
end
def to_h
{
url: @url,
type: @type
}
end
end
end
end
# frozen_string_literal: true
module WhatsappSdk
VERSION = "1.0.1"
end
# typed: false
# frozen_string_literal: true
module ErrorsHelper
def assert_unsupported_request_error(http_method, response, object_id, fb_trace_id)
assert_error_response(
{
code: 100,
error_subcode: 33,
message: "Unsupported #{http_method} request. Object with ID '#{object_id}' does not exist, " \
"cannot be loaded due to missing permissions, or does not support this operation. " \
"Please read the Graph API documentation at https://developers.facebook.com/docs/graph-api",
fbtrace_id: fb_trace_id
},
response
)
end
def assert_unsupported_request_error_v2(
http_method, object_id, fb_trace_id, error_info, type = "GraphMethodException"
)
assert_error_info(
{
code: 100,
error_subcode: 33,
type: type,
message: "Unsupported #{http_method} request. Object with ID '#{object_id}' does not exist, " \
"cannot be loaded due to missing permissions, or does not support this operation. " \
"Please read the Graph API documentation at https://developers.facebook.com/docs/graph-api",
fbtrace_id: fb_trace_id
},
error_info
)
end
def assert_error_info(expected_error, error)
[
[expected_error[:message], error.message],
[expected_error[:type], error.type],
[expected_error[:code], error.code],
[expected_error[:error_subcode], error.subcode],
[expected_error[:fbtrace_id], error.fbtrace_id]
].each do |expected, actual|
if expected.nil?
assert_nil(actual)
else
assert_equal(expected, actual)
end
end
end
def assert_error_response(expected_error, response)
refute_predicate(response, :ok?)
assert_nil(response.data)
error = response.error
[
[expected_error[:code], error.code],
[expected_error[:error_subcode], error.subcode],
[expected_error[:message], error.message],
[expected_error[:fbtrace_id], error.fbtrace_id]
].each do |expected, actual|
if expected.nil?
assert_nil(actual)
else
assert_equal(expected, actual)
end
end
end
end
File added
test/fixtures/assets/downloaded_audio.jpg

4.63 KB

File added
File added
test/fixtures/assets/downloaded_audio.png

4.63 KB

Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment