├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── common ├── TemplateMetaView.py ├── __init__.py ├── doctemplates │ └── html.mako ├── seo_meta.py ├── static │ ├── css │ │ └── base.css │ ├── images │ │ ├── fblogo.png │ │ └── logo.png │ └── scripts │ │ ├── app_config.js │ │ ├── channel.html │ │ ├── fbutils.js │ │ ├── global.js │ │ ├── lib │ │ ├── country_list.js │ │ └── react-selectize.js │ │ └── main.js ├── urls.py ├── utils.py └── views.py ├── common_templates ├── 404.html ├── 500.html ├── __init__.py ├── common │ ├── about.html │ ├── base.html │ ├── error.html │ ├── footer.html │ ├── license.html │ ├── login.html │ └── sample_base.html └── metatemplate.py ├── components ├── __init__.py ├── ad_account_select.py ├── adset_select.py ├── app_select.py ├── autobot │ ├── __init__.py │ └── asset_feed.py ├── bid_component.py ├── budget_input.py ├── budget_type_select.py ├── business_manager_select.py ├── component_form.py ├── country_select.py ├── cta_select.py ├── custom_audience_select.py ├── datetime_picker.py ├── file_input.py ├── image_input.py ├── interest_select.py ├── js_src │ ├── actselect.js │ ├── adset_select.js │ ├── app_info.jsx │ ├── app_select.js │ ├── autobot_asset_feed.js │ ├── autobot_asset_feed_composer.jsx │ ├── basic_selectize.js │ ├── bid_component.js │ ├── bid_composer.jsx │ ├── business_select.js │ ├── caselect.js │ ├── components.js │ ├── datetime_picker.js │ ├── file_input.js │ ├── image_asset_select.jsx │ ├── interest_select.js │ ├── lead_form.js │ ├── lead_form_select.jsx │ ├── page_select.js │ ├── product_catalog_select.js │ ├── product_select.js │ ├── product_set_select.js │ ├── react_modal.jsx │ ├── react_table.jsx │ ├── simple_modal.jsx │ ├── spec_select.js │ ├── spec_select.jsx │ ├── targeting_composer.jsx │ └── targeting_spec.js ├── json_char_field.py ├── lead_form_create.py ├── page_select.py ├── product_catalog_select.py ├── product_select.py ├── product_set_select.py ├── spec_select.py ├── targeting_spec.py ├── templates │ └── components │ │ ├── gallery.html │ │ ├── overview.html │ │ └── overview.md ├── urls.py ├── views.py └── widgets.py ├── dash ├── __init__.py ├── components │ ├── __init__.py │ └── role_select.py ├── management │ ├── __init__.py │ └── commands │ │ ├── __init__.py │ │ └── gensamplemetadata.py ├── migrations │ ├── 0001_initial.py │ ├── 10000_auto_20160602_0605.py │ ├── 9999_auto_samples_metadata.py │ └── __init__.py ├── models.py ├── templates │ └── dash │ │ ├── create_sample.html │ │ ├── delete_sample.html │ │ ├── details_role.html │ │ ├── details_sample.html │ │ ├── list_role.html │ │ └── list_sample.html ├── urls.py └── views │ ├── __init__.py │ ├── role.py │ └── sample.py ├── gulpfile.js ├── manage.py ├── muse ├── __init__.py ├── settings.py ├── urls.py ├── views.py └── wsgi.py ├── package.json ├── requirements.txt ├── samples ├── __init__.py ├── samplecode │ ├── __init__.py │ ├── accountlist.py │ ├── adcreation.py │ ├── ads_reporting.py │ ├── an_optin.py │ ├── app_install_ad.py │ ├── appengagement.py │ ├── autobot_config_editor.py │ ├── carousel_ad.py │ ├── carousel_app_ad.py │ ├── customaudience.py │ ├── instagram_potential.py │ ├── lead_ad.py │ ├── maca_cumulative.py │ ├── maca_frequency.py │ ├── multiple_lal.py │ ├── orderlevelreporting.py │ ├── product_audience_estimation.py │ ├── product_image_check.py │ ├── product_update.py │ ├── targeting.py │ ├── tests │ │ ├── __init__.py │ │ ├── adcreation.py │ │ ├── adimage0.png │ │ ├── adimage1.jpg │ │ ├── adimage2.jpg │ │ ├── adimage3.jpg │ │ ├── an_optin.py │ │ ├── app_install_ad.py │ │ ├── appengagement.py │ │ ├── carousel_ad.py │ │ ├── carousel_app_ad.py │ │ ├── customaudience.py │ │ ├── instagram_potential.py │ │ ├── lead_ad.py │ │ ├── maca_cumulative.py │ │ ├── maca_frequency.py │ │ ├── multiple_lal.py │ │ ├── orderlevelreporting.py │ │ ├── product_audience_estimation.py │ │ ├── product_image_check.py │ │ ├── product_update.py │ │ ├── sampletestcase.py │ │ └── tiered_lookalike.py │ ├── tiered_lookalike.py │ └── utils.py ├── seo_meta.py ├── static │ ├── css │ │ ├── codehilite.css │ │ ├── gallery.css │ │ ├── pdoc.css │ │ └── samples.css │ ├── images │ │ ├── accounts.png │ │ ├── adcreation.png │ │ ├── adsreporting.png │ │ ├── an_optin.png │ │ ├── app_install_ad.png │ │ ├── appengagement.png │ │ ├── autobot.png │ │ ├── ca.png │ │ ├── carousel.png │ │ ├── carousel_title.png │ │ ├── carouselappad.png │ │ ├── carouselappad_title.jpg │ │ ├── instagram_potential.png │ │ ├── lead_ad.png │ │ ├── maca_cumulative.png │ │ ├── maca_frequency.png │ │ ├── multiple_lal.png │ │ ├── product_audience_est.png │ │ ├── productimagecheck.png │ │ ├── productupdate.png │ │ ├── targeting.png │ │ └── tiered_lookalike.png │ └── scripts │ │ └── sample.js ├── templates │ └── samples │ │ ├── accountlist.html │ │ ├── ad_set_list.html │ │ ├── ads_reporting_form.html │ │ ├── autbot_config_editor_form.html │ │ ├── caform.html │ │ ├── index.html │ │ ├── order_level_report.footer.csv │ │ ├── order_level_report.footer.html │ │ ├── order_level_report.footer.xls │ │ ├── order_level_report.header.csv │ │ ├── order_level_report.header.html │ │ ├── order_level_report.header.xls │ │ ├── order_level_report.row.csv │ │ ├── order_level_report.row.html │ │ ├── order_level_report.row.xls │ │ ├── product_audience_estimation_form.html │ │ ├── product_image_check.html │ │ └── sample_form.html ├── urls.py └── views │ ├── __init__.py │ ├── accountlist.py │ ├── adcreation.py │ ├── ads_reporting.py │ ├── an_optin.py │ ├── app_install_ad.py │ ├── appengagement.py │ ├── autobot_config_editor.py │ ├── carousel_ad.py │ ├── carousel_app_ad.py │ ├── customaudience.py │ ├── instagram_potential.py │ ├── lead_ad.py │ ├── maca_cumulative.py │ ├── maca_frequency.py │ ├── multiple_lal.py │ ├── orderlevelreporting.py │ ├── product_audience_estimation.py │ ├── product_image_check.py │ ├── product_update.py │ ├── sample.py │ ├── targeting.py │ └── tiered_lookalike.py └── security ├── __init__.py ├── fbsample.py ├── middleware.py ├── migrations ├── 0001_initial.py ├── 0002_role.py ├── 0003_auto_20160602_0605.py └── __init__.py ├── models.py ├── role.py ├── urls.py └── views.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | *.pyc 4 | *.sqlite3 5 | *.log 6 | docs/templates/php.html 7 | *.swp 8 | *.swo 9 | staticfiles 10 | components/static/scripts/components/* 11 | node_modules 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Facebook Marketing API Samples 2 | We want to make contributing to this project as easy and transparent as 3 | possible. 4 | 5 | ## Our Development Process 6 | We will be pushing changes to this framework and add new use case samples. 7 | We will also be monitoring pull requests for bugs and samples contributed from 8 | the community and merge them in the updates. 9 | 10 | ## Pull Requests 11 | We actively welcome your pull requests. 12 | 13 | 1. Fork the repo and create your branch from `master`. 14 | 2. If you've added code that should be tested, add tests. 15 | 3. If you've changed APIs, update the documentation. 16 | 4. Ensure the test suite passes. 17 | 5. Make sure your code lints. 18 | 6. If you haven't already, complete the Contributor License Agreement ("CLA"). 19 | 20 | ## Contributor License Agreement ("CLA") 21 | In order to accept your pull request, we need you to submit a CLA. You only need 22 | to do this once to work on any of Facebook's open source projects. 23 | 24 | Complete your CLA here: 25 | 26 | ## Issues 27 | We use GitHub issues to track public bugs. Please ensure your description is 28 | clear and has sufficient instructions to be able to reproduce the issue. 29 | 30 | Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe 31 | disclosure of security bugs. In those cases, please go through the process 32 | outlined on that page and do not file a public issue. 33 | 34 | ## Coding Style 35 | * 4 spaces for indentation rather than tabs 36 | * 80 character line length 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-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 Developer Principles and Policies 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 | -------------------------------------------------------------------------------- /common/TemplateMetaView.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django.views.generic import TemplateView 22 | from seo_meta import meta 23 | 24 | 25 | class TemplateMetaView(TemplateView): 26 | # override these parameters at urls.py 27 | seo_title = 'Facebook Marketing API Accelerator' 28 | seo_description = 'The Facebook Marketing API Accelerator is your path ' \ 29 | 'to serious ads API skills and significant ' \ 30 | 'technical developer support.' 31 | seo_image = '/static/images/fmd.jpg' 32 | 33 | def get_context_data(self, **kwargs): 34 | # Call the base implementation first to get a context 35 | context = super(TemplateMetaView, self).get_context_data(**kwargs) 36 | 37 | meta.title = self.seo_title 38 | meta.description = self.seo_description 39 | meta.image = self.seo_image 40 | context['meta'] = meta 41 | 42 | return context 43 | -------------------------------------------------------------------------------- /common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/common/__init__.py -------------------------------------------------------------------------------- /common/seo_meta.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from meta.views import Meta 22 | from django.conf import settings 23 | 24 | meta = Meta( 25 | title="Facebook Marketing API Accelerator", 26 | description="The Facebook Marketing API Accelerator is your path to " 27 | "serious ads API skills and significant technical developer " 28 | "support.", 29 | keywords=[ 30 | 'facebook marketing api', 31 | 'facebook ads api', 32 | 'ads api', 33 | 'marketing automation', 34 | 'ads api samples', 35 | 'marketing api samples' 36 | ], 37 | use_og=True, 38 | use_twitter=True, 39 | use_facebook=True, 40 | facebook_app_id=settings.FACEBOOK_APP_ID, 41 | site_name="Facebook Marketing Developers", 42 | twitter_site='@fbplatform', 43 | twitter_card='summary_large_image', 44 | image='/static/images/fmd.jpg', 45 | ) 46 | -------------------------------------------------------------------------------- /common/static/images/fblogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/common/static/images/fblogo.png -------------------------------------------------------------------------------- /common/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/common/static/images/logo.png -------------------------------------------------------------------------------- /common/static/scripts/app_config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 3 | * 4 | * You are hereby granted a non-exclusive, worldwide, royalty-free license to 5 | * use, copy, modify, and distribute this software in source code or binary 6 | * form for use in connection with the web services and APIs provided by 7 | * Facebook. 8 | * 9 | * As with any software that integrates with the Facebook platform, your use 10 | * of this software is subject to the Facebook Developer Principles and 11 | * Policies [http://developers.facebook.com/policy/]. This copyright notice 12 | * shall be included in all copies or substantial portions of the software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE 21 | */ 22 | 23 | // app configuration options 24 | 'use strict'; 25 | /*global define*/ 26 | 27 | define(function() { 28 | return { 29 | channelUrl: '/static/common/scripts/channel.html', 30 | fbAppId: window.app_config.fbAppId, 31 | }; 32 | }); 33 | -------------------------------------------------------------------------------- /common/static/scripts/channel.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /common/static/scripts/global.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 3 | * 4 | * You are hereby granted a non-exclusive, worldwide, royalty-free license to 5 | * use, copy, modify, and distribute this software in source code or binary 6 | * form for use in connection with the web services and APIs provided by 7 | * Facebook. 8 | * 9 | * As with any software that integrates with the Facebook platform, your use 10 | * of this software is subject to the Facebook Developer Principles and 11 | * Policies [http://developers.facebook.com/policy/]. This copyright notice 12 | * shall be included in all copies or substantial portions of the software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE 21 | */ 22 | 23 | 'use strict'; 24 | /*global window*/ 25 | window.require = { 26 | baseUrl: '/static/scripts', 27 | paths: { 28 | // External libraries 29 | 'facebook': '//connect.facebook.net/en_US/sdk', 30 | 'jquery': '//ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min', 31 | 'bootstrap': '//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min', 32 | 'jasny-bootstrap': '//cdnjs.cloudflare.com/ajax/libs/jasny-bootstrap/3.1.3/js/jasny-bootstrap.min', 33 | 'datetimepicker': 34 | '//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.15.35/js/bootstrap-datetimepicker.min', 35 | 'moment': '//cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.3/moment.min', 36 | 'selectize': '//cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.2/js/standalone/selectize.min', 37 | 'react': '//cdnjs.cloudflare.com/ajax/libs/react/0.13.3/react.min', 38 | // Paths 39 | 'components': '/static/scripts/components', 40 | 'samples': '/static/samples/scripts', 41 | // Local libraries 42 | 'country_list': 'lib/country_list', 43 | 'react-selectize': 'lib/react-selectize', 44 | }, 45 | shim: { 46 | 'facebook': { 47 | exports: 'FB' 48 | }, 49 | 'bootstrap': { 50 | deps: ['jquery'] 51 | }, 52 | 'jasny-bootstrap': { 53 | deps: ['bootstrap'] 54 | }, 55 | 'selectize': { 56 | deps: ['jquery'] 57 | }, 58 | 'datetimepicker': { 59 | deps: ['moment', 'jquery'] 60 | }, 61 | 'react-selectize': { 62 | deps: ['react', 'selectize'] 63 | } 64 | }, 65 | deps: ['main'], 66 | }; 67 | -------------------------------------------------------------------------------- /common/urls.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django.conf.urls import url, include 22 | from common import views 23 | 24 | urlpatterns = [ 25 | ] 26 | -------------------------------------------------------------------------------- /common/views.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | -------------------------------------------------------------------------------- /common_templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | {% block title %} 3 | Oops ! - Facebook Marketing Developers 4 | {% endblock %} 5 | {% block body_block %} 6 |
7 |
8 |

Sorry, this page isn't available.

9 |
10 |

You can fix your URL to retry, or try some sweet samples.

11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /common_templates/500.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | {% block title %} 3 | Oops ! - Facebook Marketing Developers 4 | {% endblock %} 5 | {% block body_block %} 6 |
7 |
8 |

Oops, something bad just happened.

9 |
10 |

Logs have been recorded for investigation and fixing. Please try this later.

11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /common_templates/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/common_templates/__init__.py -------------------------------------------------------------------------------- /common_templates/common/about.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | 3 | {% block body_block %} 4 |
5 | {{ readme|safe }} 6 |
7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /common_templates/common/error.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 |
3 | {% block body_block %} 4 |
5 |
6 |

Something went wrong

