facebookbusiness 0.7.0.1 → 0.8.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/lib/facebook_ads/ad_objects/ad_account.rb +16 -19
  3. data/lib/facebook_ads/ad_objects/ad_account_ad_volume.rb +23 -0
  4. data/lib/facebook_ads/ad_objects/ad_account_delivery_estimate.rb +1 -0
  5. data/lib/facebook_ads/ad_objects/ad_account_matched_search_applications_edge_data.rb +1 -0
  6. data/lib/facebook_ads/ad_objects/ad_account_targeting_unified.rb +1 -0
  7. data/lib/facebook_ads/ad_objects/ad_activity.rb +7 -0
  8. data/lib/facebook_ads/ad_objects/ad_asset_feed_spec.rb +2 -0
  9. data/lib/facebook_ads/ad_objects/ad_campaign_activity.rb +2 -2
  10. data/lib/facebook_ads/ad_objects/ad_campaign_delivery_estimate.rb +1 -0
  11. data/lib/facebook_ads/ad_objects/ad_creative.rb +1 -0
  12. data/lib/facebook_ads/ad_objects/{atlas_url.rb → ad_creative_instagram_branded_content.rb} +1 -2
  13. data/lib/facebook_ads/ad_objects/ad_creative_interactive_components_spec.rb +1 -0
  14. data/lib/facebook_ads/ad_objects/ad_creative_link_data_call_to_action.rb +1 -0
  15. data/lib/facebook_ads/ad_objects/ad_network_analytics_sync_query_result.rb +1 -0
  16. data/lib/facebook_ads/ad_objects/ad_place_page_set.rb +6 -0
  17. data/lib/facebook_ads/ad_objects/ad_preview.rb +0 -1
  18. data/lib/facebook_ads/ad_objects/ad_report_spec.rb +0 -1
  19. data/lib/facebook_ads/ad_objects/ad_set.rb +2 -0
  20. data/lib/facebook_ads/ad_objects/ad_study.rb +2 -0
  21. data/lib/facebook_ads/ad_objects/ad_video.rb +12 -27
  22. data/lib/facebook_ads/ad_objects/adgroup_placement_specific_review_feedback.rb +4 -0
  23. data/lib/facebook_ads/ad_objects/{ads_interest.rb → adoptable_pet.rb} +19 -5
  24. data/lib/facebook_ads/ad_objects/ads_insights.rb +4 -0
  25. data/lib/facebook_ads/ad_objects/ads_pixel.rb +3 -0
  26. data/lib/facebook_ads/ad_objects/application.rb +26 -0
  27. data/lib/facebook_ads/ad_objects/atlas_campaign.rb +3 -3
  28. data/lib/facebook_ads/ad_objects/automotive_model.rb +1 -0
  29. data/lib/facebook_ads/ad_objects/business.rb +46 -117
  30. data/lib/facebook_ads/ad_objects/business_asset_group.rb +2 -3
  31. data/lib/facebook_ads/ad_objects/business_role_request.rb +9 -0
  32. data/lib/facebook_ads/ad_objects/business_unit.rb +1 -1
  33. data/lib/facebook_ads/ad_objects/business_user.rb +9 -0
  34. data/lib/facebook_ads/ad_objects/campaign.rb +257 -0
  35. data/lib/facebook_ads/ad_objects/catalog_sub_vertical_list.rb +88 -0
  36. data/lib/facebook_ads/ad_objects/commerce_merchant_settings.rb +27 -0
  37. data/lib/facebook_ads/ad_objects/commerce_order.rb +6 -0
  38. data/lib/facebook_ads/ad_objects/commerce_order_transaction_detail.rb +4 -0
  39. data/lib/facebook_ads/ad_objects/{creative_asset_tag.rb → connections_targeting.rb} +2 -2
  40. data/lib/facebook_ads/ad_objects/{business_creative_folder_sharing_agreement.rb → cpas_advertiser_partnership_recommendation.rb} +8 -11
  41. data/lib/facebook_ads/ad_objects/{brand_audience.rb → cpas_collaboration_request.rb} +15 -9
  42. data/lib/facebook_ads/ad_objects/custom_audience_data_source.rb +1 -0
  43. data/lib/facebook_ads/ad_objects/da_check.rb +7 -0
  44. data/lib/facebook_ads/ad_objects/destination.rb +1 -0
  45. data/lib/facebook_ads/ad_objects/event.rb +12 -1
  46. data/lib/facebook_ads/ad_objects/extended_credit.rb +7 -0
  47. data/lib/facebook_ads/ad_objects/external_event_source.rb +1 -0
  48. data/lib/facebook_ads/ad_objects/flight.rb +1 -0
  49. data/lib/facebook_ads/ad_objects/group.rb +10 -1
  50. data/lib/facebook_ads/ad_objects/home_listing.rb +1 -0
  51. data/lib/facebook_ads/ad_objects/hotel.rb +1 -0
  52. data/lib/facebook_ads/ad_objects/ig_media.rb +1 -0
  53. data/lib/facebook_ads/ad_objects/life_event.rb +0 -4
  54. data/lib/facebook_ads/ad_objects/link.rb +0 -6
  55. data/lib/facebook_ads/ad_objects/live_video.rb +12 -16
  56. data/lib/facebook_ads/ad_objects/media_fingerprint.rb +0 -1
  57. data/lib/facebook_ads/ad_objects/native_offer_view.rb +0 -1
  58. data/lib/facebook_ads/ad_objects/oracle_transaction.rb +0 -7
  59. data/lib/facebook_ads/ad_objects/page.rb +34 -65
  60. data/lib/facebook_ads/ad_objects/page_admin_note.rb +1 -0
  61. data/lib/facebook_ads/ad_objects/page_call_to_action.rb +3 -0
  62. data/lib/facebook_ads/ad_objects/page_change_proposal.rb +2 -0
  63. data/lib/facebook_ads/ad_objects/page_post.rb +2 -0
  64. data/lib/facebook_ads/ad_objects/{business_creative.rb → payment_subscription.rb} +24 -16
  65. data/lib/facebook_ads/ad_objects/photo.rb +6 -0
  66. data/lib/facebook_ads/ad_objects/post.rb +4 -2
  67. data/lib/facebook_ads/ad_objects/product_catalog.rb +42 -0
  68. data/lib/facebook_ads/ad_objects/product_feed.rb +31 -0
  69. data/lib/facebook_ads/ad_objects/product_group.rb +1 -0
  70. data/lib/facebook_ads/ad_objects/product_item.rb +2 -0
  71. data/lib/facebook_ads/ad_objects/product_set.rb +4 -0
  72. data/lib/facebook_ads/ad_objects/{client_transparency_status.rb → product_set_metadata.rb} +5 -5
  73. data/lib/facebook_ads/ad_objects/profile.rb +1 -0
  74. data/lib/facebook_ads/ad_objects/profile_picture_source.rb +4 -0
  75. data/lib/facebook_ads/ad_objects/publisher_block_list.rb +6 -0
  76. data/lib/facebook_ads/ad_objects/saved_audience.rb +1 -0
  77. data/lib/facebook_ads/ad_objects/security_settings.rb +0 -1
  78. data/lib/facebook_ads/ad_objects/server_side/batch_processor.rb +73 -0
  79. data/lib/facebook_ads/ad_objects/server_side/content.rb +75 -13
  80. data/lib/facebook_ads/ad_objects/server_side/custom_data.rb +45 -6
  81. data/lib/facebook_ads/ad_objects/server_side/delivery_category.rb +33 -0
  82. data/lib/facebook_ads/ad_objects/server_side/event.rb +62 -3
  83. data/lib/facebook_ads/ad_objects/server_side/event_request.rb +134 -13
  84. data/lib/facebook_ads/ad_objects/server_side/event_request_async.rb +43 -0
  85. data/lib/facebook_ads/ad_objects/{whats_app_business_profile.rb → server_side/http_method.rb} +7 -15
  86. data/lib/facebook_ads/ad_objects/server_side/http_service_interface.rb +33 -0
  87. data/lib/facebook_ads/ad_objects/server_side/http_util.rb +31 -0
  88. data/lib/facebook_ads/ad_objects/server_side/user_data.rb +145 -17
  89. data/lib/facebook_ads/ad_objects/server_side/util.rb +216 -149
  90. data/lib/facebook_ads/ad_objects/system_user.rb +9 -4
  91. data/lib/facebook_ads/ad_objects/targeting.rb +4 -3
  92. data/lib/facebook_ads/ad_objects/{user_influence.rb → targeting_relaxation.rb} +2 -4
  93. data/lib/facebook_ads/ad_objects/third_party_measurement_report_dataset.rb +1 -0
  94. data/lib/facebook_ads/ad_objects/unified_thread.rb +1 -0
  95. data/lib/facebook_ads/ad_objects/user.rb +9 -15
  96. data/lib/facebook_ads/ad_objects/vehicle.rb +1 -0
  97. data/lib/facebook_ads/ad_objects/vehicle_offer.rb +1 -0
  98. data/lib/facebook_ads/ad_objects/whats_app_business_account.rb +22 -0
  99. data/lib/facebook_ads/errors.rb +1 -1
  100. data/lib/facebook_ads/version.rb +2 -2
  101. metadata +64 -25
  102. data/lib/facebook_ads/ad_objects/business_creative_folder.rb +0 -79
  103. data/lib/facebook_ads/ad_objects/business_image.rb +0 -95
  104. data/lib/facebook_ads/ad_objects/iterative_split_test_config.rb +0 -43
  105. data/lib/facebook_ads/ad_objects/messenger_platform_referral.rb +0 -39
  106. data/lib/facebook_ads/ad_objects/page_about_story.rb +0 -39
  107. data/lib/facebook_ads/ad_objects/split_test_config.rb +0 -41
  108. data/lib/facebook_ads/ad_objects/streaming_reaction.rb +0 -51
  109. data/lib/facebook_ads/ad_objects/user_taggable_friend.rb +0 -49
