Class: Bobot::Page

Inherits:
Object
  • Object
show all
Defined in:
lib/bobot/page.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Page

Returns a new instance of Page.



5
6
7
8
9
10
11
# File 'lib/bobot/page.rb', line 5

def initialize(options = {})
  self.slug = options[:slug]
  self.language = options[:language]
  self.page_id = options[:page_id]
  self.page_access_token = options[:page_access_token]
  self.get_started_payload = options[:get_started_payload]
end

Instance Attribute Details

#get_started_payloadObject

Returns the value of attribute get_started_payload.



3
4
5
# File 'lib/bobot/page.rb', line 3

def get_started_payload
  @get_started_payload
end

#languageObject

Returns the value of attribute language.



3
4
5
# File 'lib/bobot/page.rb', line 3

def language
  @language
end

#page_access_tokenObject

Returns the value of attribute page_access_token.



3
4
5
# File 'lib/bobot/page.rb', line 3

def page_access_token
  @page_access_token
end

#page_idObject

Returns the value of attribute page_id.



3
4
5
# File 'lib/bobot/page.rb', line 3

def page_id
  @page_id
end

#slugObject

Returns the value of attribute slug.



3
4
5
# File 'lib/bobot/page.rb', line 3

def slug
  @slug
end

Class Method Details

.[](value) ⇒ Object



27
28
29
# File 'lib/bobot/page.rb', line 27

def self.[](value)
  find(value) || find_by_slug(value)
end

.find(page_id) ⇒ Object

FINDERS



19
20
21
# File 'lib/bobot/page.rb', line 19

def self.find(page_id)
  Bobot.config.pages.find { |page| page.page_id.to_s == page_id.to_s }
end

.find_by_slug(slug) ⇒ Object



23
24
25
# File 'lib/bobot/page.rb', line 23

def self.find_by_slug(slug)
  Bobot.config.pages.find { |page| page.slug.to_s == slug.to_s }
end

Instance Method Details

#deliver(payload_template:, to:) ⇒ Object

REQUESTS

Raises:



37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/bobot/page.rb', line 37

def deliver(payload_template:, to:)
  raise Bobot::FieldFormat.new('payload_template is required') unless payload_template.present?
  raise Bobot::FieldFormat.new('payload_template[:messaging_type] is required') unless payload_template.key?(:messaging_type)
  raise Bobot::FieldFormat.new('payload_template[:messaging_type] is invalid, only "RESPONSE, UPDATE, MESSAGE_TAG" are permitted.', payload_template[:messaging_type]) unless %w[RESPONSE UPDATE MESSAGE_TAG].include?(payload_template[:messaging_type])
  Bobot::Commander.deliver(
    body: {
      recipient: { id: to },
      messaging_type: "RESPONSE",
    }.merge(payload_template),
    query: {
      access_token: page_access_token,
    },
  )
end

#mark_as_seen(to: nil, messaging_type: "RESPONSE") ⇒ Object



60
61
62
# File 'lib/bobot/page.rb', line 60

def mark_as_seen(to: nil, messaging_type: "RESPONSE")
  sender_action(sender_action: 'mark_seen', messaging_type: messaging_type, to: to)
end

#send(payload_message:, to: nil, messaging_type: "RESPONSE") ⇒ Object



64
65
66
# File 'lib/bobot/page.rb', line 64

def send(payload_message:, to: nil, messaging_type: "RESPONSE")
  deliver(payload_template: { message: payload_message, messaging_type: messaging_type }, to: to)
end

#send_attachment(url:, type:, to: nil, messaging_type: "RESPONSE") ⇒ Object

Raises:



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/bobot/page.rb', line 80

def send_attachment(url:, type:, to: nil, messaging_type: "RESPONSE")
  raise Bobot::FieldFormat.new('url is required') unless url.present?
  raise Bobot::FieldFormat.new('type is required') unless type.present?
  raise Bobot::FieldFormat.new('type is invalid, only "image, audio, video, file" are permitted.', type) unless %w[image audio video file].include?(type)
  send(
    payload_message: {
      attachment: {
        type: type,
        payload: {
          url: url,
        }.tap { |properties| properties.merge!(is_reusable: true) if type == 'image' },
      },
    },
    to: to,
    messaging_type: messaging_type,
  )
end

#send_audio(url:, to: nil, messaging_type: "RESPONSE") ⇒ Object



122
123
124
# File 'lib/bobot/page.rb', line 122

def send_audio(url:, to: nil, messaging_type: "RESPONSE")
  send_attachment(url: url, type: 'audio', to: to, messaging_type: messaging_type)