7 | {{ message }} 8 |
9 |
10 | {% endblock %} 11 |
12 | -------------------------------------------------------------------------------- /common_templates/common/footer.html: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /common_templates/common/license.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | {% block seo_meta_tags %} 3 | Facebook Marketing Developers: Sample Code License 4 | {% endblock %} 5 | {% block base_container %} 6 | 7 |
8 |
9 |
10 |

11 | Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 12 |

13 |

14 | You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 15 | copy, modify, and distribute this software in source code or binary form for use 16 | in connection with the web services and APIs provided by Facebook. 17 |

18 |

19 | As with any software that integrates with the Facebook platform, your use of 20 | this software is subject to the 21 | Facebook Developer Principles and Policies. This copyright notice shall be 22 | included in all copies or substantial portions of the software. 23 |

24 |

25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 27 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 28 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 29 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 |

32 |
33 |
34 |
35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /common_templates/common/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | {% block title %} 3 | Ads API Samples - Login 4 | {% endblock %} 5 | 6 | {% block base_container %} 7 |
8 |
9 |
10 | 24 |
25 |
26 |
27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /common_templates/metatemplate.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | # Empty meta 22 | meta = {} 23 | -------------------------------------------------------------------------------- /components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/components/__init__.py -------------------------------------------------------------------------------- /components/ad_account_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django import forms 22 | from widgets import SelectizeWidget, SelectizeMultiWidget 23 | 24 | 25 | class AdAccountSelect(forms.CharField): 26 | """ 27 | Ad Account select component. It loads the user's ad accounts via AJAX and 28 | populate the select options. 29 | """ 30 | 31 | DEFAULT_CHOICES = [('', '- Choose an ad account -')] 32 | 33 | def __init__( 34 | self, 35 | id='id_act_select', 36 | multiple=False, 37 | *args, 38 | **kwargs 39 | ): 40 | super(AdAccountSelect, self).__init__(*args, **kwargs) 41 | 42 | self.id = id 43 | 44 | args = {'attrs': { 45 | 'id': self.id, 46 | 'js_module': 'actselect', 47 | 'js_class': 'ActSelect', 48 | }, 49 | 'choices': self.DEFAULT_CHOICES 50 | } 51 | 52 | self.widget = SelectizeMultiWidget(**args) if multiple \ 53 | else SelectizeWidget(**args) 54 | -------------------------------------------------------------------------------- /components/adset_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django import forms 22 | from widgets import SelectizeWidget 23 | 24 | 25 | class AdSetSelect(forms.CharField): 26 | """ 27 | Component for selectin Ad Sets on an Ad account. It listens to the 28 | ad account select component for the selected ad account, and loads 29 | the ad sets for that account via AJAX and populate the select 30 | options. 31 | """ 32 | DEFAULT_CHOICES = [('', '- Choose an Ad Set -')] 33 | 34 | def __init__( 35 | self, 36 | id='id_adset_select', 37 | id_act_select='id_act_select', 38 | *args, 39 | **kwargs 40 | ): 41 | super(AdSetSelect, self).__init__(*args, **kwargs) 42 | 43 | self.id = id 44 | self.id_act_select = id_act_select 45 | if not self.help_text: 46 | self.help_text = ("Choose an ad account before using.") 47 | 48 | self.widget = SelectizeWidget( 49 | attrs={ 50 | 'id': self.id, 51 | 'js_params': [id_act_select], 52 | 'js_module': 'adset_select', 53 | 'js_class': 'AdSetSelect' 54 | }, 55 | choices=self.DEFAULT_CHOICES, 56 | ) 57 | -------------------------------------------------------------------------------- /components/app_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from widgets import ReactModalWidget 22 | from json_char_field import JsonCharField 23 | 24 | 25 | class AppSelect(JsonCharField): 26 | """ 27 | Component for selecting application. It renders a button on the input that 28 | triggers a pop up window to let user select an application that they own, 29 | and return a JSON string about the selected app that goes like this: 30 | 31 | { 32 | "id": "12345", 33 | "name": "My Android App", 34 | "url": "https://www.facebook.com/games/?app_id=12345", 35 | "picture": "https://someimagehost.com/your.png", 36 | "supported_platforms": [6], 37 | "native_app_store_ids": { 38 | "6": "com.my.app" 39 | }, 40 | "object_store_urls": { 41 | "google_play": 42 | "http://play.google.com/store/apps/details?id=com.my.app" 43 | } 44 | } 45 | """ 46 | 47 | def __init__( 48 | self, 49 | id='id_app_select', 50 | id_act_select='id_act_select', 51 | *args, 52 | **kwargs 53 | ): 54 | super(AppSelect, self).__init__(*args, **kwargs) 55 | 56 | if not self.help_text: 57 | self.help_text = ("Choose an ad account before using. Changing " + 58 | "ad account will reset the selection.") 59 | 60 | self.id = id 61 | self.widget = ReactModalWidget(attrs={ 62 | 'id': self.id, 63 | 'js_module': 'app_select', 64 | 'js_class': 'AppSelect', 65 | 'js_params': [id_act_select], 66 | 'icon': "glyphicon glyphicon-plus" 67 | }) 68 | -------------------------------------------------------------------------------- /components/autobot/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/components/autobot/__init__.py -------------------------------------------------------------------------------- /components/autobot/asset_feed.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015, Facebook, Inc. 2 | # 3 | # All rights reserved. 4 | # 5 | # This source code is licensed under the BSD-style license found in the 6 | # LICENSE file in the root directory of this source tree. An additional grant 7 | # of patent rights can be found in the PATENTS file in the same directory. 8 | 9 | from components.widgets import ReactModalWidget 10 | from components.json_char_field import JsonCharField 11 | 12 | 13 | class AssetFeed(JsonCharField): 14 | """ 15 | AssetFeed subsection 16 | """ 17 | 18 | """ 19 | Some sample asset feed specs 20 | """ 21 | ASSET_FEED_DEFAULT = { 22 | "default": { 23 | "descriptions": [{"text": "Description"}, ], 24 | "titles": [{"text": "Title"}, ], 25 | "ad_formats": ["SINGLE_IMAGE"], 26 | "bodies": [{"text": "Body"}, ], 27 | "images": [{"hash": "6c97ef2c81b383ae3624301b0b126a5a"}, ] 28 | } 29 | } 30 | 31 | def __init__( 32 | self, 33 | id='id_creative', 34 | id_act_select='id_act_select', 35 | id_platform_select='id_platform_select', 36 | *args, 37 | **kwargs 38 | ): 39 | super(AssetFeed, self).__init__(*args, **kwargs) 40 | 41 | self.id = id 42 | if not self.help_text: 43 | self.help_text = ("Choose an ad account before using. Changing " + 44 | "ad account will reset the current spec.") 45 | 46 | self.widget = ReactModalWidget(attrs={ 47 | 'id': self.id, 48 | 'js_params': [id_act_select, id_platform_select], 49 | 'icon': "glyphicon glyphicon-plus", 50 | 'js_module': 'autobot_asset_feed', 51 | 'js_class': 'AssetFeed', 52 | 'data-toggle': 'tooltip', 53 | 'title': 'Choose an ad account before using.', 54 | }) 55 | -------------------------------------------------------------------------------- /components/bid_component.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django import forms 22 | from django.forms import widgets 23 | from widgets import ReactModalWidget 24 | 25 | 26 | class BidWidget(widgets.MultiWidget): 27 | 28 | def decompress(self, value): 29 | return ['', '', 100] 30 | 31 | 32 | class BidComponent(forms.MultiValueField): 33 | """ 34 | Component for setting your bids. The component will have a button to open a 35 | popup window where you can input your optimization goal, billing event and 36 | bid amount. The output of this component will be a JSON object. 37 | """ 38 | 39 | # Constants for list access 40 | ID_OPTIMIZATION_GOAL = 0 41 | ID_BILLING_EVENT = 1 42 | ID_BID_AMOUNT = 2 43 | 44 | def __init__( 45 | self, 46 | field_name, 47 | objective='', 48 | id='id_bid_component', 49 | *args, 50 | **kwargs 51 | ): 52 | fields = [ 53 | forms.CharField(), 54 | forms.CharField(), 55 | forms.CharField() 56 | ] 57 | super(BidComponent, self).__init__(fields=fields, *args, **kwargs) 58 | 59 | self.id = id 60 | if not self.help_text: 61 | self.help_text = ("Click to open dialog for bidding options.") 62 | 63 | optimization_goal = forms.HiddenInput() 64 | billing_event = forms.HiddenInput() 65 | bid_amount = forms.HiddenInput() 66 | widgets = [ 67 | optimization_goal, 68 | billing_event, 69 | bid_amount, 70 | ReactModalWidget(attrs={ 71 | 'id': self.id, 72 | 'js_params': [field_name, objective], 73 | 'icon': "glyphicon glyphicon-plus", 74 | 'js_module': 'bid_component', 75 | 'js_class': 'BidComponent', 76 | }) 77 | ] 78 | self.widget = BidWidget(widgets=widgets) 79 | 80 | def compress(self, values): 81 | return values 82 | -------------------------------------------------------------------------------- /components/budget_input.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django import forms 22 | 23 | 24 | class BudgetInput(forms.IntegerField): 25 | 26 | def __init__( 27 | self, 28 | id='id_budget_input', 29 | *args, 30 | **kwargs 31 | ): 32 | super(BudgetInput, self).__init__(*args, **kwargs) 33 | 34 | self.id = id 35 | self.initial = 1000 36 | 37 | self.widget = forms.TextInput( 38 | attrs={'id': self.id} 39 | ) 40 | -------------------------------------------------------------------------------- /components/budget_type_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django import forms 22 | from widgets import SelectizeWidget 23 | 24 | 25 | class BudgetTypeSelect(forms.CharField): 26 | """ 27 | Basic budget type select component that makes use of the selectize widget. 28 | """ 29 | 30 | DEFAULT_CHOICES = ( 31 | ('', '- Choose a budget type -'), 32 | ('daily_budget', 'Daily budget'), 33 | ('lifetime_budget', 'Lifetime budget'), 34 | ) 35 | 36 | def __init__( 37 | self, 38 | id='id_budget_type_select', 39 | *args, 40 | **kwargs 41 | ): 42 | super(BudgetTypeSelect, self).__init__(*args, **kwargs) 43 | 44 | self.id = id 45 | 46 | self.widget = SelectizeWidget( 47 | attrs={'id': self.id}, 48 | choices=self.DEFAULT_CHOICES, 49 | ) 50 | -------------------------------------------------------------------------------- /components/business_manager_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django import forms 22 | from widgets import SelectizeWidget 23 | 24 | 25 | class BusinessManagerSelect(forms.CharField): 26 | """ 27 | Component for selecting Business Manager. It loads the user's business 28 | managers via AJAX and populate the select options. 29 | """ 30 | 31 | DEFAULT_CHOICES = [('', '- Choose a business manager -')] 32 | 33 | def __init__( 34 | self, 35 | id='id_business_select', 36 | *args, 37 | **kwargs 38 | ): 39 | super(BusinessManagerSelect, self).__init__(*args, **kwargs) 40 | 41 | self.id = id 42 | self.widget = SelectizeWidget( 43 | attrs={ 44 | 'id': self.id, 45 | 'js_module': 'business_select', 46 | 'js_class': 'BusinessSelect', 47 | }, 48 | choices=self.DEFAULT_CHOICES 49 | ) 50 | -------------------------------------------------------------------------------- /components/cta_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django import forms 22 | from widgets import SelectizeWidget 23 | 24 | 25 | class CTASelect(forms.CharField): 26 | """ 27 | Call To Action select component that makes use of the selectize widget. 28 | It contains a dropdown list of CTA types. 29 | Find all CTA types at: 30 | https://developers.facebook.com/docs/marketing-api/unpublished-page-posts/v2.5#cta-spec 31 | """ 32 | DEFAULT_CHOICES = [ 33 | ('NO_BUTTON', 'NO BUTTON'), 34 | ('BOOK_TRAVEL', 'BOOK TRAVEL'), 35 | ('BUY_NOW', 'BUY NOW'), 36 | ('CALL_NOW', 'CALL NOW'), 37 | ('DOWNLOAD', 'DOWNLOAD'), 38 | ('GET_DIRECTIONS', 'GET DIRECTIONS'), 39 | ('GET_QUOTE', 'GET QUOTE'), 40 | ('INSTALL_APP', 'INSTALL APP'), 41 | ('LEARN_MORE', 'LEARN MORE'), 42 | ('LIKE_PAGE', 'LIKE PAGE'), 43 | ('PLAY_GAME', 'PLAY GAME'), 44 | ('SHOP_NOW', 'SHOP NOW'), 45 | ('SIGN_UP', 'SIGN UP'), 46 | ('SUBSCRIBE', 'SUBSCRIBE'), 47 | ('USE_APP', 'USE APP'), 48 | ('WATCH_VIDEO', 'WATCH VIDEO'), 49 | ] 50 | 51 | def __init__( 52 | self, 53 | id='cta_select', 54 | *args, 55 | **kwargs 56 | ): 57 | super(CTASelect, self).__init__(*args, **kwargs) 58 | self.id = id 59 | self.widget = SelectizeWidget( 60 | attrs={ 61 | 'id': self.id, 62 | }, 63 | choices=self.DEFAULT_CHOICES, 64 | ) 65 | -------------------------------------------------------------------------------- /components/custom_audience_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django import forms 22 | from widgets import SelectizeWidget 23 | 24 | 25 | class CustomAudienceSelect(forms.CharField): 26 | """ 27 | Component for selecting custom audiences select . It listens to the ad 28 | account select component for the selected account id and loads the custom 29 | audiences for that account via AJAX and populate the select options. 30 | """ 31 | DEFAULT_CHOICES = [('', '- Choose a custom audience -')] 32 | 33 | def __init__( 34 | self, 35 | id='id_ca_select', 36 | id_act_select='id_act_select', 37 | *args, 38 | **kwargs 39 | ): 40 | super(CustomAudienceSelect, self).__init__(*args, **kwargs) 41 | 42 | self.id = id 43 | if not self.help_text: 44 | self.help_text = ("Choose an ad account before using.") 45 | 46 | self.widget = SelectizeWidget( 47 | attrs={ 48 | 'id': self.id, 49 | 'js_params': [id_act_select], 50 | 'js_module': 'caselect', 51 | 'js_class': 'CaSelect', 52 | }, 53 | choices=self.DEFAULT_CHOICES, 54 | ) 55 | -------------------------------------------------------------------------------- /components/datetime_picker.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django.forms import DateTimeField 22 | from widgets import DatetimePickerWidget 23 | 24 | 25 | class DatetimePicker(DateTimeField): 26 | """ 27 | A user friendly date time picker component, using the [bootstrap datetime 28 | picker plugin][1]. 29 | You can specify your custom datetime format that the plugin shows by setting 30 | the `datetime_format` variable. For the datetime formats see the [custom 31 | formats][2] 32 | 33 | [1]: https://eonasdan.github.io/bootstrap-datetimepicker/ 34 | [2]: https://eonasdan.github.io/bootstrap-datetimepicker/#custom-formats 35 | """ 36 | 37 | def __init__( 38 | self, 39 | id='id_datetime', 40 | datetime_format='YYYY-MM-DD HH:mm', 41 | min_date=None, 42 | max_date=None, 43 | *args, 44 | **kwargs 45 | ): 46 | super(DatetimePicker, self).__init__(*args, **kwargs) 47 | 48 | js_params = [datetime_format] 49 | if min_date is not None: 50 | js_params.append(min_date) 51 | if max_date is not None: 52 | js_params.append(max_date) 53 | self.id = id 54 | self.widget = DatetimePickerWidget(attrs={ 55 | 'id': self.id, 56 | 'js_params': js_params, 57 | 'js_module': 'datetime_picker', 58 | 'js_class': 'DatetimePicker', 59 | }) 60 | -------------------------------------------------------------------------------- /components/file_input.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django.forms import FileField 22 | from widgets import FileWidget 23 | 24 | 25 | class FileInput(FileField): 26 | """ 27 | File upload component that's more consistent with the rest of bootstrap, 28 | using this [bootstrap file input plugin][1]. 29 | The data file uploaded will be available at `form.cleaned_data[id]` 30 | 31 | [1]: http://www.jasny.net/bootstrap/javascript/#fileinput 32 | """ 33 | 34 | def __init__( 35 | self, 36 | id='id_data_file', 37 | *args, 38 | **kwargs 39 | ): 40 | super(FileInput, self).__init__(*args, **kwargs) 41 | 42 | self.id = id 43 | self.widget = FileWidget(attrs={ 44 | 'id': self.id, 45 | 'js_module': 'file_input', 46 | 'js_class': 'FileInput', 47 | }) 48 | -------------------------------------------------------------------------------- /components/image_input.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django.forms import FileField 22 | from widgets import ImageFileWidget 23 | 24 | 25 | class ImageInput(FileField): 26 | """ 27 | File upload component that's more consistent with the rest of bootstrap, 28 | using this [bootstrap file input plugin][1]. 29 | The data file uploaded will be available at `form.cleaned_data[id]` 30 | 31 | [1]: http://www.jasny.net/bootstrap/javascript/#fileinput 32 | """ 33 | 34 | def __init__( 35 | self, 36 | id='id_image_file', 37 | width='200px', 38 | height='130px', 39 | *args, 40 | **kwargs 41 | ): 42 | super(ImageInput, self).__init__(*args, **kwargs) 43 | 44 | self.id = id 45 | self.widget = ImageFileWidget(attrs={ 46 | 'id': self.id, 47 | 'width': width, 48 | 'height': height, 49 | 'js_module': 'file_input', 50 | 'js_class': 'ImageFileInput', 51 | }) 52 | -------------------------------------------------------------------------------- /components/interest_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016, Facebook, Inc. 2 | # 3 | # All rights reserved. 4 | # 5 | # This source code is licensed under the BSD-style license found in the 6 | # LICENSE file in the root directory of this source tree. An additional grant 7 | # of patent rights can be found in the PATENTS file in the same directory. 8 | 9 | from django import forms 10 | from widgets import SelectizeWidget, SelectizeMultiWidget 11 | 12 | 13 | class InterestSelect(forms.CharField): 14 | """ 15 | Interest targeting select component. It loads the interests via AJAX 16 | and populates the select options. 17 | """ 18 | 19 | DEFAULT_CHOICES = [('', '- Choose interest(s) -')] 20 | 21 | def __init__( 22 | self, 23 | id='id_interest_select', 24 | id_app_select='id_app_select', 25 | multiple=True, 26 | *args, 27 | **kwargs 28 | ): 29 | super(InterestSelect, self).__init__(*args, **kwargs) 30 | 31 | self.id = id 32 | 33 | args = {'attrs': { 34 | 'id': self.id, 35 | 'js_params': [id_app_select], 36 | 'js_module': 'interest_select', 37 | 'js_class': 'InterestSelect', 38 | }, 39 | 'choices': self.DEFAULT_CHOICES 40 | } 41 | 42 | self.widget = SelectizeMultiWidget(**args) if multiple \ 43 | else SelectizeWidget(**args) 44 | -------------------------------------------------------------------------------- /components/js_src/basic_selectize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 3 | * 4 | * You are hereby granted a non-exclusive, worldwide, royalty-free license to 5 | * use, copy, modify, and distribute this software in source code or binary 6 | * form for use in connection with the web services and APIs provided by 7 | * Facebook. 8 | * 9 | * As with any software that integrates with the Facebook platform, your use 10 | * of this software is subject to the Facebook Developer Principles and 11 | * Policies [http://developers.facebook.com/policy/]. This copyright notice 12 | * shall be included in all copies or substantial portions of the software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE 21 | */ 22 | 23 | /* 24 | Use this module if you just need the look and feel of selectize. Use it together 25 | with SelectizeWidget to make your life easier. Define you own JS module and code 26 | the behavior if you need dynamic loading of options or more complex stuff. Refer 27 | to caselect.js module is a good start. 28 | */ 29 | 'use strict'; 30 | /* global define */ 31 | define(['jquery', 'selectize'], function($, selectize) { 32 | 33 | // Takes in the DOM id for the target select element. 34 | var initialize = function(targetElementId, initialValues) { 35 | var targetId = '#' + targetElementId; 36 | var initValues = []; 37 | if (typeof initialValues === 'string') { 38 | if (initialValues.indexOf(',') > 0) { 39 | initValues = initialValues.split(','); 40 | } else { 41 | initValues = [initialValues]; 42 | } 43 | } 44 | $(targetId).ready(function() { 45 | $(targetId).selectize(); 46 | initValues.forEach(function(value) { 47 | if (value in $(targetId)[0].selectize.options) { 48 | $(targetId)[0].selectize.addItem(value); 49 | } 50 | }); 51 | }); 52 | }; 53 | 54 | return { 55 | initialize: initialize, 56 | }; 57 | }); 58 | -------------------------------------------------------------------------------- /components/js_src/components.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 3 | * 4 | * You are hereby granted a non-exclusive, worldwide, royalty-free license to 5 | * use, copy, modify, and distribute this software in source code or binary 6 | * form for use in connection with the web services and APIs provided by 7 | * Facebook. 8 | * 9 | * As with any software that integrates with the Facebook platform, your use 10 | * of this software is subject to the Facebook Developer Principles and 11 | * Policies [http://developers.facebook.com/policy/]. This copyright notice 12 | * shall be included in all copies or substantial portions of the software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE 21 | */ 22 | 23 | 'use strict'; 24 | /*global define*/ 25 | define(['jquery'], function($) { 26 | var _decodeHTML = function(input) { 27 | return $('
').html(input).text(); 28 | }; 29 | 30 | var initialize = function() { 31 | var args = Array.prototype.slice.call(arguments); 32 | // First argument is always the module name 33 | var componentModule = args.shift(); 34 | var decodedArgs = args.map(function(argument) { 35 | return _decodeHTML(argument); 36 | }); 37 | // Dynamically load the component module and call the intiialize function 38 | // with sanitized arguments 39 | require([componentModule], function(componentClass) { 40 | componentClass.initialize.apply(this, decodedArgs); 41 | }); 42 | }; 43 | return { 44 | initialize: initialize, 45 | }; 46 | }); 47 | -------------------------------------------------------------------------------- /components/js_src/datetime_picker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 3 | * 4 | * You are hereby granted a non-exclusive, worldwide, royalty-free license to 5 | * use, copy, modify, and distribute this software in source code or binary 6 | * form for use in connection with the web services and APIs provided by 7 | * Facebook. 8 | * 9 | * As with any software that integrates with the Facebook platform, your use 10 | * of this software is subject to the Facebook Developer Principles and 11 | * Policies [http://developers.facebook.com/policy/]. This copyright notice 12 | * shall be included in all copies or substantial portions of the software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE 21 | */ 22 | 23 | /* 24 | Reference: https://github.com/Eonasdan/bootstrap-datetimepicker 25 | */ 26 | 'use strict'; 27 | /* global define */ 28 | define(['jquery', 'datetimepicker'], function($, datetimepicker) { 29 | 30 | // Takes in the DOM id for the ad account select. 31 | var initialize = function( 32 | datetimePickerElementId, 33 | initialValue, 34 | datetimeFormat, 35 | minDate, 36 | maxDate 37 | ) { 38 | var picker = { 39 | format: datetimeFormat, 40 | }; 41 | if (typeof minDate !== 'undefined') { 42 | picker.minDate = minDate; 43 | } 44 | if (typeof maxDate !== 'undefined') { 45 | picker.maxDate = maxDate; 46 | } 47 | var datetimePickerId = '#' + datetimePickerElementId; 48 | $(datetimePickerId).ready(function() { 49 | $(datetimePickerId).datetimepicker(picker); 50 | 51 | var datetimePickerDivId = '#' + datetimePickerElementId + '_pickers'; 52 | $(datetimePickerDivId).find('span.input-group-addon').click(function(e) { 53 | $(datetimePickerId).focus(); 54 | }); 55 | }); 56 | }; 57 | 58 | return { 59 | initialize: initialize, 60 | }; 61 | }); 62 | -------------------------------------------------------------------------------- /components/js_src/file_input.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 3 | * 4 | * You are hereby granted a non-exclusive, worldwide, royalty-free license to 5 | * use, copy, modify, and distribute this software in source code or binary 6 | * form for use in connection with the web services and APIs provided by 7 | * Facebook. 8 | * 9 | * As with any software that integrates with the Facebook platform, your use 10 | * of this software is subject to the Facebook Developer Principles and 11 | * Policies [http://developers.facebook.com/policy/]. This copyright notice 12 | * shall be included in all copies or substantial portions of the software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE 21 | */ 22 | 23 | 'use strict'; 24 | /* global define */ 25 | define(['jasny-bootstrap'], function(jasny) { 26 | 27 | var initialize = function( 28 | elementId, 29 | initialValue 30 | ) { 31 | /* 32 | * Just loading the jasny-bootstrap library which contains the fileinput 33 | * plugin. 34 | */ 35 | }; 36 | 37 | return { 38 | initialize: initialize, 39 | }; 40 | }); 41 | -------------------------------------------------------------------------------- /components/js_src/react_table.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 3 | * 4 | * You are hereby granted a non-exclusive, worldwide, royalty-free license to 5 | * use, copy, modify, and distribute this software in source code or binary 6 | * form for use in connection with the web services and APIs provided by 7 | * Facebook. 8 | * 9 | * As with any software that integrates with the Facebook platform, your use 10 | * of this software is subject to the Facebook Developer Principles and 11 | * Policies [http://developers.facebook.com/policy/]. This copyright notice 12 | * shall be included in all copies or substantial portions of the software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE 21 | */ 22 | 23 | 'use strict'; 24 | /* global define */ 25 | define(['react'], function(React) { 26 | 27 | var ReactTable = React.createClass({ 28 | propTypes: { 29 | header: React.PropTypes.array.isRequired, 30 | data: React.PropTypes.array.isRequired, 31 | tableClasses: React.PropTypes.array, 32 | }, 33 | 34 | render: function() { 35 | var extraClasses = ''; 36 | if (this.props.tableClasses.length > 0) { 37 | extraClasses = this.props.tableClasses.join(' '); 38 | } 39 | return ( 40 | 41 | 42 | { 43 | this.props.header.map(function(value, i) { 44 | return (); 45 | }) 46 | } 47 | 48 | 49 | { 50 | this.props.data.map(function(row, rowIndex) { 51 | return ( 52 | { 53 | Object.keys(row).map(function(key, colIndex) { 54 | return ( 55 | 58 | ); 59 | }) 60 | } 61 | ); 62 | }) 63 | } 64 | 65 |
{value}
56 | {row[key]} 57 |
66 | ); 67 | }, 68 | }); 69 | 70 | return ReactTable; 71 | }); 72 | -------------------------------------------------------------------------------- /components/js_src/simple_modal.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /* global define */ 3 | define(['jquery', 'react'], function($, React) { 4 | let Modal = React.createClass({ 5 | propTypes: { 6 | targetId: React.PropTypes.string.isRequired, 7 | header: React.PropTypes.string.isRequired, 8 | show: React.PropTypes.bool.isRequired, 9 | onClose: React.PropTypes.func.isRequired, 10 | }, 11 | 12 | getDefaultProps: function() { 13 | return { 14 | show: false, 15 | onClose: function(event) {} 16 | }; 17 | }, 18 | 19 | getInitialState: function() { 20 | return { 21 | }; 22 | }, 23 | 24 | hideOnOuterClick: function(event) { 25 | if (event.target.dataset.modal) { 26 | this.props.onClose(event); 27 | } 28 | }, 29 | 30 | render: function() { 31 | if (!this.props.show) { 32 | return null; 33 | } 34 | 35 | const targetId = this.props.targetId; 36 | return ( 37 | 59 | ); 60 | }, 61 | 62 | }); 63 | 64 | return Modal; 65 | }); 66 | -------------------------------------------------------------------------------- /components/js_src/spec_select.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 3 | * 4 | * You are hereby granted a non-exclusive, worldwide, royalty-free license to 5 | * use, copy, modify, and distribute this software in source code or binary 6 | * form for use in connection with the web services and APIs provided by 7 | * Facebook. 8 | * 9 | * As with any software that integrates with the Facebook platform, your use 10 | * of this software is subject to the Facebook Developer Principles and 11 | * Policies [http://developers.facebook.com/policy/]. This copyright notice 12 | * shall be included in all copies or substantial portions of the software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE 21 | */ 22 | 23 | 'use strict'; 24 | /*global define*/ 25 | define(['jquery', 'react'], 26 | function($, React) { 27 | 28 | var SpecSelectContainer = React.createClass({displayName: 'SpecSelectContainer', 29 | 30 | getInitialState: function() { 31 | return { 32 | selected: this.props.selected || 0 33 | }; 34 | }, 35 | 36 | change: function(event) { 37 | this.setState({ selected: event.target.value }); 38 | }, 39 | 40 | render: function() { 41 | var select_options = []; 42 | this.props.specs.forEach(function(spec, index) { 43 | select_options.push( 44 | React.createElement('option', {value: index, key: index}, 45 | spec.name 46 | ) 47 | ); 48 | }); 49 | 50 | $('#' + this.props.targetId).val(this.state.selected); 51 | 52 | return ( 53 | React.createElement('div', null, 54 | React.createElement('p', null, 55 | React.createElement('select', {value: this.state.selected, 56 | onChange: this.change}, 57 | select_options 58 | ) 59 | ), 60 | React.createElement('p', null, 61 | 'Current Selected:', 62 | React.createElement('pre', null, 63 | this.props.specs[this.state.selected].spec 64 | ) 65 | ) 66 | ) 67 | ); 68 | } 69 | }); 70 | 71 | // Load the react JS component 72 | var initialize = function(specSelectId, value, specsdata) { 73 | React.render( 74 | React.createElement(SpecSelectContainer, { 75 | targetId: specSelectId, 76 | selected: value, 77 | specs: specsdata}), 78 | document.getElementById(specSelectId + '_react') 79 | ); 80 | }; 81 | 82 | return { 83 | initialize: initialize, 84 | }; 85 | 86 | }); 87 | -------------------------------------------------------------------------------- /components/js_src/spec_select.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 3 | * 4 | * You are hereby granted a non-exclusive, worldwide, royalty-free license to 5 | * use, copy, modify, and distribute this software in source code or binary 6 | * form for use in connection with the web services and APIs provided by 7 | * Facebook. 8 | * 9 | * As with any software that integrates with the Facebook platform, your use 10 | * of this software is subject to the Facebook Developer Principles and 11 | * Policies [http://developers.facebook.com/policy/]. This copyright notice 12 | * shall be included in all copies or substantial portions of the software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE 21 | */ 22 | 23 | 'use strict'; 24 | /*global define*/ 25 | define(['jquery', 'react'], function($, React) { 26 | 27 | var SpecSelectContainer = React.createClass({ 28 | 29 | getInitialState: function() { 30 | return { 31 | selected: this.props.selected || 0 32 | }; 33 | }, 34 | 35 | change: function(event) { 36 | this.setState({ selected: event.target.value }); 37 | }, 38 | 39 | render: function() { 40 | var select_options = []; 41 | this.props.specs.forEach(function(spec, index) { 42 | select_options.push( 43 | 46 | ); 47 | }); 48 | 49 | $('#' + this.props.targetId).val(this.state.selected); 50 | 51 | return ( 52 |
53 |

54 | 58 |

59 |

60 | Current Selected: 61 |

62 |             {this.props.specs[this.state.selected].spec}
63 |           
64 |

65 |
66 | ); 67 | } 68 | }); 69 | 70 | // Load the react JS component 71 | var initialize = function(specSelectId, value, specsdata) { 72 | React.render( 73 | , 77 | document.getElementById(specSelectId + '_react') 78 | ); 79 | }; 80 | 81 | return { 82 | initialize: initialize, 83 | }; 84 | 85 | }); 86 | -------------------------------------------------------------------------------- /components/json_char_field.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | import json 22 | from django.utils import six 23 | from django.forms import Field 24 | from django.core.exceptions import ValidationError 25 | 26 | 27 | class JsonCharField(Field): 28 | """ 29 | A field that expect JSON formatted string as input, 30 | and save data in python dict. 31 | """ 32 | def to_python(self, value): 33 | if isinstance(value, six.string_types): 34 | try: 35 | return json.loads(value) 36 | except ValueError: 37 | raise ValidationError("Enter valid JSON") 38 | return value 39 | 40 | def prepare_value(self, value): 41 | if isinstance(value, six.string_types): 42 | return value 43 | if value is None: 44 | return "" 45 | return json.dumps(value) 46 | -------------------------------------------------------------------------------- /components/lead_form_create.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from widgets import ReactModalWidget 22 | from django.forms import CharField 23 | 24 | 25 | class LeadFormCreate(CharField): 26 | """ 27 | Component for creating or selecting a lead gen form. This component is used 28 | for creating [Lead Ads][1] or downloading the lead data from a lead ad. The 29 | component will have a button to trigger a popup window where you can choose 30 | from a list of forms loaded via AJAX, or create a new one using the create 31 | flow available from [Facebook JS SDK][2]. 32 | 33 | [1]: https://developers.facebook.com/docs/marketing-api/guides/lead-ads/ 34 | [2]: https://developers.facebook.com/docs/javascript 35 | """ 36 | 37 | def __init__( 38 | self, 39 | id='id_lead_form', 40 | id_page_select='id_page_select', 41 | *args, 42 | **kwargs 43 | ): 44 | super(LeadFormCreate, self).__init__(*args, **kwargs) 45 | 46 | self.id = id 47 | if not self.help_text: 48 | self.help_text = ("Choose a Page before using.") 49 | 50 | self.widget = ReactModalWidget(attrs={ 51 | 'id': self.id, 52 | 'js_params': [id_page_select], 53 | 'icon': "glyphicon glyphicon-list-alt", 54 | 'js_module': 'lead_form', 55 | 'js_class': 'LeadForm', 56 | }) 57 | -------------------------------------------------------------------------------- /components/page_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django import forms 22 | from widgets import SelectizeWidget 23 | 24 | 25 | class PageSelect(forms.CharField): 26 | """ 27 | Component for selectin Page that the user owns. It listens to the ad account 28 | select component for the selected ad account, and loads the connected pages 29 | for that account via AJAX and populate the select options. 30 | """ 31 | DEFAULT_CHOICES = [('', '- Choose a page -')] 32 | 33 | def __init__( 34 | self, 35 | id='id_page_select', 36 | id_act_select='id_act_select', 37 | *args, 38 | **kwargs 39 | ): 40 | super(PageSelect, self).__init__(*args, **kwargs) 41 | 42 | self.id = id 43 | self.id_act_select = id_act_select 44 | if not self.help_text: 45 | self.help_text = ("Choose an ad account before using.") 46 | 47 | self.widget = SelectizeWidget( 48 | attrs={ 49 | 'id': self.id, 50 | 'js_params': [id_act_select], 51 | 'js_module': 'page_select', 52 | 'js_class': 'PageSelect' 53 | }, 54 | choices=self.DEFAULT_CHOICES, 55 | ) 56 | -------------------------------------------------------------------------------- /components/product_catalog_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django import forms 22 | from widgets import SelectizeWidget 23 | 24 | 25 | class ProductCatalogSelect(forms.CharField): 26 | """ 27 | Component for selecting Product Catalog. It loads the business manager's 28 | product catalogs via AJAX and populate the select options. 29 | """ 30 | 31 | DEFAULT_CHOICES = [('', '- Choose a product catalog -')] 32 | 33 | def __init__( 34 | self, 35 | id='id_product_catalog_select', 36 | id_business_select='id_business_select', 37 | catalog_limit=300, 38 | *args, 39 | **kwargs 40 | ): 41 | super(ProductCatalogSelect, self).__init__(*args, **kwargs) 42 | 43 | self.id = id 44 | if not self.help_text: 45 | self.help_text = ("Choose business manager before using.") 46 | 47 | self.widget = SelectizeWidget( 48 | attrs={ 49 | 'id': self.id, 50 | 'js_params': [id_business_select, catalog_limit], 51 | 'js_module': 'product_catalog_select', 52 | 'js_class': 'ProductCatalogSelect', 53 | }, 54 | choices=self.DEFAULT_CHOICES 55 | ) 56 | -------------------------------------------------------------------------------- /components/product_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django import forms 22 | from widgets import SelectizeWidget 23 | 24 | 25 | class ProductSelect(forms.CharField): 26 | """ 27 | Component for select a product from a product catalog. It loads the products 28 | in the selected product catalog via AJAX and populate the select options. 29 | """ 30 | 31 | DEFAULT_CHOICES = [('', '- Choose a product -')] 32 | 33 | def __init__( 34 | self, 35 | id='id_product_select', 36 | id_product_catalog_select='id_product_catalog_select', 37 | *args, 38 | **kwargs 39 | ): 40 | super(ProductSelect, self).__init__(*args, **kwargs) 41 | 42 | self.id = id 43 | if not self.help_text: 44 | self.help_text = ( 45 | "Choose product catalog before using. This is only showing " + 46 | "first 100 products for demo purpose.") 47 | 48 | self.widget = SelectizeWidget( 49 | attrs={ 50 | 'id': self.id, 51 | 'js_params': [id_product_catalog_select], 52 | 'js_module': 'product_select', 53 | 'js_class': 'ProductSelect', 54 | }, 55 | choices=self.DEFAULT_CHOICES 56 | ) 57 | -------------------------------------------------------------------------------- /components/product_set_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django import forms 22 | from widgets import SelectizeWidget 23 | 24 | 25 | class ProductSetSelect(forms.CharField): 26 | """ 27 | Component for selecting custom audiences select . It listens to the ad 28 | account select component for the selected account id and loads the custom 29 | audiences for that account via AJAX and populate the select options. 30 | """ 31 | DEFAULT_CHOICES = [('', '- Choose a Product Set -')] 32 | 33 | def __init__( 34 | self, 35 | id='id_product_set_select', 36 | id_product_catalog_select='id_product_catalog_select', 37 | *args, 38 | **kwargs 39 | ): 40 | super(ProductSetSelect, self).__init__(*args, **kwargs) 41 | 42 | self.id = id 43 | if not self.help_text: 44 | self.help_text = ("Choose an product catalog before using.") 45 | 46 | self.widget = SelectizeWidget( 47 | attrs={ 48 | 'id': self.id, 49 | 'js_params': [id_product_catalog_select], 50 | 'js_module': 'product_set_select', 51 | 'js_class': 'ProductSetSelect', 52 | }, 53 | choices=self.DEFAULT_CHOICES, 54 | ) 55 | -------------------------------------------------------------------------------- /components/spec_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from components.widgets import ReactWidget 22 | from json_char_field import JsonCharField 23 | 24 | 25 | class SpecSelect(JsonCharField): 26 | """ 27 | Component for setting [Targeting Specs][1]. This component will render 28 | a button that will toggle the targeting spec composer popup window. 29 | The output is the targeting spec JSON data. 30 | 31 | [1]: https://developers.facebook.com/docs/marketing-api/targeting-specs/ 32 | """ 33 | 34 | def __init__( 35 | self, 36 | id='id_spec_select', 37 | specs=[], 38 | *args, 39 | **kwargs 40 | ): 41 | super(SpecSelect, self).__init__(*args, **kwargs) 42 | 43 | self.id = id 44 | 45 | self.widget = ReactWidget(attrs={ 46 | 'id': self.id, 47 | 'js_params': [specs], 48 | 'js_module': 'spec_select', 49 | 'js_class': 'SpecSelect', 50 | }) 51 | -------------------------------------------------------------------------------- /components/targeting_spec.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from widgets import ReactModalWidget 22 | from json_char_field import JsonCharField 23 | import json 24 | 25 | 26 | class TargetingSpec(JsonCharField): 27 | """ 28 | Component for setting [Targeting Specs][1]. This component will render 29 | a button that will toggle the targeting spec composer popup window. 30 | The output is the targeting spec JSON data. 31 | 32 | [1]: https://developers.facebook.com/docs/marketing-api/targeting-specs/ 33 | """ 34 | 35 | """ 36 | Some sample targeting specs 37 | """ 38 | US_ANDROID_MOBILEFEED = { 39 | 'geo_locations': { 40 | 'countries': ['US'], 41 | }, 42 | 'user_os': ['Android'], 43 | 'device_platforms': ['mobile'], 44 | 'publisher_platforms': ['facebook', 'audience_network'] 45 | } 46 | 47 | def __init__( 48 | self, 49 | id='id_targeting_spec', 50 | id_act_select='id_act_select', 51 | *args, 52 | **kwargs 53 | ): 54 | super(TargetingSpec, self).__init__(*args, **kwargs) 55 | 56 | self.id = id 57 | if not self.help_text: 58 | self.help_text = ("Choose an ad account before using. Changing " + 59 | "ad account will reset the current spec.") 60 | 61 | self.widget = ReactModalWidget(attrs={ 62 | 'id': self.id, 63 | 'js_params': [id_act_select], 64 | 'icon': "glyphicon glyphicon-plus", 65 | 'js_module': 'targeting_spec', 66 | 'js_class': 'TargetingSpec', 67 | 'data-toggle': 'tooltip', 68 | 'title': 'Choose an ad account before using.', 69 | }) 70 | -------------------------------------------------------------------------------- /components/templates/components/overview.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | {% load bootstrap %} 3 | {% block head_auxiliary %} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% endblock %} 15 | 16 | {% block body_block %} 17 |
18 | 19 |
20 | 21 | {% if request.session.fbuserid %} 22 |
23 |
24 |
25 |