@@ -0,0 +1,43 @@
1
+ # Copyright (c) 2017-present, Facebook, Inc. All rights reserved.
2
+ #
3
+ # You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
4
+ # copy, modify, and distribute this software in source code or binary form for use
5
+ # in connection with the web services and APIs provided by Facebook.
6
+ #
7
+ # As with any software that integrates with the Facebook platform, your use of
8
+ # this software is subject to the Facebook Platform Policy
9
+ # [http://developers.facebook.com/policy/]. This copyright notice shall be
10
+ # included in all copies or substantial portions of the software.
11
+ #
12
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
14
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
16
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
17
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18
+
19
+ require 'concurrent'
20
+
21
+ module FacebookAds
22
+ module ServerSide
23
+ class EventRequestAsync < EventRequest
24
+ def execute
25
+ Concurrent::Promise.execute do
26
+ super
27
+ end
28
+ end
29
+
30
+ def clone_without_events
31
+ FacebookAds::ServerSide::EventRequestAsync.new(
32
+ pixel_id: pixel_id,
33
+ test_event_code: test_event_code,
34
+ partner_agent: partner_agent,
35
+ namespace_id: namespace_id,
36
+ upload_id: upload_id,
37
+ upload_tag: upload_tag,
38
+ upload_source: upload_source,
39
+ )
40
+ end
41
+ end
42
+ end
43
+ end
@@ -16,21 +16,13 @@
16
16
  # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