end

#send_buttons(text:, buttons:, to: nil, messaging_type: "RESPONSE") ⇒ Object

Raises:



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/bobot/page.rb', line 149

def send_buttons(text:, buttons:, to: nil, messaging_type: "RESPONSE")
  raise Bobot::FieldFormat.new('text is required') unless text.present?
  raise Bobot::FieldFormat.new('text size is limited to 640.', "#{text} (#{text.size} chars)") if text.size > 640
  raise Bobot::FieldFormat.new('buttons are required') unless buttons.present?
  raise Bobot::FieldFormat.new('buttons are limited to 3', "#{buttons.size} buttons") if buttons.size > 3
  send(
    payload_message: {
      attachment: {
        type: 'template',
        payload: {
          template_type: 'button',
          text: text,
          buttons: buttons,
        },
      },
    },
    to: to,
    messaging_type: messaging_type,
  )
end

#send_file(url:, to: nil, messaging_type: "RESPONSE") ⇒ Object



130
131
132
# File 'lib/bobot/page.rb', line 130

def send_file(url:, to: nil, messaging_type: "RESPONSE")
  send_attachment(url: url, type: 'file', to: to, messaging_type: messaging_type)
end

#send_generic(elements:, image_aspect_ratio: 'square', to: nil, messaging_type: "RESPONSE") ⇒ Object Also known as: send_carousel

Raises:



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/bobot/page.rb', line 170

def send_generic(elements:, image_aspect_ratio: 'square', to: nil, messaging_type: "RESPONSE")
  raise Bobot::FieldFormat.new('elements are required') if elements.nil?
  raise Bobot::FieldFormat.new('elements are limited to 10.', "#{elements.size} elements") if elements.size > 10
  raise Bobot::FieldFormat.new('image_aspect_ratio is required') if image_aspect_ratio.nil?
  raise Bobot::FieldFormat.new('image_aspect_ratio is invalid, only "square, horizontal" are permitted.', image_aspect_ratio) unless %w[square horizontal].include?(image_aspect_ratio)
  send(
    payload_message: {
      attachment: {
        type: 'template',
        payload: {
          template_type: 'generic',
          image_aspect_ratio: image_aspect_ratio,
          elements: elements,
        },
      },
    },
    to: to,
    messaging_type: messaging_type,
  )
end

#send_image(url:, to: nil, messaging_type: "RESPONSE") ⇒ Object



118
119
120
# File 'lib/bobot/page.rb', line 118

def send_image(url:, to: nil, messaging_type: "RESPONSE")
  send_attachment(url: url, type: 'image', to: to, messaging_type: messaging_type)
end

#send_quick_replies(text:, quick_replies:, to: nil, messaging_type: "RESPONSE") ⇒ Object

Raises:



134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/bobot/page.rb', line 134

def send_quick_replies(text:, quick_replies:, to: nil, messaging_type: "RESPONSE")
  raise Bobot::FieldFormat.new('text is required') unless text.present?
  raise Bobot::FieldFormat.new('text size is limited to 640.', "#{text} (#{text.size} chars)") if text.size > 640
  raise Bobot::FieldFormat.new('quick_replies are required') unless quick_replies.present?
  raise Bobot::FieldFormat.new('quick_replies are limited to 11.', "#{quick_replies.size} quick replies") if quick_replies.size > 11
  send(
    payload_message: {
      text: text,
      quick_replies: quick_replies,
    },
    to: to,
    messaging_type: messaging_type,
  )
end

#send_text(text:, to: nil, messaging_type: "RESPONSE") ⇒ Object

Raises:



68
69
70
71
72
73
74
75
76
77
78
# File 'lib/bobot/page.rb', line 68

def send_text(text:, to: nil, messaging_type: "RESPONSE")
  raise Bobot::FieldFormat.new('text is required') unless text.present?
  raise Bobot::FieldFormat.new('text size is limited to 640.', "#{text} (#{text.size} chars)") if text.size > 640
  send(
    payload_message: {
      text: text,
    },
    to: to,
    messaging_type: messaging_type,
  )
end

#send_video(url:, to: nil, messaging_type: "RESPONSE") ⇒ Object



126
127
128
# File 'lib/bobot/page.rb', line 126

def send_video(url:, to: nil, messaging_type: "RESPONSE")
  send_attachment(url: url, type: 'video', to: to, messaging_type: messaging_type)
end

#send_youtube_video(url:, to: nil, messaging_type: "RESPONSE") ⇒ Object

Raises:



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/bobot/page.rb', line 98

