facebookbusiness 0.7.0.1 → 0.8.0.3

Sign up to get free protection for your applications and to get access to all the features.
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