17
17
  # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18
18
 
19
- # FB:AUTOGEN
20
-
21
19
  module FacebookAds
22
- # This class is auto-generated.
23
-
24
- # For any issues or feature requests related to this class, please let us know
25
- # on github and we'll fix in our codegen framework. We'll not be able to accept
26
- # pull request for this class.
27
-
28
- class WhatsAppBusinessProfile < AdObject
29
-
30
- field :id, 'string'
31
- field :name_verification, 'object'
32
- field :verified_name, 'string'
33
- has_no_delete
34
-
20
+ module ServerSide
21
+ class HttpMethod
22
+ POST = 'POST'
23
+ PUT = 'PUT'
24
+ GET = 'GET'
25
+ DELETE = 'DELETE'
26
+ end
35
27
  end
36
28
  end
@@ -0,0 +1,33 @@
1
+ # Copyright (c) 2017-present, Facebook, Inc. All rights reserved.
2
+ #
3
+ # You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
4
+ # copy, modify, and distribute this software in source code or binary form for use
5
+ # in connection with the web services and APIs provided by Facebook.
6
+ #
7
+ # As with any software that integrates with the Facebook platform, your use of
8
+ # this software is subject to the Facebook Platform Policy
9
+ # [http://developers.facebook.com/policy/]. This copyright notice shall be
10
+ # included in all copies or substantial portions of the software.
11
+ #
12
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
14
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
16
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
17
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18
+
19
+
20
+ module FacebookAds
21
+ module ServerSide
22
+ class HttpServiceInterface
23
+
24
+ # String url | The graph API endpoint that will be requested
25
+ # String request_method | The HTTP request method
26
+ # Hash headers | Contains HTTP request headers including User-Agent and Accept-Encoding
27
+ # Hash params | Contains request parameters including access_token, data, test_event_code, etc.
28
+ def execute(url, request_method, headers, params)
29
+ raise Exception.new("Method 'execute' not implemented")
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright (c) 2017-present, Facebook, Inc. All rights reserved.
2
+ #
3
+ # You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
4
+ # copy, modify, and distribute this software in source code or binary form for use
5
+ # in connection with the web services and APIs provided by Facebook.
6
+ #
7
+ # As with any software that integrates with the Facebook platform, your use of
8
+ # this software is subject to the Facebook Platform Policy
9
+ # [http://developers.facebook.com/policy/]. This copyright notice shall be
10
+ # included in all copies or substantial portions of the software.
11
+ #
12
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
14
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
16
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
17
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18
+
19
+ module FacebookAds
20
+ module ServerSide
21
+ class HttpUtil
22
+ def self.appsecret_proof(app_secret, access_token)
23
+ OpenSSL::HMAC.hexdigest(
24
+ OpenSSL::Digest.new('sha256'),
25
+ app_secret,
26
+ access_token
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
@@ -16,8 +16,6 @@
16
16
  # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
17
17
  # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18
18
 
19
- require_relative 'util'
20
-
21
19
  module FacebookAds
22
20
  module ServerSide
23
21
 
@@ -93,6 +91,27 @@ module FacebookAds
93
91
  # The subscription ID for the user in this transaction. This is similar to the order ID for an individual product.
94
92
  attr_accessor :subscription_id
95
93
 
94
+ # The lead ID for the user in this transaction. This ID is associated with a lead generated by Facebook's Lead Ads.
95
+ attr_accessor :lead_id
96
+
97
+ # The first 5 letters of the first name.
98
+ attr_accessor :f5first
99
+
100
+ # The first 5 letters of the last name.
101
+ attr_accessor :f5last
102
+
103
+ # The first initial.
104
+ attr_accessor :fi
105
+
106
+ # The date of birth day.
107
+ attr_accessor :dobd
108
+
109
+ # The date of birth month.
110
+ attr_accessor :dobm
111
+
112
+ # THe date of birth year.
113
+ attr_accessor :doby
114
+
96
115
  #UserData is a set of identifiers Facebook can use for targeted attribution
97
116
  # @param [String] email
98
117
  # @param [String] phone
@@ -110,10 +129,18 @@ module FacebookAds
110
129
  # @param [String] fbc
111
130
  # @param [String] fbp
112
131
  # @param [String] subscription_id
132
+ # @param [String] lead_id
133
+ # @param [String] f5first
134
+ # @param [String] f5last
135
+ # @param [String] fi
136
+ # @param [String] dobd
137
+ # @param [String] dobm
138
+ # @param [String] doby
113
139
  def initialize(email: nil, phone: nil, gender: nil, date_of_birth: nil,
114
140
  last_name: nil, first_name: nil, city: nil, state: nil,
115
141
  country_code: nil, zip_code: nil, external_id: nil, client_ip_address: nil,
116
- client_user_agent: nil, fbc: nil, fbp: nil, subscription_id: nil)
142
+ client_user_agent: nil, fbc: nil, fbp: nil, subscription_id: nil, lead_id: nil,
143
+ f5first: nil, f5last: nil, fi: nil, dobd: nil, dobm: nil, doby: nil)
117
144
  unless email.nil?