def send_youtube_video(url:, to: nil, messaging_type: "RESPONSE")
  raise Bobot::FieldFormat.new('url is required') unless url.present?
  raise Bobot::FieldFormat.new('url is not valid', url) unless url =~ %r{^(?:https?:\/\/)?(?:www\.)?youtu(?:\.be|be\.com)\/(?:watch\?v=)?([\w-]{10,})}
  send(
    payload_message: {
      attachment: {
        type: "template",
        payload: {
          template_type: "open_graph",
          elements: [
            { url: url },
          ],
        },
      },
    },
    to: to,
    messaging_type: messaging_type,
  )
end

#sender_action(sender_action:, to: nil, messaging_type: "RESPONSE") ⇒ Object



52
53
54
# File 'lib/bobot/page.rb', line 52

def sender_action(sender_action:, to: nil, messaging_type: "RESPONSE")
  deliver(payload_template: { sender_action: sender_action, messaging_type: messaging_type }, to: to)
end

#set_get_started_button!Object

You can define the action to trigger when new humans click on ==

the Get Started button. Before doing it you should check to select the ==

messaging_postbacks field when setting up your webhook. ==

Raises:



294
295
296
297
298
299
300
301
# File 'lib/bobot/page.rb', line 294

def set_get_started_button!
  raise Bobot::FieldFormat.new("access_token is required") unless page_access_token.present?
  raise Bobot::FieldFormat.new("get_started_payload is required") unless get_started_payload.present?
  Bobot::Profile.set(
    body: { get_started: { payload: get_started_payload } },
    query: { access_token: page_access_token },
  )
end

#set_greeting_text!Object

Set bot description (only displayed on first time). ==

Raises:



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/bobot/page.rb', line 230

def set_greeting_text!
  raise Bobot::FieldFormat.new("access_token is required") unless page_access_token.present?
  greeting_texts = []
  if language.nil?
    # Default text
    greeting_text = I18n.t("bobot.#{slug}.config.greeting_text", locale: I18n.default_locale, default: nil)
    greeting_texts << { locale: 'default', text: greeting_text } if greeting_text.present?
    # Each languages
    I18n.available_locales.each do |locale|
      greeting_text = I18n.t("bobot.#{slug}.config.greeting_text", locale: locale, default: nil)
      next unless greeting_text.present?
      facebook_locales = I18n.t("bobot.#{slug}.config.facebook_locales", locale: locale, default: nil)
      facebook_locales.to_a.each do |locale_long|
        greeting_texts << { locale: locale_long, text: greeting_text }
      end
    end
  else
    greeting_text = I18n.t("bobot.#{slug}.config.greeting_text", locale: language, default: nil)
    greeting_texts << { locale: 'default', text: greeting_text } if greeting_text.present?
  end
  if greeting_texts.present?
    greeting_texts.each do |row|
      if row[:text].present? && row[:text].size > 160
        raise Bobot::FieldFormat.new("greeting text for locale #{row[:locale]} is limited to 160.", "#{row[:text]} (#{row[:text].size} chars)")
      end
    end
    Bobot::Profile.set(
      body: { greeting: greeting_texts },
      query: { access_token: page_access_token },
    )
  end
end

#set_persistent_menu!Object

You can show a persistent menu to humans. ==

If you want to have a persistent menu, you have to set get_started ==

button before. ==

Raises:



314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/bobot/page.rb', line 314

def set_persistent_menu!
  raise Bobot::FieldFormat.new("access_token is required") unless page_access_token.present?
  persistent_menus = []
  # Default text
  if language.nil?
    persistent_menu = I18n.t("bobot.#{slug}.config.persistent_menu", locale: I18n.default_locale, default: nil)
    if persistent_menu.present?
      persistent_menus << {
        locale: 'default',
        composer_input_disabled: persistent_menu[:composer_input_disabled],
        call_to_actions: persistent_menu[:call_to_actions],
      }
    end
    # Each languages
    I18n.available_locales.each do |locale|
      persistent_menu = I18n.t("bobot.#{slug}.config.persistent_menu", locale: locale, default: nil)
      facebook_locales = I18n.t("bobot.#{slug}.config.facebook_locales", locale: locale, default: nil)
      next unless persistent_menu.present?
      facebook_locales.to_a.each do |locale_long|
        persistent_menus << {
          locale: locale_long,
          composer_input_disabled: persistent_menu[:composer_input_disabled],
          call_to_actions: persistent_menu[:call_to_actions],
        }
      end
    end
  else
    persistent_menu = I18n.t("bobot.#{slug}.config.persistent_menu", locale: language, default: nil)
    if persistent_menu.present?
      persistent_menus << {
        locale: 'default',
        composer_input_disabled: persistent_menu[:composer_input_disabled],
        call_to_actions: persistent_menu[:call_to_actions],
      }
    end
  end
  if persistent_menus.present?
    persistent_menus.each do |row|
      if row[:title].present? && row[:title].size > 30
        raise Bobot::FieldFormat.new("persistent menu text for locale #{row[:locale]} is limited to 30.", "#{row[:title]} (#{row[:title].size} chars)")
      end
    end
    Bobot::Profile.set(
      body: { persistent_menu: persistent_menus },
      query: { access_token: page_access_token },
    )
  end