UI Components for Marketing Automation Tools

26 |

27 | Learn how the re-usable UI components work, and you can check 28 | out the gallery page that lists out all the UI components. 29 |

30 | 31 | Check Gallery 32 | 33 |
34 |
35 |
36 |
37 |
38 | {{ content|safe }} 39 |
40 |
41 | {% else %} 42 | 43 | {% block login_form %} 44 |
45 |
46 |
47 |

UI Components for Marketing Automation Tools

48 |
49 | {% csrf_token %} 50 |
51 | 53 | 57 |
58 |
59 |
60 |
61 |
62 | {% endblock %} 63 | {% endif %} 64 | 65 |
66 | {% endblock %} 67 | -------------------------------------------------------------------------------- /components/urls.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django.conf.urls import patterns, url 22 | from components.views import ComponentGallery, ComponentOverview 23 | 24 | urlpatterns = patterns( 25 | '', 26 | url(r'^$', ComponentOverview.as_view(), name="overview"), 27 | url(r'^gallery/', ComponentGallery.as_view(), name='gallery'), 28 | ) 29 | -------------------------------------------------------------------------------- /dash/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/dash/__init__.py -------------------------------------------------------------------------------- /dash/components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/dash/components/__init__.py -------------------------------------------------------------------------------- /dash/components/role_select.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from components.widgets import SelectizeWidget 22 | from security.models import Role 23 | 24 | 25 | class RoleSelect(SelectizeWidget): 26 | """ 27 | Role select widget based on selectize widget. 28 | """ 29 | def __init__(self, attrs={}): 30 | attrs['id'] = attrs.id if hasattr(attrs, 'id') else 'id_role_select' 31 | attrs['multiple'] = attrs.multiple \ 32 | if hasattr(attrs, 'multiple') else 'True' 33 | choices = self.get_choices() 34 | super(RoleSelect, self).__init__(attrs, choices) 35 | 36 | def get_choices(self): 37 | choices = [('', '- Choose Roles -')] 38 | # liyuhk: currently simply select all roles into memory. 39 | # This could be a problem when we have thousands of thousands roles 40 | # in muse production, but in longer enough time, I expect the total 41 | # numnber of roles can be handled in memory. 42 | roles = Role.objects.all() 43 | for role in roles: 44 | choices.append((role.name, role.name)) 45 | return choices 46 | 47 | def value_from_datadict(self, data, files, name): 48 | return ','.join(data.getlist(name, [])) 49 | -------------------------------------------------------------------------------- /dash/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/dash/management/__init__.py -------------------------------------------------------------------------------- /dash/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/dash/management/commands/__init__.py -------------------------------------------------------------------------------- /dash/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.db import models, migrations 3 | 4 | class Migration(migrations.Migration): 5 | 6 | dependencies = [ 7 | ] 8 | 9 | operations = [ 10 | ] 11 | -------------------------------------------------------------------------------- /dash/migrations/10000_auto_20160602_0605.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('dash', '9999_auto_samples_metadata'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='sample', 16 | name='roles_to_check', 17 | field=models.TextField(default=b'', blank=True), 18 | preserve_default=True, 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /dash/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/dash/migrations/__init__.py -------------------------------------------------------------------------------- /dash/models.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django.db import models 22 | 23 | 24 | class Sample(models.Model): 25 | id = models.CharField(max_length=20, primary_key=True) 26 | friendly_name = models.CharField(max_length=50) 27 | description = models.CharField(max_length=200) 28 | view_module = models.CharField(max_length=50) 29 | view_class = models.CharField(max_length=50) 30 | hide_in_gallery = models.BooleanField(default=False) 31 | roles_to_check = models.TextField(blank=True, default='') 32 | seo_description = models.CharField(max_length=150) 33 | 34 | class Meta: 35 | ordering = ['friendly_name'] 36 | -------------------------------------------------------------------------------- /dash/templates/dash/create_sample.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | {% load bootstrap %} 3 | {% block body_block %} 4 |
5 |
6 |