118
145
  self.email = email
119
146
  end
@@ -162,6 +189,27 @@ module FacebookAds
162
189
  unless subscription_id.nil?
163
190
  self.subscription_id = subscription_id
164
191
  end
192
+ unless lead_id.nil?
193
+ self.lead_id = lead_id
194
+ end
195
+ unless f5first.nil?
196
+ self.f5first = f5first
197
+ end
198
+ unless f5last.nil?
199
+ self.f5last = f5last
200
+ end
201
+ unless fi.nil?
202
+ self.fi = fi
203
+ end
204
+ unless dobd.nil?
205
+ self.dobd = dobd
206
+ end
207
+ unless dobm.nil?
208
+ self.dobm = dobm
209
+ end
210
+ unless doby.nil?
211
+ self.doby = doby
212
+ end
165
213
  end
166
214
 
167
215
  # build the object using the input hash
@@ -232,8 +280,32 @@ module FacebookAds
232
280
  self.fbp = attributes[:'fbp']
233
281
  end
234
282
 
235
- if attributes.has_key?(:'subscription_id')
236
- self.subscription_id = attributes[:'subscription_id']
283
+ if attributes.has_key?(:'lead_id')
284
+ self.lead_id = attributes[:'lead_id']
285
+ end
286
+
287
+ if attributes.has_key?(:'f5first')
288
+ self.f5first = attributes[:'f5first']
289
+ end
290
+
291
+ if attributes.has_key?(:'f5last')
292
+ self.f5last = attributes[:'f5last']
293
+ end
294
+
295
+ if attributes.has_key?(:'fi')
296
+ self.fi = attributes[:'fi']
297
+ end
298
+
299
+ if attributes.has_key?(:'dobd')
300
+ self.dobd = attributes[:'dobd']
301
+ end
302
+
303
+ if attributes.has_key?(:'dobm')
304
+ self.dobm = attributes[:'dobm']
305
+ end
306
+
307
+ if attributes.has_key?(:'doby')
308
+ self.doby = attributes[:'doby']
237
309
  end
238
310
  end
239
311
 
@@ -256,7 +328,14 @@ module FacebookAds
256
328
  client_user_agent == o.client_user_agent &&
257
329
  fbc == o.fbc &&
258
330
  fbp == o.fbp &&
259
- subscription_id == o.subscription_id
331
+ subscription_id == o.subscription_id &&
332
+ lead_id == o.lead_id &&
333
+ f5first == o.f5first &&
334
+ f5last == o.f5last &&
335
+ fi == o.fi &&
336
+ dobd == o.dobd &&
337
+ dobm == o.dobm &&
338
+ doby == o.doby
260
339
  end
261
340
 
262
341
  # @see the `==` method
@@ -283,7 +362,14 @@ module FacebookAds
283
362
  client_user_agent,
284
363
  fbc,
285
364
  fbp,
286
- subscription_id
365
+ subscription_id,
366
+ lead_id,
367
+ f5first,
368
+ f5last,
369
+ fi,
370
+ dobd,
371
+ dobm,
372
+ doby,
287
373
  ].hash
288
374
 
289
375
  end
@@ -340,6 +426,27 @@ module FacebookAds
340
426
  unless subscription_id.nil?
341
427
  hash['subscription_id'] = subscription_id
342
428
  end
429
+ unless lead_id.nil?
430
+ hash['lead_id'] = lead_id
431
+ end
432
+ unless f5first.nil?
433
+ hash['f5first'] = f5first
434
+ end
435
+ unless f5last.nil?
436
+ hash['f5last'] = f5last
437
+ end
438
+ unless fi.nil?
439
+ hash['fi'] = fi
440
+ end
441
+ unless dobd.nil?
442
+ hash['dobd'] = dobd
443
+ end
444
+ unless dobm.nil?
445
+ hash['dobm'] = dobm
446
+ end
447
+ unless doby.nil?
448
+ hash['doby'] = doby
449
+ end
343
450
  hash.to_s
344
451
  end
345
452
 
@@ -348,34 +455,34 @@ module FacebookAds
348
455
  def normalize
349
456
  hash = {}
350
457
  unless email.nil?
351
- hash['em'] = FacebookAds::ServerSide::normalize(email, 'em')
458
+ hash['em'] = FacebookAds::ServerSide::Util.normalize(email, 'em')
352
459
  end
353
460
  unless phone.nil?