end

#set_whitelist_domains!Object

Set bot whitelist domains (only displayed on first time) ==

Some features like Messenger Extensions and Checkbox Plugin require ==

a page to specify a domain whitelist. ==

Raises:



274
275
276
277
278
279
280
281
# File 'lib/bobot/page.rb', line 274

def set_whitelist_domains!
  raise Bobot::FieldFormat.new("access_token is required") unless page_access_token.present?
  raise Bobot::FieldFormat.new("Bobot.config.domains is required") unless Bobot.config.domains.present?
  Bobot::Profile.set(
    body: { whitelisted_domains: Bobot.config.domains },
    query: { access_token: page_access_token },
  )
end

#show_typing(state:, to: nil, messaging_type: "RESPONSE") ⇒ Object



56
57
58
# File 'lib/bobot/page.rb', line 56

def show_typing(state:, to: nil, messaging_type: "RESPONSE")
  sender_action(sender_action: (state ? 'typing_on' : 'typing_off'), messaging_type: messaging_type, to: to)
end

#subscribe_to_facebook_page!Object

Subcribe your bot to your page ==

Raises:



206
207
208
209
210
211
212
213
214
215
# File 'lib/bobot/page.rb', line 206

def subscribe_to_facebook_page!
  raise Bobot::FieldFormat.new("page_id is required") unless page_id.present?
  raise Bobot::FieldFormat.new("access_token is required") unless page_access_token.present?
  Bobot::Subscription.set(
    query: {
      page_id: page_id,
      access_token: page_access_token,
    },
  )
end

#unset_get_started_button!Object

Raises:



303
304
305
306
307
308
309
# File 'lib/bobot/page.rb', line 303

def unset_get_started_button!
  raise Bobot::FieldFormat.new("access_token is required") unless page_access_token.present?
  Bobot::Profile.unset(
    body: { fields: %w[persistent_menu get_started] },
    query: { access_token: page_access_token },
  )
end

#unset_greeting_text!Object

Raises:



263
264
265
266
267
268
269
# File 'lib/bobot/page.rb', line 263

def unset_greeting_text!
  raise Bobot::FieldFormat.new("access_token is required") unless page_access_token.present?
  Bobot::Profile.unset(
    body: { fields: %w[greeting] },
    query: { access_token: page_access_token },
  )
end

#unset_persistent_menu!Object

Raises:



363
364
365
366
367
368
369
# File 'lib/bobot/page.rb', line 363

def unset_persistent_menu!
  raise Bobot::FieldFormat.new("access_token is required") unless page_access_token.present?
  Bobot::Profile.unset(
    body: { fields: ["persistent_menu"] },
    query: { access_token: page_access_token },
  )
end

#unset_whitelist_domains!Object

Raises:



283
284
285
286
287
288
289
# File 'lib/bobot/page.rb', line 283

def unset_whitelist_domains!
  raise Bobot::FieldFormat.new("access_token is required") unless page_access_token.present?
  Bobot::Profile.unset(
    body: { fields: ["whitelisted_domains"] },
    query: { access_token: page_access_token },
  )
end

#unsubscribe_to_facebook_page!Object

Unsubcribe your bot from your page ==

Raises:



218
219
220
221
222
223
224
225
226
227
# File 'lib/bobot/page.rb', line 218

def unsubscribe_to_facebook_page!
  raise Bobot::FieldFormat.new("page_id is required") unless page_id.present?
  raise Bobot::FieldFormat.new("access_token is required") unless page_access_token.present?
  Bobot::Subscription.unset(
    query: {
      page_id: page_id,
      access_token: page_access_token,
    },
  )
end

#update_facebook_setup!Object

SETUP



197
198
199
200
201
202
203
# File 'lib/bobot/page.rb', line 197

def update_facebook_setup!
  subscribe_to_facebook_page!
  set_greeting_text!
  set_whitelist_domains!
  set_get_started_button!
  set_persistent_menu!
end