Sample Info

7 |
8 |
9 |
10 | {% csrf_token %} 11 | {{ form|bootstrap }} 12 | 13 |
14 |
15 |
16 |
17 |
18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /dash/templates/dash/delete_sample.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | {% block body_block %} 3 |
4 |
5 |

Confirm Delete Sample

6 |
7 |
8 |
9 | {% csrf_token %} 10 |

Are you sure you want to delete sample "{{ object.friendly_name }}"?

11 | 12 | Cancel 13 |
14 |

Sample Details

15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
Id{{ object.id}}
Name{{ object.friendly_name }}
Description{{ object.description}}
View Class{{ object.view_class}}
33 |
34 |
35 |
36 |
37 | {% endblock %} 38 | -------------------------------------------------------------------------------- /dash/templates/dash/details_role.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | {% load bootstrap %} 3 | {% block body_block %} 4 |
5 |
6 |

7 | Roles 8 | » 9 | Role "{{ object.name }}" 10 |

11 |
12 |
13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 44 | 45 |
Name{{ object.name }}
Description{{ object.description}}
FB Users in This Role 26 | {% if object.current_fbusers %} 27 |
    28 | {% for user in object.current_fbusers %} 29 | {% if 'unknown' in user %} 30 |
  • {{user.fb_userid}} 31 | {% else %} 32 |
  • {{user.full_name}}({{user.fb_userid}}) 33 | {% endif %} 34 | 35 | [profile^] 36 | 37 |
  • 38 | {% endfor %} 39 |