354
- hash['ph'] = FacebookAds::ServerSide::normalize(phone, 'ph')
461
+ hash['ph'] = FacebookAds::ServerSide::Util.normalize(phone, 'ph')
355
462
  end
356
463
  unless gender.nil?
357
- hash['ge'] = FacebookAds::ServerSide::normalize(gender, 'ge')
464
+ hash['ge'] = FacebookAds::ServerSide::Util.normalize(gender, 'ge')
358
465
  end
359
466
  unless date_of_birth.nil?
360
- hash['db'] = FacebookAds::ServerSide::normalize(date_of_birth, 'db')
467
+ hash['db'] = FacebookAds::ServerSide::Util.normalize(date_of_birth, 'db')
361
468
  end
362
469
  unless last_name.nil?
363
- hash['ln'] = FacebookAds::ServerSide::normalize(last_name, 'ln')
470
+ hash['ln'] = FacebookAds::ServerSide::Util.normalize(last_name, 'ln')
364
471
  end
365
472
  unless first_name.nil?
366
- hash['fn'] = FacebookAds::ServerSide::normalize(first_name, 'fn')
473
+ hash['fn'] = FacebookAds::ServerSide::Util.normalize(first_name, 'fn')
367
474
  end
368
475
  unless city.nil?
369
- hash['ct'] = FacebookAds::ServerSide::normalize(city, 'ct')
476
+ hash['ct'] = FacebookAds::ServerSide::Util.normalize(city, 'ct')
370
477
  end
371
478
  unless country_code.nil?
372
- hash['country'] = FacebookAds::ServerSide::normalize(country_code, 'country')
479
+ hash['country'] = FacebookAds::ServerSide::Util.normalize(country_code, 'country')
373
480
  end
374
481
  unless state.nil?
375
- hash['st'] = FacebookAds::ServerSide::normalize(state, 'st')
482
+ hash['st'] = FacebookAds::ServerSide::Util.normalize(state, 'st')
376
483
  end
377
484
  unless zip_code.nil?
378
- hash['zp'] = FacebookAds::ServerSide::normalize(zip_code, 'zp')
485
+ hash['zp'] = FacebookAds::ServerSide::Util.normalize(zip_code, 'zp')
379
486
  end
380
487
  unless external_id.nil?
381
488
  hash['external_id'] = external_id
@@ -395,6 +502,27 @@ module FacebookAds
395
502
  unless subscription_id.nil?
396
503
  hash['subscription_id'] = subscription_id
397
504
  end
505
+ unless lead_id.nil?
506
+ hash['lead_id'] = lead_id
507
+ end
508
+ unless f5first.nil?
509
+ hash['f5first'] = FacebookAds::ServerSide::Util.normalize(f5first, 'f5first')
510
+ end
511
+ unless f5last.nil?
512
+ hash['f5last'] = FacebookAds::ServerSide::Util.normalize(f5last, 'f5last')
513
+ end
514
+ unless fi.nil?
515
+ hash['fi'] = FacebookAds::ServerSide::Util.normalize(fi, 'fi')
516
+ end
517
+ unless dobd.nil?
518
+ hash['dobd'] = FacebookAds::ServerSide::Util.normalize(dobd, 'dobd')
519
+ end
520
+ unless dobm.nil?
521
+ hash['dobm'] = FacebookAds::ServerSide::Util.normalize(dobm, 'dobm')
522
+ end
523
+ unless doby.nil?
524
+ hash['doby'] = FacebookAds::ServerSide::Util.normalize(doby, 'doby')
525
+ end
398
526
  hash
399
527
  end
400
528
  end
@@ -19,210 +19,277 @@
19
19
  require 'digest'
20
20
  require 'countries'
21
21
  require 'money'
22
+ require 'time'
22
23
 
23
24
  module FacebookAds
24
25
  module ServerSide
26
+ class Util
27
+ PHONE_NUMBER_IGNORE_CHAR_SET = /[\-\s\(\)]+/
28
+ PHONE_NUMBER_DROP_PREFIX_ZEROS = /^\+?0{0,2}/
29
+ US_PHONE_NUMBER_REGEX = /^1\(?\d{3}\)?\d{7}$/
30
+ INTL_PHONE_NUMBER_REGEX = /^\d{1,4}\(?\d{2,3}\)?\d{4,}$/
31
+
32
+ # RFC 2822 for email format
33
+ EMAIL_REGEX = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
34
+
35
+ # Normalizes the input string given the field_type
36
+ # @param [String] input Input string that needs to be normalized
37
+ # @param [String] field_type Type/Key for the value provided
38
+ # @return [String] Normalized value for the input and field_type.
39
+ def self.normalize(input, field_type)
40
+
41
+ if input.nil? or field_type.nil?
42
+ return nil;
43
+ end
44
+
45
+ input = input.strip.downcase
46
+
47
+ # If the data is already hashed, we by-pass input normalization
48
+ if is_already_hashed?(input) == true
49
+ return input
50
+ end
51
+
52
+ normalized_input = input;
53
+
54
+ case field_type
55
+ when 'country'
56
+ normalized_input = normalize_country input
57
+ when 'ct'
58
+ normalized_input = normalize_city input
59
+ when 'currency'
60
+ return normalize_currency input
61
+ when 'delivery_category'
62
+ return normalize_delivery_category input
63
+ when 'em'
64
+ normalized_input = normalize_email input
65
+ when 'ge'
66
+ normalized_input = normalize_gender input
67
+ when 'ph'
68
+ normalized_input = normalize_phone input
69
+ when 'st'
70
+ normalized_input = normalize_state input
71
+ when 'zp'
72
+ normalized_input = normalize_zip input
73
+ when 'f5first'
74
+ normalized_input = normalize_f5 input
75
+ when 'f5last'
76
+ normalized_input = normalize_f5 input
77
+ when 'fi'
78
+ normalized_input = normalize_fi input
79
+ when 'dobd'
80
+ normalized_input = normalize_dobd input
81
+ when 'dobm'
82
+ normalized_input = normalize_dobm input
83
+ when 'doby'
84
+ normalized_input = normalize_doby input
85
+ end
86
+
87
+ normalized_input = sha256Hash normalized_input
88
+
89
+ return normalized_input
90
+ end
91
+
92
+ # @return [String] SHA 256 hash of input string
93
+ def self.sha256Hash(input)
94
+ unless input.nil?
95
+ Digest::SHA256.hexdigest input
96
+ end
97
+ end
25
98
 