40 | {% else %} 41 | Nobody yet! 42 | {% endif %} 43 |
46 |
47 |
48 |
49 |
50 | {% endblock %} 51 | -------------------------------------------------------------------------------- /dash/templates/dash/details_sample.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | {% block body_block %} 3 |
4 |
5 |

Sample: {{ object.friendly_name }}

6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
Id{{ object.id}}
Name{{ object.friendly_name }}
Description{{ object.description}}
View Module{{ object.view_module}}
View Class{{ object.view_class}}
Roles To Check{{ object.roles_to_check }}
Description Meta Tag{{ object.seo_description }}
38 |
39 |
40 |
41 |
42 | {% endblock %} 43 | -------------------------------------------------------------------------------- /dash/templates/dash/list_role.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | {% load bootstrap %} 3 | {% block body_block %} 4 |
5 |
6 |

7 | Roles 8 |

9 |
10 |
11 |
12 |

Existing Roles

13 | 14 | 15 | 16 | 17 | 18 | 19 | {% for role in object_list %} 20 | 21 | 22 | 23 | 28 | 29 | {% endfor %} 30 |
NameDescriptionActions
{{role.name}}{{role.description}} 24 | 25 | details 26 | 27 |
31 |
32 |
33 |
34 |
35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /dash/templates/dash/list_sample.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | {% block body_block %} 3 |
4 |
5 |

Samples