26
- PHONE_NUMBER_IGNORE_CHAR_SET = /[\-\s\(\)]+/
27
- PHONE_NUMBER_DROP_PREFIX_ZEROS = /^\+?0{0,2}/
28
- US_PHONE_NUMBER_REGEX = /^1\(?\d{3}\)?\d{7}$/
29
- INTL_PHONE_NUMBER_REGEX = /^\d{1,4}\(?\d{2,3}\)?\d{4,}$/
99
+ # Boolean method which checks if a input is already hashed with MD5 or SHA256
100
+ # @param [String] input Input string that is to be validated
101
+ # @return [TrueClass|FalseClass] representing whether the value is hashed
102
+ def self.is_already_hashed?(input)
30
103
 
31
- # RFC 2822 for email format
32
- EMAIL_REGEX = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
104
+ # We support Md5 and SHA256, and highly recommend users to use SHA256 for hashing PII keys.
105
+ md5_match = /^[a-f0-9]{32}$/.match(input)
106
+ sha256_match = /^[a-f0-9]{64}$/.match(input)
33
107
 
34
- # @return [String] SHA 256 hash of input string
35
- def self.sha256Hash(input)
36
- unless input.nil?
37
- Digest::SHA256.hexdigest input
108
+ if md5_match != nil or sha256_match != nil
109
+ return true
110
+ end
111
+
112
+ return false
38
113
  end
39
- end
40
114
 
41
- # Normalizes the input string given the field_type
42
- # @param [String] input Input string that needs to be normalized
43
- # @param [String] field_type Type/Key for the value provided
44
- # @return [String] Normalized value for the input and field_type.
45
- def self.normalize(input, field_type)
46
-
47
- if input.nil? or field_type.nil?
48
- return nil;
49
- end
50
-
51
- input = input.strip.downcase
52
-
53
- # If the data is already hashed, we by-pass input normalization
54
- if FacebookAds::ServerSide::is_already_hashed?(input) == true
55
- return input
56
- end
57
-
58
- normalized_input = input;
59
-
60
- case field_type
61
- when 'country'
62
- normalized_input = FacebookAds::ServerSide::normalize_country input
63
- when 'ct'
64
- normalized_input = FacebookAds::ServerSide::normalize_city input
65
- when 'currency'
66
- return FacebookAds::ServerSide::normalize_currency input
67
- when 'em'
68
- normalized_input = FacebookAds::ServerSide::normalize_email input
69
- when 'ge'
70
- normalized_input = FacebookAds::ServerSide::normalize_gender input
71
- when 'ph'
72
- normalized_input = FacebookAds::ServerSide::normalize_phone input
73
- when 'st'
74
- normalized_input = FacebookAds::ServerSide::normalize_state input
75
- when 'zp'
76
- normalized_input = FacebookAds::ServerSide::normalize_zip input
77
- end
78
-
79
- normalized_input = FacebookAds::ServerSide::sha256Hash normalized_input
80
-
81
- return normalized_input
82
- end
115
+ # Normalizes the given country code and returns acceptable hashed country ISO code
116
+ def self.normalize_country(country)
117
+
118
+ # Replace unwanted characters and retain only alpha characters bounded for ISO code.
119
+ country = country.gsub(/[^a-z]/,'')
120
+ iso_country = ISO3166::Country.search(country)
121
+ if iso_country == nil
122
+ raise ArgumentError, "Invalid format for country:'" + country + "'.Please follow ISO 2-letter ISO 3166-1 standard for representing country. eg: us"
123
+ end
83
124
 
84
- # Boolean method which checks if a input is already hashed with MD5 or SHA256
85
- # @param [String] input Input string that is to be validated
86
- # @return [TrueClass|FalseClass] representing whether the value is hashed
87
- def self.is_already_hashed?(input)
125
+ return country
126
+ end
88
127
 
89
- # We support Md5 and SHA256, and highly recommend users to use SHA256 for hashing PII keys.
90
- md5_match = /^[a-f0-9]{32}$/.match(input)
91
- sha256_match = /^[a-f0-9]{64}$/.match(input)
128
+ # Normalizes the given city and returns acceptable hashed city value
129
+ def self.normalize_city(city)
92
130
 
93
- if md5_match != nil or sha256_match != nil
94
- return true
131
+ # Remove commonly occuring characters from city name.
132
+ city = city.gsub(/[0-9.\s\-()]/,'')
133
+
134
+ return city
95
135
  end
96
136
 
97
- return false
98
- end
137
+ # Normalizes the given currency code and returns acceptable hashed currency ISO code
138
+ def self.normalize_currency(currency)
99
139
 
100
- # Normalizes the given country code and returns acceptable hashed country ISO code
101
- def self.normalize_country(country)
140
+ # Retain only alpha characters bounded for ISO code.
141
+ currency = currency.gsub(/[^a-z]/,'')
102
142
 
103
- # Replace unwanted characters and retain only alpha characters bounded for ISO code.
104
- country = country.gsub(/[^a-z]/,'')
105
- iso_country = ISO3166::Country.search(country)
106
- if iso_country == nil
107
- raise ArgumentError, "Invalid format for country:'" + country + "'.Please follow ISO 2-letter ISO 3166-1 standard for representing country. eg: us"
143
+ iso_currency = Money::Currency.find(currency)
144
+ if iso_currency == nil
145
+ raise ArgumentError, "Invalid format for currency:'" + currency + "'.Please follow ISO 3-letter ISO 4217 standard for representing currency. Eg: usd"
146
+ end
147
+
148
+ return currency;
108
149
  end
109
150
 
110
- return country
111
- end
151
+ # Normalizes the given email and returns acceptable hashed email value
152
+ def self.normalize_email(email)
112
153
 
113
- # Normalizes the given city and returns acceptable hashed city value
114
- def self.normalize_city(city)
154
+ if EMAIL_REGEX.match(email) == nil
155
+ return ArgumentError, "Invalid email format for the passed email:' + email + '.Please check the passed email format."
156
+ end
115
157
 
116
- # Remove commonly occuring characters from city name.
117
- city = city.gsub(/[0-9.\s\-()]/,'')
158
+ return email
159
+ end
118
160
 
119
- return city
120
- end
161
+ # Normalizes the given gender and returns acceptable hashed gender value
162
+ def self.normalize_gender(gender)
121
163
 
122
- # Normalizes the given currency code and returns acceptable hashed currency ISO code
123
- def self.normalize_currency(currency)
164
+ # Replace extra characters with space, to bound under alpha characters set.
165
+ gender = gender.gsub(/[^a-z]/,'')
124
166
 
125
- # Retain only alpha characters bounded for ISO code.
126
- currency = currency.gsub(/[^a-z]/,'')
167
+ case gender
168
+ when 'female' , 'f'
169
+ gender = 'f'
170
+ when 'male' , 'm'
171
+ gender = 'm'
172
+ else
173
+ return nil
174
+ end
127
175
 
128
- iso_currency = Money::Currency.find(currency)
129
- if iso_currency == nil
130
- raise ArgumentError, "Invalid format for currency:'" + currency + "'.Please follow ISO 3-letter ISO 4217 standard for representing currency. Eg: usd"
131
- end
176
+ return gender
177
+ end
132
178
 
133
- return currency;
134
- end
179
+ # Normalizes the given phone and returns acceptable hashed phone value
180
+ def self.normalize_phone(phone)
135
181
 
136
- # Normalizes the given email and returns acceptable hashed email value
137
- def self.normalize_email(email)
182
+ # Drop the spaces, hyphen and parenthesis from the Phone Number
183
+ normalized_phone = phone.gsub(PHONE_NUMBER_IGNORE_CHAR_SET, '')
138
184
 
139
- if EMAIL_REGEX.match(email) == nil
140
- return ArgumentError, "Invalid email format for the passed email:' + email + '.Please check the passed email format."
141
- end
185
+ if(is_international_number?(normalized_phone))
186
+ normalized_phone = normalized_phone.gsub(PHONE_NUMBER_DROP_PREFIX_ZEROS, '')
187
+ end
142
188
 
143
- return email
144
- end
189
+ if normalized_phone.length < 7 || normalized_phone.length > 15
190
+ return nil;
191
+ end
145
192
 
146
- # Normalizes the given gender and returns acceptable hashed gender value
147
- def self.normalize_gender(gender)
193
+ return normalized_phone
194
+ end
148
195
 
149
- # Replace extra characters with space, to bound under alpha characters set.
150
- gender = gender.gsub(/[^a-z]/,'')
196
+ # Normalizes the given state and returns acceptable hashed state value
197
+ def self.normalize_state(state)
198
+ state = state.gsub(/[0-9.\s\-()]/,'')
151
199
 
152
- case gender
153
- when 'female' , 'f'
154
- gender = 'f'
155
- when 'male' , 'm'
156
- gender = 'm'
157
- else
158
- return nil
200
+ return state
159
201
  end
160
202
 
161
- return gender
162
- end
203
+ # Normalizes the given zip and returns acceptable hashed zip code value
204
+ def self.normalize_zip(zip)
163
205
 
164
- # Normalizes the given phone and returns acceptable hashed phone value
165
- def self.normalize_phone(phone)
206
+ # Remove spaces from the Postal code
207
+ zip = zip.gsub(/[\s]/,'')
166
208
 