6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% for sample in object_list %} 17 | 18 | 19 | 20 | 21 | 22 | 27 | 28 | {% endfor %} 29 |
IdNameView ClassDescriptionActions
{{sample.id}}{{sample.friendly_name}}{{sample.description}}{{sample.view_class}} 23 | details | 24 | edit | 25 | delete 26 |
30 | New Sample 31 |
32 |
33 |
34 |
35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /dash/urls.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | import logging 22 | from django.conf.urls import patterns, url 23 | from dash.views.sample import SampleCreateView, SampleUpdateView 24 | from dash.views.sample import SampleDetailView, SampleListView 25 | from dash.views.sample import SampleDeleteView 26 | from dash.views.role import RoleListView, RoleDetailsView 27 | from django.conf import settings 28 | 29 | logger = logging.getLogger(__name__) 30 | 31 | urlpatterns = [] 32 | # enable dash only if not in prod/test and dash explicitly enabled 33 | if hasattr(settings, 'ENABLE_DASH') \ 34 | and settings.ENABLE_DASH \ 35 | and not settings.IS_RELEASE() \ 36 | and not settings.IS_TEST(): 37 | urlpatterns = patterns( 38 | '', 39 | url(r'^sample/add/$', SampleCreateView.as_view(), name='sample_add'), 40 | url(r'^sample/list/$', SampleListView.as_view(), name='sample_list'), 41 | url(r'^sample/details/(?P\w+)/$', 42 | SampleDetailView.as_view(), 43 | name='sample_details'), 44 | url(r'^sample/delete/(?P\w+)$', 45 | SampleDeleteView.as_view(), 46 | name='sample_delete'), 47 | url(r'^sample/edit/(?P\w+)$', 48 | SampleUpdateView.as_view(), 49 | name='sample_edit'), 50 | url(r'^role/list/$', RoleListView.as_view(), name='role_list'), 51 | url(r'^role/details/(?P\w+)/$', RoleDetailsView.as_view(), 52 | name='role_details') 53 | ) 54 | else: 55 | logger.info('Dash disabled') 56 | -------------------------------------------------------------------------------- /dash/views/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/dash/views/__init__.py -------------------------------------------------------------------------------- /dash/views/role.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | import logging 22 | from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist 23 | from django.views.generic import DetailView, ListView 24 | from security.models import Role, FBUser, FBUserInRole 25 | from security.fbsample import fbads_auth 26 | 27 | logger = logging.getLogger(__name__) 28 | 29 | 30 | class RoleListView(ListView): 31 | model = Role 32 | template_name = 'dash/list_role.html' 33 | 34 | @fbads_auth(check_role_list=['super_role']) 35 | def get(self, request, *args, **kwargs): 36 | return ListView.get(self, request, args, kwargs) 37 | 38 | 39 | class RoleDetailsView(DetailView): 40 | model = Role 41 | template_name = 'dash/details_role.html' 42 | 43 | def get_object(self, queryset=None): 44 | obj = DetailView.get_object(self, queryset) 45 | fbuserinroles = FBUserInRole.objects.filter(role__name=obj.name) 46 | obj.current_fbusers = [] 47 | for f in fbuserinroles: 48 | try: 49 | u = FBUser.objects.get(fb_userid=f.fb_userid) 50 | obj.current_fbusers.append(u) 51 | except MultipleObjectsReturned as mor: 52 | logger.error( 53 | "Multi objets returned for fb_userid: %s.", 54 | f.fb_userid 55 | ) 56 | logger.exception(mor) 57 | continue 58 | except ObjectDoesNotExist: 59 | obj.current_fbusers.append({ 60 | 'fb_userid': f.fb_userid, 61 | 'unknown': True 62 | }) 63 | return obj 64 | 65 | @fbads_auth(check_role_list=['super_role']) 66 | def get(self, request, *args, **kwargs): 67 | return DetailView.get(self, request, args, kwargs) 68 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 3 | * 4 | * You are hereby granted a non-exclusive, worldwide, royalty-free license to 5 | * use, copy, modify, and distribute this software in source code or binary 6 | * form for use in connection with the web services and APIs provided by 7 | * Facebook. 8 | * 9 | * As with any software that integrates with the Facebook platform, your use 10 | * of this software is subject to the Facebook Developer Principles and 11 | * Policies [http://developers.facebook.com/policy/]. This copyright notice 12 | * shall be included in all copies or substantial portions of the software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE 21 | */ 22 | 23 | var gulp = require('gulp'); 24 | var babel = require('gulp-babel'); 25 | var minify = require('gulp-minify'); 26 | 27 | var buildPaths = { 28 | src: ['./components/js_src/*'], 29 | dest: './components/static/scripts/components/' 30 | }; 31 | 32 | gulp.task('build', function() { 33 | build(); 34 | }); 35 | 36 | gulp.task('default', ['build']); 37 | 38 | gulp.task('watch', function() { 39 | gulp.watch(buildPaths.src, ['build']); 40 | }); 41 | 42 | function build() { 43 | gulp.src(buildPaths.src) 44 | .pipe(babel({ 45 | presets: ['es2015', 'react'], 46 | })) 47 | .pipe(minify({ 48 | ext: { 49 | min: '.js', 50 | }, 51 | noSource: true, 52 | })) 53 | .pipe(gulp.dest(buildPaths.dest)); 54 | } 55 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 4 | # 5 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 6 | # use, copy, modify, and distribute this software in source code or binary 7 | # form for use in connection with the web services and APIs provided by 8 | # Facebook. 9 | # 10 | # As with any software that integrates with the Facebook platform, your use of 11 | # this software is subject to the Facebook Developer Principles and Policies 12 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 13 | # included in all copies or substantial portions of the software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import os 24 | import sys 25 | 26 | if __name__ == "__main__": 27 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "muse.settings") 28 | 29 | from django.core.management import execute_from_command_line 30 | 31 | execute_from_command_line(sys.argv) 32 | -------------------------------------------------------------------------------- /muse/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/muse/__init__.py -------------------------------------------------------------------------------- /muse/urls.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django.conf.urls import patterns, include, url 22 | from django.views.generic import TemplateView 23 | from django.conf import settings 24 | from views import about 25 | 26 | 27 | urlpatterns = patterns( 28 | '', 29 | url(r'^$', about, name='about'), 30 | url(r'^auth/', include('security.urls', namespace="auth")), 31 | url(r'^common/', include('common.urls', namespace="common")), 32 | url(r'^components/', include('components.urls', namespace="components")), 33 | url(r'^samples/', include('samples.urls', namespace="samples")), 34 | url(r'^dash/', include('dash.urls', namespace="dash")), 35 | url(r'^license/', 36 | TemplateView.as_view(template_name='common/license.html'), 37 | name='license'), 38 | ) 39 | 40 | # Enable testing 404 pages by calling their urls in DEBUG mode 41 | if settings.DEBUG: 42 | urlpatterns += patterns( 43 | '', 44 | (r'^404/$', TemplateView.as_view(template_name="404.html")), 45 | (r'^500/$', TemplateView.as_view(template_name="500.html")) 46 | ) 47 | -------------------------------------------------------------------------------- /muse/views.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django.shortcuts import render 22 | from django.conf import settings 23 | import markdown 24 | import os 25 | import logging 26 | 27 | logger = logging.getLogger('security') 28 | 29 | 30 | def about(request): 31 | readme = '' 32 | fin = os.path.join(settings.BASE_DIR, '../README.md') 33 | with open(fin) as f: 34 | file_content = f.read() 35 | readme = markdown.markdown(file_content) 36 | 37 | return render(request, 'common/about.html', {'readme': readme}) 38 | -------------------------------------------------------------------------------- /muse/wsgi.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | import os 22 | from django.core.wsgi import get_wsgi_application 23 | from dj_static import Cling 24 | 25 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "muse.settings") 26 | os.environ['HTTPS'] = "on" 27 | os.environ['wsgi.url_scheme'] = "https" 28 | application = get_wsgi_application() 29 | application = Cling(application) 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "babel": "^6.5.2", 4 | "babel-preset-es2015": "^6.13.2", 5 | "babel-preset-react": "^6.11.1", 6 | "gulp": "^3.9.1", 7 | "gulp-babel": "^6.1.2", 8 | "gulp-minify": "0.0.14" 9 | }, 10 | "scripts": { 11 | "postinstall": "./node_modules/.bin/gulp" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | amqp==1.4.6 2 | anyjson==0.3.3 3 | billiard==3.3.0.20 4 | celery==3.1.17 5 | configparser==3.5.0b2 6 | dj-database-url==0.3.0 7 | dj-static==0.0.6 8 | Django==1.7.4 9 | django-bootstrap-form==3.1 10 | django-extensions==1.4.9 11 | django-postgrespool==0.3.0 12 | django-settings-export==1.0.6 13 | django-sslserver==0.15 14 | django-toolbelt==0.0.1 15 | facebookads==2.7.1 16 | gfm==0.0.3 17 | gunicorn==19.1.1 18 | kombu==3.0.26 19 | Mako==1.0.1 20 | Markdown==2.4.1 21 | MarkupSafe==0.23 22 | mock==1.0.1 23 | pdoc==0.3.1 24 | pep8==1.6.2 25 | Pillow==2.7.0 26 | psycopg2==2.5.4 27 | pyflakes==0.8.1 28 | Pygments==2.0.1 29 | pytz==2015.4 30 | quik==0.2.2 31 | requests==2.4.3 32 | six==1.8.0 33 | SQLAlchemy==0.9.8 34 | sqlparse==0.1.15 35 | static3==0.5.1 36 | wheel==0.24.0 37 | whitenoise==1.0.6 38 | -------------------------------------------------------------------------------- /samples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/__init__.py -------------------------------------------------------------------------------- /samples/samplecode/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/samplecode/__init__.py -------------------------------------------------------------------------------- /samples/samplecode/accountlist.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | """ 22 | # Ad Account List 23 | 24 | ## Getting user's ad accounts 25 | 26 | *** 27 | 28 | This is a simple sample that shows how to get a list of the user's ad accounts. 29 | A first test after you get an access token with ads management/insights 30 | permission you should do is to try to get the user's list of ad accounts. 31 | 32 | ## References: 33 | 34 | * [Ad Account document][1] 35 | 36 | [1]: https://developers.facebook.com/docs/reference/ads-api/adaccount 37 | """ 38 | from facebookads.objects import AdUser 39 | 40 | 41 | class AdAccountsList: 42 | 43 | def get_accounts(self): 44 | """ 45 | Retrieves and displays a list of the user's ad accounts. 46 | """ 47 | me = AdUser(fbid='me') 48 | return list(me.get_ad_accounts(fields=[ 49 | 'id', 50 | 'name', 51 | 'timezone_name', 52 | 'amount_spent', 53 | 'currency'])) 54 | -------------------------------------------------------------------------------- /samples/samplecode/autobot_config_editor.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | """ 22 | # Autobot Config Editor 23 | 24 | ## Creating Autobot configuration file 25 | 26 | *** 27 | 28 | This sample editor shows how to use the Marketing API to create and save a 29 | configuration fle for Autobot. 30 | 31 | """ 32 | 33 | 34 | class AutobotConfigEditorSample: 35 | """ 36 | """ 37 | -------------------------------------------------------------------------------- /samples/samplecode/customaudience.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | """ 22 | # Custom Audiences 23 | 24 | ## Creating custom audiences and uploading data 25 | 26 | *** 27 | 28 | This sample shows how to use the Custom Audiences API to create a new custom 29 | audience and upload data to it. 30 | 31 | Using data from your CRM system, you can find your existing customers on 32 | Facebook. You can then run campaigns to re-target those customers and/or 33 | campaigns that target new customers and exclude existing ones. 34 | 35 | ## References: 36 | 37 | * [Custom Audiences API doc][1] 38 | 39 | [1]: https://developers.facebook.com/docs/reference/ads-api/custom-audience-api 40 | """ 41 | from facebookads.objects import CustomAudience 42 | 43 | 44 | class CustomAudienceSample: 45 | """ 46 | The main sample class. 47 | """ 48 | def create_audience(self, accountid, name, description, optoutlink): 49 | """ 50 | Creates a new custom audience and returns the id. 51 | """ 52 | audience = CustomAudience(parent_id=accountid) 53 | audience.update({ 54 | CustomAudience.Field.name: name, 55 | CustomAudience.Field.description: description, 56 | CustomAudience.Field.opt_out_link: optoutlink, 57 | CustomAudience.Field.subtype: CustomAudience.Subtype.custom, 58 | }) 59 | audience.remote_create() 60 | caid = audience[CustomAudience.Field.id] 61 | return caid 62 | 63 | def upload_users_to_audience( 64 | self, 65 | audienceid, 66 | users, 67 | schema=CustomAudience.Schema.email_hash): 68 | """ 69 | Adds user emails to an existing audience. The SDK automatically hashes 70 | the emails. Only the hash is sent to Facebook. 71 | """ 72 | audience = CustomAudience(audienceid) 73 | return audience.add_users(schema, users) 74 | -------------------------------------------------------------------------------- /samples/samplecode/targeting.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | """ 22 | # Targeting Specs 23 | 24 | ## Testing with the targeting specs setting and reach estimate 25 | 26 | *** 27 | 28 | This sample creates a targeting spec JSON string using the pop up composer. 29 | Check the [targeting spec reference doc][1] for more information on targeting 30 | specs. Using the composer in this sample, you can also test the targeting spec 31 | with the [reach estimate][2] API end point to see if this is a valid targeting 32 | setting and what is the estimated audience size. 33 | 34 | ## References: 35 | 36 | * [Targeting Specs][1] 37 | * [Reach estimate][2] 38 | 39 | [1]: https://developers.facebook.com/docs/marketing-api/targeting-specs 40 | [2]: https://developers.facebook.com/docs/marketing-api/reachestimate 41 | """ 42 | -------------------------------------------------------------------------------- /samples/samplecode/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/samplecode/tests/__init__.py -------------------------------------------------------------------------------- /samples/samplecode/tests/adcreation.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | import time 22 | from samples.samplecode.adcreation import AdCreationSample 23 | from samples.samplecode.tests.sampletestcase import SampleTestCase 24 | from facebookads.objects import AdSet 25 | 26 | 27 | class AdCreationTestCase(SampleTestCase): 28 | 29 | def setUp(self): 30 | super(AdCreationTestCase, self).setUp() 31 | self.sample = AdCreationSample() 32 | 33 | def test_normal(self): 34 | start = int(time.time()) + 86400 # start tomorrow 35 | end = start + (2 * 86400) # end after 2 days 36 | 37 | result = self.sample.create_multiple_link_clicks_ads( 38 | self.account_id, 39 | self.page_id, 40 | "sample_test", 41 | ["title1", "title2"], 42 | ["body1", "body2"], 43 | ["http://www.gaishen.org", "http://www.example.com"], 44 | self.images, 45 | self.basic_targeting, 46 | AdSet.OptimizationGoal.link_clicks, 47 | AdSet.BillingEvent.link_clicks, 48 | 100, # bid 49 | 1000, # daily budget 50 | 10000, # lifetime budget 51 | start, 52 | end 53 | ) 54 | self.assertEqual(len(result), 3) 55 | campaign = result[0] 56 | ad_set = result[1] 57 | ads_created = result[2] 58 | self.assertIsNotNone(campaign) 59 | self.assertIsNotNone(ad_set) 60 | self.assertIsNotNone(ads_created) 61 | self.assertTrue(len(ads_created) > 0) 62 | self.campaign = campaign 63 | 64 | def tearDown(self): 65 | super(AdCreationTestCase, self).tearDown() 66 | if hasattr(self, 'campaign'): 67 | self.campaign.remote_delete() 68 | -------------------------------------------------------------------------------- /samples/samplecode/tests/adimage0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/samplecode/tests/adimage0.png -------------------------------------------------------------------------------- /samples/samplecode/tests/adimage1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/samplecode/tests/adimage1.jpg -------------------------------------------------------------------------------- /samples/samplecode/tests/adimage2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/samplecode/tests/adimage2.jpg -------------------------------------------------------------------------------- /samples/samplecode/tests/adimage3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/samplecode/tests/adimage3.jpg -------------------------------------------------------------------------------- /samples/samplecode/tests/app_install_ad.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from facebookads.objects import Campaign 22 | from samples.samplecode.app_install_ad import AppInstallAdSample 23 | from samples.samplecode.tests.sampletestcase import SampleTestCase 24 | 25 | 26 | class AppInstallAdTestCase(SampleTestCase): 27 | 28 | def setUp(self): 29 | super(AppInstallAdTestCase, self).setUp() 30 | self.maia_sample = AppInstallAdSample() 31 | 32 | def test_normal(self): 33 | optimization_goal = 'APP_INSTALLS' 34 | billing_event = 'IMPRESSIONS' 35 | bid_amount = 100 36 | result = self.maia_sample.create_app_install_ad( 37 | self.account_id, 38 | "MAIA Test", # basename 39 | "Try my app!", # message 40 | self.images[0], 41 | "1000", # dailybudget, 42 | self.page_id, 43 | optimization_goal, 44 | billing_event, 45 | bid_amount, 46 | self.mobile_targeting, 47 | self.app_info['fbapplication_id'], 48 | self.app_info['app_name'], 49 | self.app_info['appstore_link'], 50 | self.app_info['app_deep_link'], 51 | ) 52 | 53 | self.assertIn('campaign_id', result) 54 | self.assertIn('adset_id', result) 55 | self.assertIn('creative_id', result) 56 | self.assertIn('ad_id', result) 57 | 58 | self.campaign = Campaign() 59 | self.campaign[Campaign.Field.id] = result['campaign_id'] 60 | self.campaign.remote_read() 61 | self.assertEqual(self.campaign.get_id(), result['campaign_id']) 62 | 63 | def tearDown(self): 64 | super(AppInstallAdTestCase, self).tearDown() 65 | if hasattr(self, 'campaign'): 66 | self.campaign.remote_delete() 67 | -------------------------------------------------------------------------------- /samples/samplecode/tests/appengagement.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | import os 22 | from facebookads.objects import Campaign 23 | from samples.samplecode.appengagement import AppEngagementSample 24 | from samples.samplecode.tests.sampletestcase import SampleTestCase 25 | 26 | 27 | class AppEngagementTestCase(SampleTestCase): 28 | 29 | def setUp(self): 30 | super(AppEngagementTestCase, self).setUp() 31 | self.appengagement_sample = AppEngagementSample() 32 | 33 | def test_normal(self): 34 | 35 | optimization_goal = 'LINK_CLICKS' 36 | billing_event = 'LINK_CLICKS' 37 | bid_amount = '100' # stands for $1.00 38 | 39 | result = self.appengagement_sample.app_engagement_ad_create( 40 | self.account_id, 41 | "appengagement_test", # basename 42 | "Try my app! Only 8 clicks you are done!", # message 43 | self.images[0], 44 | "500", # dailybudget stands for $5.00, 45 | self.app_info, 46 | optimization_goal, 47 | billing_event, 48 | bid_amount, 49 | self.mobile_targeting 50 | ) 51 | 52 | self.assertIn('campaignid', result) 53 | self.assertIn('adsetid', result) 54 | self.assertIn('creativeid', result) 55 | self.assertIn('adid', result) 56 | 57 | self.campaign = Campaign() 58 | self.campaign[Campaign.Field.id] = result['campaignid'] 59 | self.campaign.remote_read() 60 | self.assertEqual(self.campaign.get_id(), result['campaignid']) 61 | 62 | def tearDown(self): 63 | super(AppEngagementTestCase, self).tearDown() 64 | if hasattr(self, 'campaign'): 65 | self.campaign['adsets'] = None 66 | self.campaign.remote_delete() 67 | -------------------------------------------------------------------------------- /samples/samplecode/tests/carousel_ad.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from samples.samplecode.carousel_ad import CarouselAdSample 22 | from samples.samplecode.tests.sampletestcase import SampleTestCase 23 | from facebookads.objects import AdSet 24 | 25 | 26 | class CarouselAdTestCase(SampleTestCase): 27 | 28 | def setUp(self): 29 | super(CarouselAdTestCase, self).setUp() 30 | self.sample = CarouselAdSample() 31 | 32 | def test_normal(self): 33 | products = [{ 34 | "link": "https://www.gaishen.org/img/photo/skypark_night.jpg", 35 | "name": "Skypark at night", 36 | "description": "Singapore Marina Bay Sky Park at night", 37 | "image_path": self.images[2], 38 | }, { 39 | "link": "https://www.gaishen.org/img/photo/garden_day.jpg", 40 | "name": "Garden by the Bay", 41 | "description": "Singapore Garden By The Bay", 42 | "image_path": self.images[3], 43 | }] 44 | 45 | result = self.sample.create_carousel_ad( 46 | self.account_id, 47 | self.page_id, 48 | "http://www.gaishen.org", 49 | "Some caption", 50 | "Some message", 51 | AdSet.OptimizationGoal.link_clicks, 52 | AdSet.BillingEvent.link_clicks, 53 | 100, # bid 54 | "Ad name", 55 | self.basic_targeting, 56 | products, 57 | ) 58 | self.assertEqual(len(result), 3) 59 | campaign = result[0] 60 | ad_set = result[1] 61 | ad = result[2] 62 | self.assertIsNotNone(campaign) 63 | self.assertIsNotNone(ad_set) 64 | self.assertIsNotNone(ad) 65 | self.campaign = campaign 66 | 67 | def tearDown(self): 68 | super(CarouselAdTestCase, self).tearDown() 69 | if hasattr(self, 'campaign'): 70 | self.campaign.remote_delete() 71 | -------------------------------------------------------------------------------- /samples/samplecode/tests/carousel_app_ad.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from facebookads.objects import Campaign 22 | from samples.samplecode.carousel_app_ad import CarouselAppAdSample 23 | from samples.samplecode.tests.sampletestcase import SampleTestCase 24 | 25 | 26 | class CarouselAppAdTestCase(SampleTestCase): 27 | 28 | def setUp(self): 29 | super(CarouselAppAdTestCase, self).setUp() 30 | self.cmaia_sample = CarouselAppAdSample() 31 | 32 | def test_normal(self): 33 | images = self.images[-3:] # Only three images needed 34 | linktitles = ['Title 1', 'Title 2', 'Title 3'] 35 | deeplinks = None 36 | 37 | optimization_goal = 'APP_INSTALLS' 38 | billing_event = 'IMPRESSIONS' 39 | bid_amount = 100 40 | 41 | result = self.cmaia_sample.carousel_app_ad_create( 42 | self.account_id, 43 | "CMAIA test", # basename 44 | "Try my app!", # message 45 | images, 46 | linktitles, 47 | deeplinks, 48 | "1000", # dailybudget, 49 | self.app_info, 50 | optimization_goal, 51 | billing_event, 52 | bid_amount, 53 | self.mobile_targeting, 54 | ) 55 | 56 | self.assertIn('campaignid', result) 57 | self.assertIn('adsetid', result) 58 | self.assertIn('creativeid', result) 59 | self.assertIn('adid', result) 60 | 61 | self.campaign = Campaign() 62 | self.campaign[Campaign.Field.id] = result['campaignid'] 63 | self.campaign.remote_read() 64 | self.assertEqual(self.campaign.get_id(), result['campaignid']) 65 | 66 | def tearDown(self): 67 | super(CarouselAppAdTestCase, self).tearDown() 68 | if hasattr(self, 'campaign'): 69 | self.campaign['adsets'] = None 70 | self.campaign.remote_delete() 71 | -------------------------------------------------------------------------------- /samples/samplecode/tests/instagram_potential.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from samples.samplecode.tests.sampletestcase import SampleTestCase 22 | from samples.samplecode.instagram_potential import InstagramAdsPotential 23 | 24 | 25 | class InstagramAdsPotentialTestCase(SampleTestCase): 26 | 27 | def setUp(self): 28 | super(InstagramAdsPotentialTestCase, self).setUp() 29 | self.sample = InstagramAdsPotential() 30 | 31 | def test_normal(self): 32 | self.adsets = self.sample.get_ad_sets( 33 | self.account_id, 34 | False, 35 | 5 # limit 36 | ) 37 | self.assertTrue(len(self.adsets) <= 5) 38 | 39 | def tearDown(self): 40 | pass 41 | -------------------------------------------------------------------------------- /samples/samplecode/tests/lead_ad.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from facebookads.objects import Campaign 22 | from samples.samplecode.lead_ad import LeadAdSample 23 | from samples.samplecode.tests.sampletestcase import SampleTestCase 24 | 25 | 26 | class LeadAdTestCase(SampleTestCase): 27 | 28 | def setUp(self): 29 | super(LeadAdTestCase, self).setUp() 30 | self.sample = LeadAdSample() 31 | 32 | def test_normal(self): 33 | result = self.sample.create_lead_ad( 34 | account_id=self.account_id, 35 | name="My Awesome Lead Ad", 36 | page_id=self.page_id, 37 | form_id=self.form_id, 38 | optimization_goal='LEAD_GENERATION', 39 | billing_event='IMPRESSIONS', 40 | bid_amount=100, 41 | daily_budget=1000, 42 | targeting=self.mobile_targeting, 43 | image_path=self.images[0], 44 | message="My message", 45 | link="fb.me/fmd", 46 | caption="My Caption", 47 | description="My description", 48 | cta_type="SIGN_UP" 49 | ) 50 | 51 | self.assertIn('image_hash', result) 52 | self.assertIn('campaign_id', result) 53 | self.assertIn('adset_id', result) 54 | self.assertIn('creative_id', result) 55 | self.assertIn('ad_id', result) 56 | 57 | self.campaign = Campaign() 58 | self.campaign[Campaign.Field.id] = result['campaign_id'] 59 | self.campaign.remote_read() 60 | self.assertEqual(self.campaign.get_id(), result['campaign_id']) 61 | 62 | def tearDown(self): 63 | super(LeadAdTestCase, self).tearDown() 64 | if hasattr(self, 'campaign'): 65 | self.campaign.remote_delete() 66 | -------------------------------------------------------------------------------- /samples/samplecode/tests/maca_cumulative.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from facebookads.objects import CustomAudience 22 | from samples.samplecode.tests.sampletestcase import SampleTestCase 23 | from samples.samplecode.maca_cumulative import MacaCumulativeSample 24 | 25 | 26 | class MacaCumulativeTestCase(SampleTestCase): 27 | 28 | def setUp(self): 29 | super(MacaCumulativeTestCase, self).setUp() 30 | self.ca_sample = MacaCumulativeSample() 31 | 32 | def test_normal(self): 33 | self.caid = self.ca_sample.create_audience( 34 | self.account_id, 35 | app_id=self.app_info['fbapplication_id'], 36 | name='Test MACA', 37 | retention_days=180, 38 | event='fb_mobile_purchase', 39 | period='28d', 40 | greater_than=20, 41 | less_than=500, 42 | ) 43 | self.assertIsNotNone(self.caid, "Failed creating custom audience") 44 | 45 | def tearDown(self): 46 | super(MacaCumulativeTestCase, self).tearDown() 47 | if hasattr(self, 'caid'): 48 | ca = CustomAudience(self.caid) 49 | ca.remote_delete() 50 | -------------------------------------------------------------------------------- /samples/samplecode/tests/maca_frequency.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from facebookads.objects import CustomAudience 22 | from samples.samplecode.tests.sampletestcase import SampleTestCase 23 | from samples.samplecode.maca_frequency import MacaFrequencySample 24 | 25 | 26 | class MacaFrequencyTestCase(SampleTestCase): 27 | 28 | def setUp(self): 29 | super(MacaFrequencyTestCase, self).setUp() 30 | self.ca_sample = MacaFrequencySample() 31 | 32 | def test_normal(self): 33 | self.caid = self.ca_sample.create_audience( 34 | self.account_id, 35 | app_id=self.app_info['fbapplication_id'], 36 | name='Test MACA', 37 | retention_days=180, 38 | event='fb_mobile_purchase', 39 | period='28d', 40 | greater_than=20, 41 | less_than=500, 42 | ) 43 | self.assertIsNotNone(self.caid, "Failed creating custom audience") 44 | 45 | def tearDown(self): 46 | super(MacaFrequencyTestCase, self).tearDown() 47 | if hasattr(self, 'caid'): 48 | ca = CustomAudience(self.caid) 49 | ca.remote_delete() 50 | -------------------------------------------------------------------------------- /samples/samplecode/tests/multiple_lal.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from samples.samplecode.tests.sampletestcase import SampleTestCase 22 | from samples.samplecode.multiple_lal import MultipleLalSample 23 | 24 | 25 | class MultipleLalTestCase(SampleTestCase): 26 | 27 | def setUp(self): 28 | super(MultipleLalTestCase, self).setUp() 29 | self.sample = MultipleLalSample() 30 | 31 | def test_normal(self): 32 | self.created_lals = self.sample.create_lals( 33 | self.account_id, 34 | self.ca_id, 35 | "Multiple LAL Test", # lookalike_name 36 | ["US"], # country 37 | [1, 2], # ratio 38 | ) 39 | self.assertEqual(len(self.created_lals), 2) 40 | 41 | def tearDown(self): 42 | super(MultipleLalTestCase, self).tearDown() 43 | if hasattr(self, 'created_lals'): 44 | for lookalike in self.created_lals: 45 | lookalike.remote_delete() 46 | -------------------------------------------------------------------------------- /samples/samplecode/tests/orderlevelreporting.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from samples.samplecode.orderlevelreporting import OrderLevelReportingSample 22 | from samples.samplecode.tests.sampletestcase import SampleTestCase 23 | from datetime import date, timedelta 24 | 25 | 26 | class OrderLevelReportingTestCase(SampleTestCase): 27 | 28 | def setUp(self): 29 | super(OrderLevelReportingTestCase, self).setUp() 30 | 31 | self.TEST_BUSINESS = '722569367853065' 32 | self.sample = OrderLevelReportingSample() 33 | 34 | def test_normal(self): 35 | # get generator 36 | generator = self.sample.retrieve_order_level_report_data_parallel( 37 | from_date=date.today() - timedelta(days=8), 38 | to_date=date.today() - timedelta(days=7), 39 | business_id=self.TEST_BUSINESS, 40 | app_id='743337925789686', 41 | splits=3, 42 | ) 43 | 44 | # enumerate and make sure that we don't throw any errors 45 | self.assertListEqual(list(generator), []) 46 | -------------------------------------------------------------------------------- /samples/samplecode/tests/product_image_check.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from samples.samplecode.product_image_check import DPAImageCheckSample 22 | from samples.samplecode.tests.sampletestcase import SampleTestCase 23 | 24 | 25 | class ProductImageCheckTestCase(SampleTestCase): 26 | 27 | def setUp(self): 28 | super(ProductImageCheckTestCase, self).setUp() 29 | self.TEST_BUSINESS = '722569367853065' 30 | self.TEST_CATALOG = '1625011544447134' 31 | self.TEST_RETAILER = 'ps4' 32 | 33 | self.sample = DPAImageCheckSample() 34 | 35 | def test_normal(self): 36 | # get catalogs for business 37 | catalogs = self.sample.get_product_catalog_by_business_id( 38 | self.TEST_BUSINESS 39 | ) 40 | self.assertGreater(len(catalogs), 0, 'get catalogs') 41 | 42 | # check catalogs contain a catalog for testing. 43 | catalog_ids = [] 44 | for catalog in catalogs: 45 | catalog_ids.append(catalog['id']) 46 | self.assertIn(self.TEST_CATALOG, catalog_ids) 47 | 48 | # check result contains correct results 49 | check_result = self.sample.check_product_images( 50 | self.TEST_CATALOG, 51 | 5 52 | ) 53 | 54 | self.assertEqual(check_result[0], 5) 55 | self.assertEqual(check_result[1], 2) 56 | self.assertEqual(check_result[2], 0) 57 | -------------------------------------------------------------------------------- /samples/samplecode/tests/product_update.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from samples.samplecode.product_update import ProductUpdateSample 22 | from samples.samplecode.tests.sampletestcase import SampleTestCase 23 | from facebookads.objects import Product 24 | 25 | 26 | class ProductUpdateTestCase(SampleTestCase): 27 | 28 | def setUp(self): 29 | super(ProductUpdateTestCase, self).setUp() 30 | self.TEST_BUSINESS = '722569367853065' 31 | self.TEST_CATALOG = '1625011544447134' 32 | self.TEST_RETAILER = 'ps4' 33 | 34 | self.sample = ProductUpdateSample() 35 | 36 | def test_normal(self): 37 | # get catalogs for business 38 | catalogs = self.sample.get_product_catalog_by_business_id( 39 | self.TEST_BUSINESS 40 | ) 41 | self.assertGreater(len(catalogs), 0, 'get catalogs') 42 | 43 | # check catalogs contain a catalog for testing. 44 | catalog_ids = [] 45 | for catalog in catalogs: 46 | catalog_ids.append(catalog['id']) 47 | self.assertIn(self.TEST_CATALOG, catalog_ids) 48 | 49 | # get products for catalog 50 | products = self.sample.get_products_by_product_catalog_id( 51 | self.TEST_CATALOG 52 | ) 53 | self.assertGreater(len(products), 0, 'get products') 54 | 55 | # check result contains test product 56 | retailer_ids = [] 57 | for product in products: 58 | retailer_ids.append(product['retailer_id']) 59 | self.assertIn(self.TEST_RETAILER, retailer_ids) 60 | 61 | # update test product 62 | result = self.sample.update_product_item_by_retailer_id( 63 | self.TEST_CATALOG, 64 | self.TEST_RETAILER, 65 | { 66 | "availability": Product.Availability.in_stock 67 | } 68 | ) 69 | self.assertTrue(result.json()) 70 | -------------------------------------------------------------------------------- /samples/samplecode/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | 22 | def generate_batches(iterable, batch_size_limit): 23 | """ 24 | Generator that yields lists of length size batch_size_limit containing 25 | objects yielded by the iterable. 26 | """ 27 | batch = [] 28 | 29 | for item in iterable: 30 | if len(batch) == batch_size_limit: 31 | yield batch 32 | batch = [] 33 | batch.append(item) 34 | 35 | if len(batch): 36 | yield batch 37 | -------------------------------------------------------------------------------- /samples/seo_meta.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from meta.views import Meta 22 | from django.conf import settings 23 | 24 | meta = Meta( 25 | title="Facebook Marketing API Code Samples", 26 | description="The Facebook Marketing API Accelerator is your path to " 27 | "serious ads API skills and significant technical developer " 28 | "support.", 29 | keywords=[ 30 | 'facebook marketing api', 31 | 'facebook ads api', 32 | 'ads api', 33 | 'marketing automation', 34 | 'ads api samples', 35 | 'marketing api samples' 36 | ], 37 | use_og=True, 38 | use_twitter=True, 39 | use_facebook=True, 40 | facebook_app_id=settings.FACEBOOK_APP_ID, 41 | site_name="Facebook Marketing Developers", 42 | twitter_site='@fbplatform', 43 | twitter_card='summary_large_image', 44 | image='/static/images/fmd.jpg', 45 | ) 46 | -------------------------------------------------------------------------------- /samples/static/css/gallery.css: -------------------------------------------------------------------------------- 1 | body .anchor { 2 | position: relative; 3 | top: -65px; 4 | } 5 | 6 | .panel .fa-file-text { 7 | margin-right: 8px; 8 | } 9 | -------------------------------------------------------------------------------- /samples/static/css/samples.css: -------------------------------------------------------------------------------- 1 | .samples { 2 | margin-top: 40px; 3 | } 4 | .samples .sample { 5 | background-repeat: no-repeat; 6 | background-size: 80px 80px; 7 | height: 100px; 8 | background-position-y: center; 9 | margin-bottom: 10px; 10 | } 11 | .samples .sample h4 { 12 | margin: 27px 0 5px 0; 13 | } 14 | .samples .sample p { 15 | color: rgba(0,0,0,0.6); 16 | } 17 | 18 | .samples h2 { 19 | font-weight: 200; 20 | font-size: 19px; 21 | margin-bottom: 40px; 22 | line-height: 1.4em; 23 | } 24 | .sample-body { 25 | display: block; 26 | padding-left: 100px; 27 | line-height: 1em; 28 | font-size: 16px; 29 | } 30 | -------------------------------------------------------------------------------- /samples/static/images/accounts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/accounts.png -------------------------------------------------------------------------------- /samples/static/images/adcreation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/adcreation.png -------------------------------------------------------------------------------- /samples/static/images/adsreporting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/adsreporting.png -------------------------------------------------------------------------------- /samples/static/images/an_optin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/an_optin.png -------------------------------------------------------------------------------- /samples/static/images/app_install_ad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/app_install_ad.png -------------------------------------------------------------------------------- /samples/static/images/appengagement.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/appengagement.png -------------------------------------------------------------------------------- /samples/static/images/autobot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/autobot.png -------------------------------------------------------------------------------- /samples/static/images/ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/ca.png -------------------------------------------------------------------------------- /samples/static/images/carousel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/carousel.png -------------------------------------------------------------------------------- /samples/static/images/carousel_title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/carousel_title.png -------------------------------------------------------------------------------- /samples/static/images/carouselappad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/carouselappad.png -------------------------------------------------------------------------------- /samples/static/images/carouselappad_title.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/carouselappad_title.jpg -------------------------------------------------------------------------------- /samples/static/images/instagram_potential.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/instagram_potential.png -------------------------------------------------------------------------------- /samples/static/images/lead_ad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/lead_ad.png -------------------------------------------------------------------------------- /samples/static/images/maca_cumulative.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/maca_cumulative.png -------------------------------------------------------------------------------- /samples/static/images/maca_frequency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/maca_frequency.png -------------------------------------------------------------------------------- /samples/static/images/multiple_lal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/multiple_lal.png -------------------------------------------------------------------------------- /samples/static/images/product_audience_est.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/product_audience_est.png -------------------------------------------------------------------------------- /samples/static/images/productimagecheck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/productimagecheck.png -------------------------------------------------------------------------------- /samples/static/images/productupdate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/productupdate.png -------------------------------------------------------------------------------- /samples/static/images/targeting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/targeting.png -------------------------------------------------------------------------------- /samples/static/images/tiered_lookalike.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/static/images/tiered_lookalike.png -------------------------------------------------------------------------------- /samples/static/scripts/sample.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 3 | * 4 | * You are hereby granted a non-exclusive, worldwide, royalty-free license to 5 | * use, copy, modify, and distribute this software in source code or binary 6 | * form for use in connection with the web services and APIs provided by 7 | * Facebook. 8 | * 9 | * As with any software that integrates with the Facebook platform, your use 10 | * of this software is subject to the Facebook Developer Principles and 11 | * Policies [http://developers.facebook.com/policy/]. This copyright notice 12 | * shall be included in all copies or substantial portions of the software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE 21 | */ 22 | 23 | // Sample JS module 24 | // 25 | // initializes other modules needed by samples 26 | // 27 | // tracks sample view and sample run events 28 | 29 | /*global define, window, document*/ 30 | 31 | 'use strict'; 32 | 33 | define(['main', 'jquery'], function(main, $) { 34 | 35 | function _getFbEventParams() { 36 | return { 37 | 'content_ids': [window.app_config.sample_id], 38 | 'content_type': 'product', 39 | }; 40 | } 41 | 42 | function _getGAEventParams(action) { 43 | return { 44 | hitType: 'event', 45 | eventCategory: 'Sample', 46 | eventAction: action, 47 | eventLabel: window.app_config.sample_id, 48 | }; 49 | } 50 | // hook the form submit 51 | // to track when a sample runs 52 | $(document).ready(function() { 53 | // track the view sample event 54 | // using GA and FB Pixel 55 | main.eventsUtil.trackEvent([ 56 | 'send', 57 | _getGAEventParams('view'), 58 | ], [ 59 | 'track', 60 | 'ViewContent', 61 | _getFbEventParams(), 62 | ]); 63 | // hook form submit to track sample run 64 | $('form').submit(function() { 65 | // track the run sample event 66 | main.eventsUtil.trackEvent([ 67 | 'send', 68 | _getGAEventParams('run'), 69 | ], [ 70 | 'track', 71 | 'InitiateCheckout', 72 | _getFbEventParams(), // will use Purchase for sample code download 73 | ]); 74 | }); 75 | }); 76 | 77 | return { 78 | // expose any common sample utils here 79 | }; 80 | }); 81 | -------------------------------------------------------------------------------- /samples/templates/samples/accountlist.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/sample_base.html' %} 2 | {% block sample_ux %} 3 |
4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {% for account in accounts %} 13 | 14 | 15 | 16 | 17 | 18 | 19 | {% endfor %} 20 |
NameTimezoneSpentCurrency
{{account.name}}{{account.timezone_name}}{{ account.amount_spent}}{{account.currency}}
21 |
22 |
23 | {% endblock %} 24 | -------------------------------------------------------------------------------- /samples/templates/samples/ad_set_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/sample_base.html' %} 2 | {% block base_container %} 3 |
4 |
5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% for adset in ad_sets %} 19 | 20 | 21 | 22 | 23 | 35 | 36 | 46 | 55 | 56 | 57 | 58 | {% endfor %} 59 |
Ad Set IDObjectivePlacementObjective SupportedIG Audience Size / IG vs FBCreative IG ReadyOverall SuitabilitySuggestionsPreview on Instagram (the Instagram account is to be replaced by yours)
{{adset.id}}{{adset.c_objective}}
    {{adset.publisher_platforms|safe}}
{% if adset.objective_supported = 0 %} 24 | 25 | 26 | 27 | {% elif adset.objective_supported = 1 %} 28 | 29 | 30 | 31 | {% else %} 32 | Coming soon! 33 | {% endif %} 34 | {{adset.ig_audience}} / {{adset.audience}}%{% if adset.creative_ready = 0 %} 37 | 38 | 39 | 40 | {% else %} 41 | 42 | 43 | 44 | {% endif %} 45 | 47 | {% for i in "xxxxx" %} 48 | {% if forloop.counter0 < adset.eligibility %} 49 | 50 | {% else %} 51 | 52 | {% endif %} 53 | {% endfor %} 54 |
    {{adset.suggestion|safe}}
{{adset.preview_url|safe}}
60 |
61 |
62 |
63 | {% endblock %} 64 | -------------------------------------------------------------------------------- /samples/templates/samples/ads_reporting_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/sample_base.html' %} 2 | {% load bootstrap %} 3 | {% block sample_ux %} 4 |
5 |
6 |
7 | {% if data and data.ads_reports %} 8 |
9 | 10 | {% for row in data.ads_reports %} 11 | {% if forloop.first %} 12 | 13 | {% for col in row %} 14 | 15 | {% endfor %} 16 | 17 | {% else %} 18 | 19 | {% for col in row %} 20 | 21 | {% endfor %} 22 | 23 | {% endif %} 24 | {% endfor %} 25 |
{{col}}
{{col}}
26 |
27 | {% endif %} 28 |
29 |
30 |
31 | {% csrf_token %} 32 | {{ form|bootstrap }} 33 | 34 |
35 |
36 |
37 |
38 |
39 |
40 | {% endblock %} 41 | -------------------------------------------------------------------------------- /samples/templates/samples/autbot_config_editor_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/sample_base.html' %} 2 | {% load bootstrap %} 3 | {% block sample_ux %} 4 |
5 |
6 | {% if load_form %} 7 |
8 |
9 |
10 | {% csrf_token %} 11 | {{ load_form|bootstrap }} 12 | 16 |
17 |
18 |
19 | {% endif %} 20 |
21 |
22 |
23 | {% csrf_token %} 24 | {{ form|bootstrap }} 25 | 29 |
30 |
31 |
32 |
33 |
34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /samples/templates/samples/caform.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/sample_base.html' %} 2 | {% load bootstrap %} 3 | {% block sample_ux %} 4 |
5 |
6 |
7 |
8 |
9 | {% csrf_token %} 10 | {{ form|bootstrap }} 11 | 12 |
13 |
14 |
15 |
16 |
17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /samples/templates/samples/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | {% block seo_meta_tags %} 3 | Facebook Marketing API Code Samples | For Developers 4 | {% endblock %} 5 | {% block head_auxiliary %} 6 | 7 | {% endblock %} 8 | {% block body_block %} 9 |
10 |
11 |
12 |
13 |
14 |