167
- # Drop the spaces, hyphen and parenthesis from the Phone Number
168
- normalized_phone = phone.gsub(PHONE_NUMBER_IGNORE_CHAR_SET, '')
209
+ # If the zip code '-', we retain just the first part alone.
210
+ zip = zip.split('-')[0]
169
211
 
170
- if(FacebookAds::ServerSide::is_international_number?(normalized_phone))
171
- normalized_phone = normalized_phone.gsub(PHONE_NUMBER_DROP_PREFIX_ZEROS, '')
172
- end
212
+ if zip.length < 2
213
+ return nil
214
+ end
173
215
 
174
- if normalized_phone.length < 7 || normalized_phone.length > 15
175
- return nil;
216
+ return zip
176
217
  end
177
218
 
178
- return normalized_phone
179
- end
219
+ # Boolean method which checks if a given number is represented in international format
220
+ # @param [String] phone_number that has to be tested.
221
+ # @return [TrueClass | FalseClass] boolean value representing if a number is international
222
+ def self.is_international_number?(phone_number)
180
223
 
181
- # Normalizes the given city and returns acceptable hashed city value
182
- def self.normalize_state(state)
183
- state = state.gsub(/[0-9.\s\-()]/,'')
224
+ # Drop upto 2 leading 0s from the number
225
+ phone_number = phone_number.gsub(PHONE_NUMBER_DROP_PREFIX_ZEROS, '')
184
226
 
185
- return state
186
- end
227
+ if phone_number.start_with?('0')
228
+ return false;
229
+ end
187
230
 
188
- # Normalizes the given zip and returns acceptable hashed zip code value
189
- def self.normalize_zip(zip)
231
+ if phone_number.start_with?('1') && US_PHONE_NUMBER_REGEX.match(phone_number) != nil
232
+ return false;
233
+ end
190
234
 
191
- # Remove spaces from the Postal code
192
- zip = zip.gsub(/[\s]/,'')
235
+ if INTL_PHONE_NUMBER_REGEX.match(phone_number) != nil
236
+ return true;
237
+ end
193
238
 
194
- # If the zip code '-', we retain just the first part alone.
195
- zip = zip.split('-')[0]
239
+ return false;
240
+ end
196
241
 
197
- if zip.length < 2
198
- return nil
242
+ def self.normalize_f5(input)
243
+ input[0, 5]
199
244
  end
200
245
 
201
- return zip
202
- end
246
+ def self.normalize_fi(fi)
247
+ fi[0, 1]
248
+ end
203
249
 
204
- # Boolean method which checks if a given number is represented in international format
205
- # @param [String] phone_number that has to be tested.
206
- # @return [TrueClass | FalseClass] boolean value representing if a number is international
207
- def self.is_international_number?(phone_number)
250
+ def self.normalize_dobd(dobd)
251
+ if dobd.length == 1
252
+ dobd = '0' + dobd
253
+ end
208
254
 
209
- # Drop upto 2 leading 0s from the number
210
- phone_number = phone_number.gsub(PHONE_NUMBER_DROP_PREFIX_ZEROS, '')
255
+ dobd_int = dobd.to_i
256
+ if dobd.length > 2 or dobd_int < 1 or dobd_int > 31
257
+ raise ArgumentError.new("Invalid dobd format: '#{dobd}'. Please pass in a valid date of birth day in 'DD' format.")
258
+ end
211
259
 
212
- if phone_number.start_with?('0')
213
- return false;
260
+ return dobd
214
261
  end
215
262
 
216
- if phone_number.start_with?('1') && US_PHONE_NUMBER_REGEX.match(phone_number) != nil
217
- return false;
263
+ def self.normalize_dobm(dobm)
264
+ if dobm.length == 1
265
+ dobm = '0' + dobm
266
+ end
267
+
268
+ dobm_int = dobm.to_i
269
+ if dobm.length > 2 or dobm_int < 1 or dobm_int > 12
270
+ raise ArgumentError.new("Invalid dobm format: '#{dobm}'. Please pass in a valid date of birth month in 'MM' format.")
271
+ end
272
+
273
+ return dobm
218
274
  end
219
275
 
220
- if INTL_PHONE_NUMBER_REGEX.match(phone_number) != nil
221
- return true;
276
+ def self.normalize_doby(doby)
277
+ unless doby.match("^[0-9]{4}$")
278
+ raise ArgumentError.new("Invalid doby format: '#{doby}'. Please pass in a valid birth year in 'YYYY' format.")
279
+ end
280
+ doby
222
281
  end
223
282
 
224
- return false;
225
- end
283
+ # Normalizes the input delivery category and returns valid value (or throw exception if invalid).
284
+ def self.normalize_delivery_category(delivery_category)
226
285
 
286
+ unless FacebookAds::ServerSide::DeliveryCategory.include?(delivery_category)
287
+ raise ArgumentError.new("Invalid delivery_category passed: " + delivery_category + ". Please use one of the defined values #{FacebookAds::ServerSide::DeliveryCategory.to_a.join(',')}" )
288
+ end
289
+
290
+ delivery_category;
291
+ end
292
+
293
+ end
227
294
  end
228
295
  end