Marketing API Solution Samples.

15 |

16 | A library of code for developers that features solutions to common tasks using Facebook Marketing API. These code samples allow you to use the power of the Marketing API to automation ad creation and management. 17 |

18 |
19 |
20 |
21 |
22 |
23 |
24 | {% for sample in object_list %} 25 | {% if not sample.hide_in_gallery %} 26 | 32 | {% endif %} 33 | {% endfor %} 34 |
35 | 36 |
37 |
38 | {% endblock %} -------------------------------------------------------------------------------- /samples/templates/samples/order_level_report.footer.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/templates/samples/order_level_report.footer.csv -------------------------------------------------------------------------------- /samples/templates/samples/order_level_report.footer.html: -------------------------------------------------------------------------------- 1 | 2 |

Total number of order IDs: {{cumulative_num_rows}}

3 |

Total number of outline rows: {{cumulative_num_outline_rows}}

4 |
5 |
6 | 7 | {% include 'common/footer.html' %} 8 | 9 | -------------------------------------------------------------------------------- /samples/templates/samples/order_level_report.footer.xls: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /samples/templates/samples/order_level_report.header.csv: -------------------------------------------------------------------------------- 1 | Order Timestamp,Order ID,Pixel ID,App ID,Attribution Type,Ad Account ID,Campaign ID,Adset ID,Ad ID,Action Type,Impression Cost,Click Cost,Impression Timestamp,Click Timestamp,Placement,Device 2 | -------------------------------------------------------------------------------- /samples/templates/samples/order_level_report.header.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/base.html' %} 2 | {% block body_block %} 3 |
4 |
5 |

Streaming in preview for Business ID: {{business_id}} {% if pixel_id %}Pixel ID: {{pixel_id}}{% endif %} {% if app_id %}App ID: {{app_id}}{% endif %} From: {{from_date|date:"r"}} Until: {{to_date|date:"r"}}

6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | {% endblock %} 25 | {% block base_container_close_tag %}{% endblock %} 26 | {% block end_html %}{% endblock %} -------------------------------------------------------------------------------- /samples/templates/samples/order_level_report.row.csv: -------------------------------------------------------------------------------- 1 | {% for orderid in data %}{% for attribution in orderid.attributions %}{{orderid.order_timestamp}},"{{orderid.order_id|addslashes}}",{{orderid.pixel_id}},{{orderid.app_id}},{{orderid.attribution_type}},{{attribution.account_id}},{{attribution.campaign_id}},{{attribution.adset_id}},{{attribution.ad_id}},{{attribution.action_type}},{{attribution.impression_cost}},{% if attribution.click_timestamp %}{{attribution.click_cost}}{% endif %},{{attribution.impression_timestamp}},{{attribution.click_timestamp}},{{attribution.placement}},{{attribution.device}} 2 | {% empty %}{{orderid.order_timestamp}},"{{orderid.order_id|addslashes}}",{{orderid.pixel_id}},{{orderid.app_id}},{{orderid.attribution_type}} 3 | {% endfor %}{% endfor %} -------------------------------------------------------------------------------- /samples/templates/samples/order_level_report.row.html: -------------------------------------------------------------------------------- 1 | {% for orderid in data|slice:preview_slice %} 2 | 3 | 4 | 5 | 6 | 7 | {% for attribution in orderid.attributions %} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {% endfor %} 22 | {% endfor %} 23 | -------------------------------------------------------------------------------- /samples/templates/samples/order_level_report.row.xls: -------------------------------------------------------------------------------- 1 | {% for orderid in data %}{% for attribution in orderid.attributions %} 2 | 3 | {{orderid.order_timestamp|slice:":-5"}} 4 | {{orderid.order_id}} 5 | {% if orderid.pixel_id %}{{orderid.pixel_id}}{% endif %} 6 | {% if orderid.app_id %}{{orderid.app_id}}{% endif %} 7 | {% if orderid.attribution_type %}{{orderid.attribution_type}}{% endif %} 8 | {{attribution.account_id}} 9 | {{attribution.campaign_id}} 10 | {{attribution.adset_id}} 11 | {{attribution.ad_id}} 12 | {{attribution.action_type}} 13 | {{attribution.impression_cost}} 14 | {% if attribution.click_timestamp %}{{attribution.click_cost}}{% endif %} 15 | {{attribution.impression_timestamp|slice:":-5"}} 16 | {% if attribution.click_timestamp %}{{attribution.click_timestamp|slice:":-5"}}{% endif %} 17 | {{attribution.placement}} 18 | {{attribution.device}} 19 | {% endfor %}{% endfor %} -------------------------------------------------------------------------------- /samples/templates/samples/product_audience_estimation_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/sample_base.html' %} 2 | {% load bootstrap %} 3 | {% block sample_ux %} 4 |
5 |
6 |
7 | {% if data and data.reachestimate %} 8 |
9 |

Product Audience Estimation

10 |

for AdAccount: {{data.ad_account_id}} + 11 | Product Set: {{data.product_set_id}}

12 |
{{data.reachestimate}}
13 |
Order TimestampOrder IDPixel/App IDAttribution TypeAd Account IDCampaign IDAdset IDAd IDAction TypeImpression CostClick CostImpression TimestampClick TimestampPlacementDevice
{{orderid.order_timestamp|slice:":10"}} {{orderid.order_timestamp|slice:"11:19"}}{{orderid.order_id}}{{orderid.pixel_id}} {{orderid.app_id}}{{orderid.attribution_type}}{{attribution.account_id}}{{attribution.campaign_id}}{{attribution.adset_id}}{{attribution.ad_id}}{{attribution.action_type}}{{attribution.impression_cost}}{% if attribution.click_timestamp %}{{attribution.click_cost}}{% endif %}{{attribution.impression_timestamp|slice:":10"}} {{attribution.impression_timestamp|slice:"11:19"}}{{attribution.click_timestamp|slice:":10"}} {{attribution.click_timestamp|slice:"11:19"}}{{attribution.placement}}{{attribution.device}}
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 32 | 33 |
Users{{data.reachestimate.users|stringformat:"i"}}
Estimate Ready{{data.reachestimate.estimate_ready}}
Bid Estimation 25 |
    26 |
  • min: {{data.reachestimate.bid_estimations.0.bid_amount_min}} 27 |
  • median: {{data.reachestimate.bid_estimations.0.bid_amount_median}} 28 |
  • max: {{data.reachestimate.bid_estimations.0.bid_amount_max}} 29 |
  • estimate_DAU: {{data.reachestimate.bid_estimations.0.estimate_DAU}} 30 |
31 |
34 |
35 | {% endif %} 36 |
37 |
38 |
39 | {% csrf_token %} 40 | {{ form|bootstrap }} 41 | 42 |
43 |
44 |
45 |
46 | 47 | 48 | {% endblock %} 49 | -------------------------------------------------------------------------------- /samples/templates/samples/product_image_check.html: -------------------------------------------------------------------------------- 1 | {% extends 'samples/sample_form.html' %} 2 | {% block sample_result %} 3 | {% if data.total_count > 0 %} 4 | 5 | 32 | 33 | 34 | 38 | 41 | 42 | {% if data.small_images_count > 0 %} 43 | 44 | 54 | 55 | {% endif %} 56 |
35 | {{data.total_count}} Products Analyzed 36 | 37 | 39 |
40 |
45 | For example, the default images of the following products are below 46 | 600x600px: 47 |
48 | {% for prod_url, img_url in data.small_images %} 49 | 50 |   52 | {% endfor %} 53 |
57 | {% else %} 58 | This product catalog is empty. 59 | {% endif %} 60 | {% endblock %} 61 | -------------------------------------------------------------------------------- /samples/templates/samples/sample_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'common/sample_base.html' %} 2 | {% load bootstrap %} 3 | {% block sample_ux %} 4 |
5 |
6 |
7 |
8 |
9 | {% csrf_token %} 10 | {{ form|bootstrap }} 11 | 15 |
16 |
17 |
18 |
19 |
20 | {% endblock %} 21 | -------------------------------------------------------------------------------- /samples/urls.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django.conf.urls import patterns, url 22 | from samples.views import sample 23 | 24 | 25 | urlpatterns = patterns( 26 | '', 27 | url(r'^(?P\w+)$', sample.SampleView.as_view(), name='sample'), 28 | url(r'^', sample.SampleCatalog.as_view(), name='index')) 29 | -------------------------------------------------------------------------------- /samples/views/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/samples/views/__init__.py -------------------------------------------------------------------------------- /samples/views/accountlist.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django.shortcuts import render 22 | from django.views.generic import View 23 | from samples.samplecode import accountlist 24 | from security.fbsample import fbads_sample 25 | 26 | 27 | class AccountListView(View): 28 | 29 | @fbads_sample('samples.samplecode.accountlist') 30 | def get(self, request, *args, **kwargs): 31 | sample = accountlist.AdAccountsList() 32 | accounts = sample.get_accounts() 33 | # name is an optional field 34 | for account in accounts: 35 | amount_spent = int(account["amount_spent"]) 36 | if (amount_spent > 0): 37 | account["amount_spent"] = amount_spent / 100 38 | 39 | if not (account["name"]): 40 | account["name"] = account["id"] 41 | 42 | return render( 43 | request, 44 | 'samples/accountlist.html', 45 | {'accounts': accounts}) 46 | -------------------------------------------------------------------------------- /samples/views/customaudience.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django import forms 22 | from samples.samplecode import customaudience 23 | from samples.views.sample import SampleBaseView 24 | from components.component_form import ComponentForm 25 | from components.ad_account_select import AdAccountSelect 26 | from components.file_input import FileInput 27 | from security.fbsample import fbads_sample 28 | 29 | 30 | class CustomAudienceForm(ComponentForm): 31 | 32 | ad_account = AdAccountSelect() 33 | name = forms.CharField(max_length=50) 34 | description = forms.CharField(max_length=100, required=False) 35 | optout_link = forms.URLField() 36 | data_file = FileInput( 37 | max_length=5242880, 38 | allow_empty_file=False, 39 | help_text='''Data format: one hash per line.''', 40 | ) 41 | 42 | 43 | class CustomAudienceView(SampleBaseView): 44 | 45 | BUTTON_TEXT = "Create Custom Audience" 46 | 47 | @fbads_sample('samples.samplecode.customaudience') 48 | def get(self, request, *args, **kwargs): 49 | form = CustomAudienceForm(request.last_error_post) 50 | return self.render_form(request, form) 51 | 52 | @fbads_sample('samples.samplecode.customaudience') 53 | def post(self, request, *args, **kwargs): 54 | form = CustomAudienceForm(request.POST, request.FILES) 55 | if not form.is_valid(): 56 | return self.render_invalid_form(request, form) 57 | 58 | schema = customaudience.CustomAudience.Schema.email_hash 59 | casample = customaudience.CustomAudienceSample() 60 | caid = casample.create_audience( 61 | form.cleaned_data['ad_account'], 62 | form.cleaned_data['name'], 63 | form.cleaned_data['description'], 64 | form.cleaned_data['optout_link']) 65 | cadata = [] 66 | for line in form.cleaned_data['data_file']: 67 | cadata.append(line) 68 | 69 | result = casample.upload_users_to_audience(caid, cadata, schema) 70 | status = result.body() 71 | 72 | return self.render_form_with_status(request, form, status) 73 | -------------------------------------------------------------------------------- /samples/views/targeting.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from samples.views.sample import SampleBaseView 22 | from components.component_form import ComponentForm 23 | from components.ad_account_select import AdAccountSelect 24 | from components.targeting_spec import TargetingSpec 25 | from security.fbsample import fbads_sample 26 | 27 | 28 | class TargetingForm(ComponentForm): 29 | 30 | ad_account = AdAccountSelect() 31 | targeting_spec = TargetingSpec() 32 | 33 | 34 | class TargetingView(SampleBaseView): 35 | 36 | @fbads_sample('samples.samplecode.targeting') 37 | def get(self, request, *args, **kwargs): 38 | form = TargetingForm(request.last_error_post) 39 | return self.render_form(request, form) 40 | 41 | @fbads_sample('samples.samplecode.targeting') 42 | def post(self, request, *args, **kwargs): 43 | form = TargetingForm(request.POST, request.FILES) 44 | if not form.is_valid(): 45 | return self.render_invalid_form(request, form) 46 | 47 | status = "OK" 48 | return self.render_form_with_status(request, form, status) 49 | -------------------------------------------------------------------------------- /security/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/security/__init__.py -------------------------------------------------------------------------------- /security/middleware.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django.http import HttpResponseRedirect 22 | from django.conf import settings 23 | 24 | class SslRedirect: 25 | def process_request(self, request): 26 | request_url = request.build_absolute_uri() 27 | original = request_url 28 | 29 | if not request.is_secure(): 30 | # enforce https 31 | request_url = request_url.replace('http://', 'https://') 32 | 33 | if settings.IS_RELEASE(): 34 | # only do this in release/production 35 | # replace non-www domain to www-domain 36 | if not request_url.startswith('https://www.'): 37 | request_url = request_url.replace( 38 | 'https://', 39 | 'https://www.', 1 40 | ) 41 | 42 | if original == request_url: 43 | # do nothing when we did not change the url to avoid cycle 44 | # redirecting issue. 45 | return None 46 | else: 47 | return HttpResponseRedirect(request_url) 48 | -------------------------------------------------------------------------------- /security/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | import django.utils.timezone 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='FBUser', 16 | fields=[ 17 | ('password', models.CharField(max_length=128, verbose_name='password')), 18 | ('last_login', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login')), 19 | ('fb_userid', models.CharField(max_length=20, serialize=False, primary_key=True)), 20 | ('fb_username', models.CharField(unique=True, max_length=50)), 21 | ('full_name', models.CharField(unique=False, max_length=61)), 22 | ], 23 | options={ 24 | 'abstract': False, 25 | }, 26 | bases=(models.Model,), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /security/migrations/0002_role.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | from django.conf import settings 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('security', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='FBUserInRole', 17 | fields=[ 18 | ('id', models.AutoField( 19 | verbose_name='ID', 20 | serialize=False, 21 | auto_created=True, 22 | primary_key=True 23 | )), 24 | ('fb_userid', models.ForeignKey(to=settings.AUTH_USER_MODEL)), 25 | ], 26 | options={ 27 | }, 28 | bases=(models.Model,), 29 | ), 30 | migrations.CreateModel( 31 | name='Role', 32 | fields=[ 33 | ('name', models.CharField( 34 | max_length=20, 35 | serialize=False, 36 | primary_key=True 37 | )), 38 | ('description', models.CharField(max_length=200)), 39 | ], 40 | options={ 41 | }, 42 | bases=(models.Model,), 43 | ), 44 | migrations.AddField( 45 | model_name='fbuserinrole', 46 | name='role', 47 | field=models.ForeignKey(to='security.Role'), 48 | preserve_default=True, 49 | ), 50 | ] 51 | -------------------------------------------------------------------------------- /security/migrations/0003_auto_20160602_0605.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('security', '0002_role'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='fbuserinrole', 16 | name='fb_userid', 17 | field=models.ForeignKey(to='security.FBUser'), 18 | preserve_default=True, 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /security/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbsamples/marketing-api-samples/5395f6d48bccde8b8f1c8c37a01baf39611bfedf/security/migrations/__init__.py -------------------------------------------------------------------------------- /security/urls.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | # 3 | # You are hereby granted a non-exclusive, worldwide, royalty-free license to 4 | # use, copy, modify, and distribute this software in source code or binary 5 | # form for use in connection with the web services and APIs provided by 6 | # Facebook. 7 | # 8 | # As with any software that integrates with the Facebook platform, your use of 9 | # this software is subject to the Facebook Developer Principles and Policies 10 | # [http://developers.facebook.com/policy/]. This copyright notice shall be 11 | # included in all copies or substantial portions of the software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | from django.conf.urls import url 22 | from security import views 23 | 24 | urlpatterns = [ 25 | url(r'^login/$', views.do_login, name='login'), 26 | url(r'^logout/$', views.do_logout, name='logout'), 27 | url(r'^oauth/$', views.oauth, name='oauth'), 28 | url(r'^fbcallback/$', views.auth_callback, name='fbcallback'), 29 | ] 30 | --------------------------------------------------------------------------------