├── developerportal
├── __init__.py
├── apps
│ ├── __init__.py
│ ├── home
│ │ ├── __init__.py
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ └── test_home.py
│ │ └── migrations
│ │ │ ├── __init__.py
│ │ │ ├── 0018_merge_20190702_1247.py
│ │ │ ├── 0019_merge_20190709_0910.py
│ │ │ ├── 0037_remove_homepage_show_header.py
│ │ │ ├── 0035_remove_homepage_external_promos.py
│ │ │ ├── 0010_auto_20190704_1031.py
│ │ │ ├── 0024_auto_20190718_1438.py
│ │ │ ├── 0032_homepage_show_header.py
│ │ │ ├── 0009_homepage_featured.py
│ │ │ ├── 0029_update_home_manager.py
│ │ │ ├── 0026_auto_20190813_1302.py
│ │ │ ├── 0011_auto_20190705_1258.py
│ │ │ ├── 0030_add_social_image_field.py
│ │ │ ├── 0009_auto_20190702_0904.py
│ │ │ ├── 0031_homepage_featured_people.py
│ │ │ ├── 0006_auto_20190625_1111.py
│ │ │ ├── 0007_auto_20190625_1112.py
│ │ │ └── 0008_auto_20190625_1119.py
│ ├── search
│ │ ├── models.py
│ │ ├── __init__.py
│ │ ├── tests
│ │ │ └── __init__.py
│ │ └── urls.py
│ ├── articles
│ │ ├── __init__.py
│ │ ├── tests
│ │ │ └── __init__.py
│ │ ├── migrations
│ │ │ ├── __init__.py
│ │ │ ├── 0013_merge_20190603_1229.py
│ │ │ ├── 0007_merge_20190517_1323.py
│ │ │ ├── 0014_merge_20190604_0953.py
│ │ │ ├── 0027_merge_20190802_1535.py
│ │ │ ├── 0028_merge_20190805_1426.py
│ │ │ ├── 0020_auto_20190612_0426.py
│ │ │ ├── 0023_auto_20190709_0928.py
│ │ │ ├── 0005_auto_20190516_1236.py
│ │ │ ├── 0040_remove_article_image.py
│ │ │ ├── 0021_auto_20190618_0840.py
│ │ │ ├── 0003_article_intro.py
│ │ │ ├── 0004_auto_20190516_0907.py
│ │ │ ├── 0002_article_date.py
│ │ │ ├── 0026_articles_description.py
│ │ │ ├── 0016_auto_20190604_1317.py
│ │ │ ├── 0019_auto_20190611_1453.py
│ │ │ ├── 0035_soft_rename_Article_as_Post_via_meta.py
│ │ │ ├── 0010_article_labels.py
│ │ │ ├── 0011_auto_20190522_1630.py
│ │ │ ├── 0017_auto_20190611_1344.py
│ │ │ ├── 0012_auto_20190603_1048.py
│ │ │ ├── 0029_auto_20190813_1302.py
│ │ │ ├── 0032_update_article_manager.py
│ │ │ ├── 0002_article_body.py
│ │ │ ├── 0022_auto_20190624_1622.py
│ │ │ ├── 0006_auto_20190516_1303.py
│ │ │ ├── 0012_article_header_image.py
│ │ │ ├── 0012_article_author.py
│ │ │ └── 0039_copy_image_field_data_to_card_image_field.py
│ │ ├── templates
│ │ │ ├── partials
│ │ │ │ └── verbose_standfirst.html
│ │ │ └── articles.html
│ │ └── wagtail_hooks.py
│ ├── common
│ │ ├── __init__.py
│ │ ├── tasks
│ │ │ └── __init__.py
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── test_survey_tags.py
│ │ │ └── test_models.py
│ │ ├── migrations
│ │ │ └── __init__.py
│ │ ├── templates
│ │ │ ├── code_snippet_block.html
│ │ │ └── button_block.html
│ │ ├── views.py
│ │ ├── validators.py
│ │ ├── test_helpers.py
│ │ ├── image_formats.py
│ │ └── settings_helpers.py
│ ├── content
│ │ ├── __init__.py
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ └── test_content.py
│ │ └── migrations
│ │ │ ├── __init__.py
│ │ │ ├── 0011_remove_contentpage_hero_image.py
│ │ │ ├── 0004_update_content_manager.py
│ │ │ ├── 0008_contentpage_nav_description.py
│ │ │ ├── 0007_contentpage_description.py
│ │ │ ├── 0005_add_social_image_field.py
│ │ │ ├── 0012_auto_20200511_1148.py
│ │ │ ├── 0006_contentpage_icon.py
│ │ │ ├── 0002_contentpage_hero_image.py
│ │ │ ├── 0014_contentpage_card_image_3_2.py
│ │ │ ├── 0015_hide_about_page_from_menu.py
│ │ │ └── 0010_copy_hero_image_field_to_card_image_field.py
│ ├── events
│ │ ├── __init__.py
│ │ ├── tests
│ │ │ └── __init__.py
│ │ ├── migrations
│ │ │ ├── __init__.py
│ │ │ ├── 0004_merge_20190711_1925.py
│ │ │ ├── 0005_merge_20190711_2019.py
│ │ │ ├── 0003_auto_20190709_0928.py
│ │ │ ├── 0010_auto_20190718_1551.py
│ │ │ ├── 0023_remove_event_image.py
│ │ │ ├── 0003_auto_20190709_1241.py
│ │ │ ├── 0028_event_is_mozilla_supported_event.py
│ │ │ ├── 0017_auto_20190819_1304.py
│ │ │ ├── 0014_auto_20190813_1302.py
│ │ │ ├── 0018_update_event_manager.py
│ │ │ ├── 0022_copy_image_field_data_to_card_image_field.py
│ │ │ └── 0021_auto_20200326_1339.py
│ │ └── wagtail_hooks.py
│ ├── health
│ │ ├── __init__.py
│ │ ├── tests
│ │ │ └── __init__.py
│ │ └── urls.py
│ ├── mozimages
│ │ ├── __init__.py
│ │ ├── migrations
│ │ │ └── __init__.py
│ │ └── models.py
│ ├── people
│ │ ├── __init__.py
│ │ ├── tests
│ │ │ └── __init__.py
│ │ ├── migrations
│ │ │ ├── __init__.py
│ │ │ ├── 0019_remove_people_keywords.py
│ │ │ ├── 0010_merge_20190627_1318.py
│ │ │ ├── 0011_merge_20190627_1428.py
│ │ │ ├── 0023_merge_20190802_1535.py
│ │ │ ├── 0012_merge_20190628_1108.py
│ │ │ ├── 0013_merge_20190702_1247.py
│ │ │ ├── 0013_merge_20190702_1300.py
│ │ │ ├── 0014_merge_20190702_1619.py
│ │ │ ├── 0009_auto_20190626_0848.py
│ │ │ ├── 0009_auto_20190626_1353.py
│ │ │ ├── 0010_auto_20190625_1258.py
│ │ │ ├── 0015_auto_20190709_0928.py
│ │ │ ├── 0036_remove_person_image.py
│ │ │ ├── 0005_person_is_mozillian.py
│ │ │ ├── 0012_auto_20190702_1059.py
│ │ │ ├── 0031_person_nickname.py
│ │ │ ├── 0027_person_country.py
│ │ │ ├── 0022_people_description.py
│ │ │ ├── 0034_people_nav_description.py
│ │ │ ├── 0024_auto_20190813_1302.py
│ │ │ ├── 0032_auto_20191008_1530.py
│ │ │ ├── 0038_make_Person_country_optional.py
│ │ │ ├── 0037_auto_20200511_1148.py
│ │ │ ├── 0004_auto_20190530_1441.py
│ │ │ ├── 0026_auto_20190819_1304.py
│ │ │ ├── 0033_people_icon.py
│ │ │ ├── 0028_auto_20190926_1049.py
│ │ │ ├── 0029_update_person_manager.py
│ │ │ ├── 0006_auto_20190604_1050.py
│ │ │ ├── 0035_copy_image_field_to_card_image_field.py
│ │ │ ├── 0018_people_keywords.py
│ │ │ └── 0020_people_keywords.py
│ │ ├── wagtail_hooks.py
│ │ ├── edit_handlers.py
│ │ └── templates
│ │ │ └── people.html
│ ├── topics
│ │ ├── __init__.py
│ │ ├── tests
│ │ │ └── __init__.py
│ │ ├── migrations
│ │ │ ├── __init__.py
│ │ │ ├── 0014_merge_20190618_1609.py
│ │ │ ├── 0013_merge_20190618_1635.py
│ │ │ ├── 0013_merge_20190619_1357.py
│ │ │ ├── 0024_merge_20190702_1619.py
│ │ │ ├── 0026_merge_20190704_1459.py
│ │ │ ├── 0028_merge_20190710_1633.py
│ │ │ ├── 0015_merge_20190619_1437.py
│ │ │ ├── 0015_merge_20190619_1506.py
│ │ │ ├── 0017_merge_20190621_1033.py
│ │ │ ├── 0017_merge_20190624_0904.py
│ │ │ ├── 0018_merge_20190624_1248.py
│ │ │ ├── 0018_merge_20190624_1252.py
│ │ │ ├── 0019_merge_20190625_1257.py
│ │ │ ├── 0015_merge_20190621_1009.py
│ │ │ ├── 0007_auto_20190611_1542.py
│ │ │ ├── 0027_auto_20190709_0928.py
│ │ │ ├── 0054_remove_topic_color.py
│ │ │ ├── 0046_remove_topic_tabbed_panels_title.py
│ │ │ ├── 0050_remove_topic_latest_articles_count.py
│ │ │ ├── 0013_topic_icon.py
│ │ │ ├── 0010_auto_20190618_0840.py
│ │ │ ├── 0008_auto_20190612_1759.py
│ │ │ ├── 0016_auto_20190619_1437.py
│ │ │ ├── 0016_auto_20190619_1506.py
│ │ │ ├── 0016_auto_20190624_1129.py
│ │ │ ├── 0038_topic_latest_articles_count.py
│ │ │ ├── 0049_topic_nav_description.py
│ │ │ ├── 0033_auto_20190718_1452.py
│ │ │ ├── 0039_auto_20190805_0806.py
│ │ │ ├── 0005_auto_20190610_1413.py
│ │ │ ├── 0043_auto_20190819_1304.py
│ │ │ ├── 0052_auto_20200511_1148.py
│ │ │ ├── 0055_topic_relevant_events.py
│ │ │ ├── 0009_topic_color.py
│ │ │ ├── 0040_auto_20190813_1302.py
│ │ │ └── 0044_update_topic_manager.py
│ │ ├── wagtail_hooks.py
│ │ └── templates
│ │ │ └── topics.html
│ ├── videos
│ │ ├── __init__.py
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ └── test_videos.py
│ │ ├── migrations
│ │ │ ├── __init__.py
│ │ │ ├── 0012_remove_video_image.py
│ │ │ ├── 0007_auto_20190819_1304.py
│ │ │ ├── 0004_auto_20190813_1302.py
│ │ │ ├── 0008_update_video_manager.py
│ │ │ └── 0011_copy_image_to_card_image.py
│ │ └── wagtail_hooks.py
│ ├── externalcontent
│ │ ├── __init__.py
│ │ ├── tests
│ │ │ └── __init__.py
│ │ └── migrations
│ │ │ ├── __init__.py
│ │ │ ├── 0002_auto_20190704_1221.py
│ │ │ ├── 0012_auto_20190724_1437.py
│ │ │ ├── 0029_rename_image_to_card_image.py
│ │ │ ├── 0019_auto_20190813_1302.py
│ │ │ ├── 0008_externalcontent_description.py
│ │ │ ├── 0027_relabel_external_article_as_external_post.py
│ │ │ ├── 0013_externalevent_venue.py
│ │ │ ├── 0025_add_social_image_field.py
│ │ │ ├── 0022_auto_20190819_1304.py
│ │ │ ├── 0018_auto_20190807_1244.py
│ │ │ └── 0004_auto_20190705_1306.py
│ ├── ingestion
│ │ ├── tests
│ │ │ └── __init__.py
│ │ ├── migrations
│ │ │ └── __init__.py
│ │ ├── __init__.py
│ │ ├── constants.py
│ │ ├── admin.py
│ │ └── apps.py
│ └── taskqueue
│ │ ├── tests
│ │ ├── __init__.py
│ │ └── test_wagtail_hooks.py
│ │ ├── models.py
│ │ ├── __init__.py
│ │ └── wagtail_hooks.py
├── settings
│ ├── __init__.py
│ ├── worker.py
│ ├── test_fast.py
│ ├── test.py
│ └── dev.py
├── templates
│ ├── robots.txt
│ ├── wagtailadmin
│ │ ├── home.html
│ │ ├── 404.html
│ │ ├── admin_base.html
│ │ └── login.html
│ ├── molecules
│ │ ├── accessibility-nav.html
│ │ ├── image-block.html
│ │ ├── cards
│ │ │ └── card.html
│ │ └── site-search-form.html
│ ├── atoms
│ │ ├── icons
│ │ │ ├── close.svg
│ │ │ ├── facebook.svg
│ │ │ ├── person.svg
│ │ │ ├── location.svg
│ │ │ ├── video.svg
│ │ │ └── reading-time.svg
│ │ ├── image.html
│ │ └── label.html
│ └── organisms
│ │ ├── featured-events--four-up.html
│ │ ├── homepage-header.html
│ │ ├── partials
│ │ └── featured-card-selector.html
│ │ ├── article-read-more.html
│ │ └── homepage-about.html
├── regex.py
├── templatetags
│ └── survey_tags.py
└── wsgi.py
├── src
├── css
│ ├── molecules
│ │ ├── card-featured.scss
│ │ ├── card-event.scss
│ │ ├── card-person.scss
│ │ ├── notification-bar.scss
│ │ ├── pagination.scss
│ │ ├── site-search-form.scss
│ │ ├── accessibility-nav.scss
│ │ ├── resource-toolbar.scss
│ │ └── search-result.scss
│ ├── organisms
│ │ ├── featured.scss
│ │ ├── article-read-more.scss
│ │ ├── topic-links.scss
│ │ ├── search-results.scss
│ │ └── people-section.scss
│ ├── templates
│ │ ├── video.scss
│ │ ├── content-page.scss
│ │ ├── site-search.scss
│ │ ├── article.scss
│ │ ├── events.scss
│ │ └── event.scss
│ ├── atoms
│ │ ├── icon.scss
│ │ ├── buttons.scss
│ │ ├── rich-text.scss
│ │ ├── modal.scss
│ │ ├── label.scss
│ │ ├── quote.scss
│ │ ├── image.scss
│ │ └── embed.scss
│ ├── admin.scss
│ └── global
│ │ └── layout.scss
├── js
│ ├── admin-extras.js
│ ├── head-includes.js
│ └── organisms
│ │ └── notification-bar.js
├── img
│ ├── http-error.png
│ ├── homepage@1x.png
│ ├── homepage@2x.png
│ ├── icons
│ │ ├── favicon.ico
│ │ ├── website.png
│ │ ├── favicon_dev.ico
│ │ ├── favicon_stage.ico
│ │ ├── expand.svg
│ │ ├── expand-white.svg
│ │ ├── menu-arrow.svg
│ │ ├── menu.svg
│ │ ├── menu-white.svg
│ │ ├── close.svg
│ │ ├── close-white.svg
│ │ ├── article-white.svg
│ │ ├── content-white.svg
│ │ ├── social
│ │ │ ├── protocol
│ │ │ │ ├── white.svg
│ │ │ │ └── black.svg
│ │ │ ├── firefox
│ │ │ │ └── black.svg
│ │ │ └── facebook
│ │ │ │ ├── black.svg
│ │ │ │ ├── brand.svg
│ │ │ │ └── white.svg
│ │ ├── arrow-left.svg
│ │ ├── arrow-left-white.svg
│ │ ├── events-white.svg
│ │ ├── search-black.svg
│ │ ├── search-white.svg
│ │ ├── map-pin.svg
│ │ ├── video.svg
│ │ ├── video-white.svg
│ │ └── speaker.svg
│ ├── promo
│ │ ├── mdn@1x.jpg
│ │ ├── mdn@2x.jpg
│ │ ├── mdn-dino@1x.jpg
│ │ ├── mdn-dino@2x.jpg
│ │ ├── newsletter@1x.jpg
│ │ ├── newsletter@2x.jpg
│ │ ├── firefox-developer@1x.jpg
│ │ └── firefox-developer@2x.jpg
│ ├── logos
│ │ ├── mozilla
│ │ │ ├── black.png
│ │ │ ├── white.png
│ │ │ ├── black@2x.png
│ │ │ ├── black@3x.png
│ │ │ ├── white@2x.png
│ │ │ └── white@3x.png
│ │ ├── firefox
│ │ │ ├── logo-word-hor-sm.png
│ │ │ └── logo-word-hor-sm-high-res.png
│ │ └── mdn-dino-white.svg
│ ├── placeholders
│ │ ├── article.jpg
│ │ ├── event_16_9.jpg
│ │ ├── event_3_2.jpg
│ │ ├── person_3_2.jpg
│ │ ├── post_16_9.jpg
│ │ ├── post_3_2.jpg
│ │ ├── person_16_9.jpg
│ │ └── original
│ │ │ ├── post_3_2.jpg
│ │ │ ├── event_16_9.jpg
│ │ │ ├── event_3_2.jpg
│ │ │ ├── person_16_9.jpg
│ │ │ ├── person_3_2.jpg
│ │ │ └── post_16_9.jpg
│ └── hamburger.svg
└── fonts
│ ├── Inter-Bold.woff
│ ├── Inter-Bold.woff2
│ ├── Inter-Italic.woff
│ ├── Inter-Italic.woff2
│ ├── Inter-Regular.woff
│ ├── Inter-Regular.woff2
│ ├── ZillaSlab-Bold.woff
│ ├── ZillaSlab-Bold.woff2
│ ├── Inter-BoldItalic.woff
│ ├── Inter-BoldItalic.woff2
│ ├── ZillaSlab-Regular.woff
│ ├── ZillaSlab-Regular.woff2
│ ├── ZillaSlab-SemiBold.woff
│ ├── ZillaSlab-SemiBold.woff2
│ ├── ZillaSlabHighlight-Bold.woff
│ ├── ZillaSlabHighlight-Bold.woff2
│ ├── ZillaSlabHighlight-Regular.woff
│ └── ZillaSlabHighlight-Regular.woff2
├── .prettierignore
├── .eslintignore
├── scripts
└── ci-tests
├── setup.cfg
├── .github
├── ISSUE_TEMPLATE
│ ├── custom.md
│ └── feature_request.md
└── pull_request_template.md
├── .editorconfig
├── renovate.json
├── etc
└── nginx
│ └── ssl
│ ├── README.md
│ ├── cfssl.json
│ ├── ca-config.json
│ └── gen-cert.sh
├── data
├── README.md
└── devportal_topic_icons
│ ├── search.svg
│ ├── default-d.svg
│ └── html.svg
├── k8s
├── redirector.svc.yaml.j2
├── hpa.yaml.j2
├── redirector.ingress.yaml.j2
├── db-migration-job.yaml.j2
├── search-index-update-job.yaml.j2
├── wait_for_job.sh
└── app.svc.yaml.j2
├── locust
└── docker-compose.yml
├── .isort.cfg
├── CODE_OF_CONDUCT.md
├── manage.py
├── .travis.yml
└── requirements.txt
/developerportal/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/home/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/search/models.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/settings/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/css/molecules/card-featured.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/common/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/content/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/events/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/health/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/home/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/mozimages/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/people/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/search/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/videos/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/common/tasks/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/common/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/content/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/events/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/health/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/ingestion/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/people/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/search/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/taskqueue/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/videos/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/common/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/content/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/events/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/ingestion/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/mozimages/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/videos/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/js/admin-extras.js:
--------------------------------------------------------------------------------
1 | import '../css/admin.scss';
2 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist
2 | *.py
3 | *.pyc
4 | *.html
5 | *.svg
6 | *.json
7 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
2 | *.scss
3 | *.py
4 | *.pyc
5 | *.html
6 | *.svg
7 | renovate.json
8 |
--------------------------------------------------------------------------------
/src/css/molecules/card-event.scss:
--------------------------------------------------------------------------------
1 | address.mzp-c-card-desc {
2 | font-style: normal;
3 | }
4 |
--------------------------------------------------------------------------------
/src/img/http-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/http-error.png
--------------------------------------------------------------------------------
/developerportal/apps/taskqueue/models.py:
--------------------------------------------------------------------------------
1 | # empty models.py to allow Django to accept the `taskqueue` app
2 |
--------------------------------------------------------------------------------
/src/fonts/Inter-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/Inter-Bold.woff
--------------------------------------------------------------------------------
/src/img/homepage@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/homepage@1x.png
--------------------------------------------------------------------------------
/src/img/homepage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/homepage@2x.png
--------------------------------------------------------------------------------
/src/img/icons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/icons/favicon.ico
--------------------------------------------------------------------------------
/src/img/icons/website.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/icons/website.png
--------------------------------------------------------------------------------
/src/img/promo/mdn@1x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/promo/mdn@1x.jpg
--------------------------------------------------------------------------------
/src/img/promo/mdn@2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/promo/mdn@2x.jpg
--------------------------------------------------------------------------------
/src/fonts/Inter-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/Inter-Bold.woff2
--------------------------------------------------------------------------------
/src/fonts/Inter-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/Inter-Italic.woff
--------------------------------------------------------------------------------
/src/js/head-includes.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-unresolved */
2 |
3 | require('./mozilla-dnthelper');
4 |
--------------------------------------------------------------------------------
/src/fonts/Inter-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/Inter-Italic.woff2
--------------------------------------------------------------------------------
/src/fonts/Inter-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/Inter-Regular.woff
--------------------------------------------------------------------------------
/src/fonts/Inter-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/Inter-Regular.woff2
--------------------------------------------------------------------------------
/src/fonts/ZillaSlab-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/ZillaSlab-Bold.woff
--------------------------------------------------------------------------------
/src/fonts/ZillaSlab-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/ZillaSlab-Bold.woff2
--------------------------------------------------------------------------------
/src/img/icons/favicon_dev.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/icons/favicon_dev.ico
--------------------------------------------------------------------------------
/src/img/promo/mdn-dino@1x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/promo/mdn-dino@1x.jpg
--------------------------------------------------------------------------------
/src/img/promo/mdn-dino@2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/promo/mdn-dino@2x.jpg
--------------------------------------------------------------------------------
/src/fonts/Inter-BoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/Inter-BoldItalic.woff
--------------------------------------------------------------------------------
/src/fonts/Inter-BoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/Inter-BoldItalic.woff2
--------------------------------------------------------------------------------
/src/fonts/ZillaSlab-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/ZillaSlab-Regular.woff
--------------------------------------------------------------------------------
/src/img/icons/favicon_stage.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/icons/favicon_stage.ico
--------------------------------------------------------------------------------
/src/img/logos/mozilla/black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/logos/mozilla/black.png
--------------------------------------------------------------------------------
/src/img/logos/mozilla/white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/logos/mozilla/white.png
--------------------------------------------------------------------------------
/src/img/placeholders/article.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/placeholders/article.jpg
--------------------------------------------------------------------------------
/src/img/promo/newsletter@1x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/promo/newsletter@1x.jpg
--------------------------------------------------------------------------------
/src/img/promo/newsletter@2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/promo/newsletter@2x.jpg
--------------------------------------------------------------------------------
/developerportal/templates/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow: /admin/
3 | Disallow: /django-admin/
4 | Disallow: /static/
5 |
--------------------------------------------------------------------------------
/src/fonts/ZillaSlab-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/ZillaSlab-Regular.woff2
--------------------------------------------------------------------------------
/src/fonts/ZillaSlab-SemiBold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/ZillaSlab-SemiBold.woff
--------------------------------------------------------------------------------
/src/fonts/ZillaSlab-SemiBold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/ZillaSlab-SemiBold.woff2
--------------------------------------------------------------------------------
/src/img/logos/mozilla/black@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/logos/mozilla/black@2x.png
--------------------------------------------------------------------------------
/src/img/logos/mozilla/black@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/logos/mozilla/black@3x.png
--------------------------------------------------------------------------------
/src/img/logos/mozilla/white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/logos/mozilla/white@2x.png
--------------------------------------------------------------------------------
/src/img/logos/mozilla/white@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/logos/mozilla/white@3x.png
--------------------------------------------------------------------------------
/src/img/placeholders/event_16_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/placeholders/event_16_9.jpg
--------------------------------------------------------------------------------
/src/img/placeholders/event_3_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/placeholders/event_3_2.jpg
--------------------------------------------------------------------------------
/src/img/placeholders/person_3_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/placeholders/person_3_2.jpg
--------------------------------------------------------------------------------
/src/img/placeholders/post_16_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/placeholders/post_16_9.jpg
--------------------------------------------------------------------------------
/src/img/placeholders/post_3_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/placeholders/post_3_2.jpg
--------------------------------------------------------------------------------
/src/img/placeholders/person_16_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/placeholders/person_16_9.jpg
--------------------------------------------------------------------------------
/src/css/organisms/featured.scss:
--------------------------------------------------------------------------------
1 | .featured-items-wrapper {
2 | .mzp-l-card-half {
3 | margin-bottom: $spacing-md;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/fonts/ZillaSlabHighlight-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/ZillaSlabHighlight-Bold.woff
--------------------------------------------------------------------------------
/src/fonts/ZillaSlabHighlight-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/ZillaSlabHighlight-Bold.woff2
--------------------------------------------------------------------------------
/src/img/promo/firefox-developer@1x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/promo/firefox-developer@1x.jpg
--------------------------------------------------------------------------------
/src/img/promo/firefox-developer@2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/promo/firefox-developer@2x.jpg
--------------------------------------------------------------------------------
/developerportal/settings/worker.py:
--------------------------------------------------------------------------------
1 | # Extra settings that ONLY apply to the Celery workers/schedulers
2 |
3 | from .production import *
4 |
--------------------------------------------------------------------------------
/src/fonts/ZillaSlabHighlight-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/ZillaSlabHighlight-Regular.woff
--------------------------------------------------------------------------------
/src/fonts/ZillaSlabHighlight-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/fonts/ZillaSlabHighlight-Regular.woff2
--------------------------------------------------------------------------------
/src/img/logos/firefox/logo-word-hor-sm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/logos/firefox/logo-word-hor-sm.png
--------------------------------------------------------------------------------
/src/img/placeholders/original/post_3_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/placeholders/original/post_3_2.jpg
--------------------------------------------------------------------------------
/src/img/placeholders/original/event_16_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/placeholders/original/event_16_9.jpg
--------------------------------------------------------------------------------
/src/img/placeholders/original/event_3_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/placeholders/original/event_3_2.jpg
--------------------------------------------------------------------------------
/src/img/placeholders/original/person_16_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/placeholders/original/person_16_9.jpg
--------------------------------------------------------------------------------
/src/img/placeholders/original/person_3_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/placeholders/original/person_3_2.jpg
--------------------------------------------------------------------------------
/src/img/placeholders/original/post_16_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/placeholders/original/post_16_9.jpg
--------------------------------------------------------------------------------
/src/css/molecules/card-person.scss:
--------------------------------------------------------------------------------
1 | .mzp-c-card.card-person {
2 | .mzp-c-card-media-wrapper {
3 | background-color: transparent;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/developerportal/settings/test_fast.py:
--------------------------------------------------------------------------------
1 | from .test import *
2 |
3 | DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}}
4 |
--------------------------------------------------------------------------------
/developerportal/templates/wagtailadmin/home.html:
--------------------------------------------------------------------------------
1 | {% extends "wagtailadmin/home.html" %}
2 |
3 | {% block branding_welcome %}{{ site_name }}{% endblock %}
4 |
--------------------------------------------------------------------------------
/src/img/logos/firefox/logo-word-hor-sm-high-res.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/developer-portal/master/src/img/logos/firefox/logo-word-hor-sm-high-res.png
--------------------------------------------------------------------------------
/developerportal/regex.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | # Spot a REDIS_URL with a DB number associated with it
4 | REDIS_DB_URL_PATTERN = re.compile(r"redis\:\/\/.*\d{4,5}(\/\d{1,2})")
5 |
--------------------------------------------------------------------------------
/developerportal/apps/search/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 |
3 | from . import views
4 |
5 | urlpatterns = [url(r"^$", views.site_search, name="search.site_search")]
6 |
--------------------------------------------------------------------------------
/src/css/templates/video.scss:
--------------------------------------------------------------------------------
1 | body.video {
2 | .video-wrapper {
3 | margin-bottom: $spacing-md;
4 | }
5 |
6 | .resource-share {
7 | margin-bottom: $spacing-2xl;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/img/hamburger.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/icons/expand.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/developerportal/apps/ingestion/__init__.py:
--------------------------------------------------------------------------------
1 | from .celery import app as celery_app
2 |
3 | # Make sure Celery is always imported when Django starts
4 | # so that @shared_task will use this app.
5 | __all__ = ("celery_app",)
6 |
--------------------------------------------------------------------------------
/developerportal/apps/taskqueue/__init__.py:
--------------------------------------------------------------------------------
1 | from .celery import app as celery_app
2 |
3 | # Make sure Celery is always imported when Django starts
4 | # so that @shared_task will use this app.
5 | __all__ = ("celery_app",)
6 |
--------------------------------------------------------------------------------
/src/css/atoms/icon.scss:
--------------------------------------------------------------------------------
1 | .icon {
2 | // Note that this class includes the close triggers for filter-form.html
3 | display: inline-block;
4 | fill: currentColor;
5 | line-height: 0;
6 | vertical-align: middle;
7 | }
8 |
--------------------------------------------------------------------------------
/src/img/icons/expand-white.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/scripts/ci-tests:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -eo pipefail
4 |
5 | echo "Running tests"
6 | docker-compose exec -T app python manage.py test --settings=developerportal.settings.test
7 | docker-compose exec -T static npm run test
8 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [flake8]
2 | exclude = .*,__pycache__,*.egg,migrations,node_modules
3 | max-line-length = 88
4 | per-file-ignores =
5 | # Ignored to allow wildcard imports in settings
6 | developerportal/settings/*:F401,F403,F405
7 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/custom.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Blank issue template
3 | about: Please only use this template if you know why the other two aren't appropriate.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 2
7 | indent_style = space
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.py]
12 | indent_size = 4
13 |
--------------------------------------------------------------------------------
/src/img/icons/menu-arrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/css/atoms/buttons.scss:
--------------------------------------------------------------------------------
1 | .links-as-buttons {
2 | margin-bottom: $spacing-lg;
3 | a {
4 | @extend .mzp-c-button;
5 | margin-bottom: $spacing-sm;
6 | }
7 |
8 | @media #{$mq-md} {
9 | margin-bottom: 100px;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/img/icons/menu.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/developerportal/apps/common/templates/code_snippet_block.html:
--------------------------------------------------------------------------------
1 | {% load wagtailcore_tags %}
2 | {% load app_filters %}
3 |
4 |
5 | {{ value.code|syntax_highlight:value.language }}
6 |
7 |
--------------------------------------------------------------------------------
/developerportal/templates/wagtailadmin/404.html:
--------------------------------------------------------------------------------
1 | {% extends "wagtailadmin/404.html" %}
2 | {% load static %}
3 |
4 | {% block branding_logo %}
5 |
6 | {% endblock %}
7 |
--------------------------------------------------------------------------------
/src/img/icons/menu-white.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/templates/partials/verbose_standfirst.html:
--------------------------------------------------------------------------------
1 | {% load wagtailcore_tags %}
2 |
3 | {{page.read_time}} | {{page.date|date}}
4 |
5 | {% if page.description %}
6 | {{page.description|richtext}}
7 | {% endif %}
8 |
--------------------------------------------------------------------------------
/developerportal/settings/test.py:
--------------------------------------------------------------------------------
1 | from .production import *
2 |
3 | CACHES["default"]["KEY_PREFIX"] = "test"
4 |
5 | DEFAULT_FILE_STORAGE = "django.core.files.storage.FileSystemStorage"
6 | MEDIA_ROOT = "/tmp/test-media/"
7 |
8 | AWS_CLOUDFRONT_DISTRIBUTION_ID = None
9 |
--------------------------------------------------------------------------------
/developerportal/apps/health/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 |
3 | from . import views
4 |
5 | urlpatterns = [
6 | url(r"^healthz/?$", views.liveness, name="health.liveness"),
7 | url(r"^readiness/?$", views.readiness, name="health.readiness"),
8 | ]
9 |
--------------------------------------------------------------------------------
/developerportal/apps/ingestion/constants.py:
--------------------------------------------------------------------------------
1 | # For the skeleton ingestion user, who counts as the Editor of imported content
2 | INGESTION_USER_USERNAME = "ingestion_user"
3 | INGESTION_USER_FIRST_NAME = "Portal"
4 | INGESTION_USER_LAST_NAME = "Bot"
5 | INGESTION_USER_EMAIL = "Developer"
6 |
--------------------------------------------------------------------------------
/developerportal/templates/molecules/accessibility-nav.html:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/developerportal/templates/wagtailadmin/admin_base.html:
--------------------------------------------------------------------------------
1 | {% extends "wagtailadmin/admin_base.html" %}
2 | {% load static app_tags %}
3 |
4 | {% block branding_favicon %}
5 | {% get_favicon_path as favicon_path %}
6 |
7 | {% endblock %}
8 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | This changeset addresses ... by ...
2 |
3 | (Related issue #XX)
4 |
5 | ## Key changes:
6 |
7 | - summarise changes here, linking to commits as appropriate
8 |
9 | ## How to test
10 |
11 | - add test steps here, including how to set up relevant data/state
12 |
--------------------------------------------------------------------------------
/src/css/admin.scss:
--------------------------------------------------------------------------------
1 | /* Custom CSS for the Wagtail Admin */
2 |
3 | .Draftail-block--button-block {
4 | border: 2px dotted gray;
5 | padding: 10px 0px 10px 5px;
6 | a {
7 | background: black;
8 | border: 2px solid black;
9 | color: white;
10 | padding: 3px;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/css/atoms/rich-text.scss:
--------------------------------------------------------------------------------
1 | // revert the Protocol styling reset
2 | .rich-text {
3 | clear: both;
4 |
5 | ul {
6 | list-style: disc;
7 | }
8 |
9 | ol {
10 | list-style: decimal;
11 | }
12 |
13 | li {
14 | margin-left: 1.5em;
15 | padding-left: 4px;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/developerportal/apps/ingestion/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from .models import IngestionConfiguration
4 |
5 |
6 | class IngestionConfigAdmin(admin.ModelAdmin):
7 | model = IngestionConfiguration
8 |
9 |
10 | admin.site.register(IngestionConfiguration, IngestionConfigAdmin)
11 |
--------------------------------------------------------------------------------
/src/img/icons/close.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/css/atoms/modal.scss:
--------------------------------------------------------------------------------
1 | // Override Protocol default padding for modals on mobile
2 | .mzp-c-modal-window,
3 | .mzp-c-modal-inner {
4 | @media screen and (max-width: 1055px) {
5 | padding: 16px;
6 | }
7 | }
8 |
9 | .mzp-c-modal-inner {
10 | > header h2 {
11 | background: none;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/img/icons/close-white.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:base"
4 | ],
5 | "dockerfile": {
6 | "pinDigests": true
7 | },
8 | "docker-compose": {
9 | "enabled": false
10 | },
11 | "labels": ["renovate"],
12 | "masterIssue": true,
13 | "rangeStrategy": "pin",
14 | "rebaseStalePrs": true
15 | }
16 |
--------------------------------------------------------------------------------
/developerportal/templates/atoms/icons/close.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/developerportal/apps/ingestion/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 | from .celery import app as celery_app
4 |
5 | # Make sure Celery is always imported when Django starts
6 | # so that @shared_task will use this app.
7 | __all__ = ("celery_app",)
8 |
9 |
10 | class IngestionConfig(AppConfig):
11 | name = "ingestion"
12 |
--------------------------------------------------------------------------------
/src/css/atoms/label.scss:
--------------------------------------------------------------------------------
1 | .label {
2 | background-color: $color-blue-50;
3 | border-radius: 4px;
4 | color: white;
5 | display: inline-block;
6 | font-size: 0.8em;
7 | font-weight: bold;
8 | line-height: 1.2em;
9 | padding: 4px 6px;
10 | vertical-align: 2px;
11 | width: auto;
12 | margin-left: $spacing-sm;
13 | }
14 |
--------------------------------------------------------------------------------
/src/css/molecules/notification-bar.scss:
--------------------------------------------------------------------------------
1 | .mzp-c-notification-bar {
2 | @media #{$mq-md} {
3 | margin: $spacing-md auto 0px;
4 | }
5 | .mzp-c-notification-bar-cta {
6 | margin: 0px !important;
7 | text-decoration: underline;
8 | &:hover {
9 | color: $color-marketing-gray-40 !important;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/developerportal/templates/atoms/image.html:
--------------------------------------------------------------------------------
1 |
2 |
8 | {% if image.caption %}
9 |
10 | {{ image.caption }}
11 |
12 | {% endif %}
13 |
14 |
--------------------------------------------------------------------------------
/src/css/atoms/quote.scss:
--------------------------------------------------------------------------------
1 | blockquote {
2 | clear: both;
3 | font-family: $heading-font-family;
4 | font-size: 24px;
5 | line-height: 32px;
6 | margin: 24px auto;
7 | max-width: 90%;
8 | text-align: center;
9 |
10 | :first-child {
11 | margin-top: 0;
12 | }
13 |
14 | :last-child {
15 | margin-bottom: 0;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/etc/nginx/ssl/README.md:
--------------------------------------------------------------------------------
1 | # SSL support for the local build
2 |
3 | This folder will contain self-signed certificates for SSL support in local development.
4 |
5 | They are generated/updated each time the local Docker stack is upped using `etc/nginx/ssl/gen-cert.sh`
6 |
7 | See `services:cfssl:entrypoint` in `docker-compose.yml` for where this is hooked in.
8 |
--------------------------------------------------------------------------------
/src/css/organisms/article-read-more.scss:
--------------------------------------------------------------------------------
1 | .article-read-more {
2 | .section-header {
3 | padding: $spacing-sm 0px $spacing-xl;
4 | h4 {
5 | font-family: $body-font-family;
6 |
7 | span {
8 | display: inline-block;
9 | padding-left: $spacing-sm;
10 | font-size: 0.6em;
11 | }
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/css/organisms/topic-links.scss:
--------------------------------------------------------------------------------
1 | .topic-links {
2 | h2 {
3 | font-family: $body-font-family;
4 | font-size: $h4-font-size-mobile;
5 | line-height: heading-line-height($h4-font-size-mobile);
6 |
7 | @media #{$mq-md} {
8 | font-size: $h4-font-size;
9 | line-height: heading-line-height($h4-font-size);
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0019_remove_people_keywords.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-25 12:25
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("people", "0018_people_keywords")]
9 |
10 | operations = [migrations.RemoveField(model_name="people", name="keywords")]
11 |
--------------------------------------------------------------------------------
/src/img/icons/article-white.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/img/icons/content-white.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/developerportal/apps/common/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 | from django.views.decorators.cache import never_cache
3 |
4 |
5 | @never_cache
6 | def rate_limited(request, exception):
7 | """Render a rate-limited exception page"""
8 | response = render(request, "429.html", status=429)
9 | response["Retry-After"] = "60"
10 | return response
11 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0018_merge_20190702_1247.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-07-02 12:47
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("home", "0017_auto_20190628_1438"),
10 | ("home", "0009_auto_20190702_0904"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0019_merge_20190709_0910.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-09 09:10
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("home", "0018_merge_20190702_1247"),
10 | ("home", "0011_auto_20190705_1258"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0014_merge_20190618_1609.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-18 16:09
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0010_auto_20190618_0840"),
10 | ("topics", "0013_topic_icon"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/templates/atoms/label.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 |
3 | Small element used to label other things
4 |
5 | Args:
6 | - content: plaintext string
7 | - extra_css_classes (optional): string of extra CSS classes, separated by spaces
8 |
9 | {% endcomment %}
10 |
11 |
12 |
--------------------------------------------------------------------------------
/developerportal/apps/events/migrations/0004_merge_20190711_1925.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-11 19:25
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("events", "0003_auto_20190709_0928"),
10 | ("events", "0003_auto_20190709_1241"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0010_merge_20190627_1318.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-27 13:18
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("people", "0009_auto_20190626_0848"),
10 | ("people", "0009_auto_20190626_1353"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0011_merge_20190627_1428.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-27 14:28
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("people", "0010_auto_20190625_1258"),
10 | ("people", "0009_auto_20190626_0848"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0023_merge_20190802_1535.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-08-02 15:35
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("people", "0022_person_websites"),
10 | ("people", "0022_people_description"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0013_merge_20190618_1635.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-18 16:35
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0010_auto_20190618_0840"),
10 | ("topics", "0012_auto_20190614_1319"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0013_merge_20190619_1357.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-19 13:57
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0010_auto_20190618_0840"),
10 | ("topics", "0012_auto_20190614_1319"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0024_merge_20190702_1619.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-07-02 16:19
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0023_auto_20190702_1318"),
10 | ("topics", "0020_topic_featured"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0026_merge_20190704_1459.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-04 14:59
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0025_auto_20190702_1620"),
10 | ("topics", "0021_auto_20190702_1402"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0028_merge_20190710_1633.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-10 16:33
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0027_auto_20190710_1339"),
10 | ("topics", "0027_auto_20190709_0928"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/src/css/global/layout.scss:
--------------------------------------------------------------------------------
1 | // Override Protocol's 25% / 75% layout to be 33% / 67%
2 |
3 | @media #{$mq-md} {
4 | .mzp-l-sidebar.custom-width {
5 | // .custom-width gives us greater specificity so we
6 | // can override mzp-l-sidebar without needing !important
7 | width: 33.333%;
8 | }
9 |
10 | .mzp-l-main.custom-width {
11 | width: 66.665%;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0013_merge_20190603_1229.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-03 12:29
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("articles", "0012_article_header_image"),
10 | ("articles", "0012_article_author"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0012_merge_20190628_1108.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-28 11:08
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("people", "0010_merge_20190627_1318"),
10 | ("people", "0011_merge_20190627_1428"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0013_merge_20190702_1247.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-07-02 12:47
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("people", "0012_auto_20190702_1059"),
10 | ("people", "0012_merge_20190628_1108"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0013_merge_20190702_1300.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-07-02 13:00
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("people", "0012_merge_20190628_1108"),
10 | ("people", "0012_auto_20190702_1059"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0014_merge_20190702_1619.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-07-02 16:19
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("people", "0013_merge_20190702_1247"),
10 | ("people", "0013_merge_20190702_1300"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0015_merge_20190619_1437.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-19 14:37
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0013_merge_20190618_1635"),
10 | ("topics", "0014_merge_20190618_1609"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0015_merge_20190619_1506.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-19 15:06
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0014_merge_20190618_1609"),
10 | ("topics", "0013_merge_20190618_1635"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0017_merge_20190621_1033.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-21 10:33
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0015_merge_20190621_1009"),
10 | ("topics", "0016_auto_20190619_1506"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0017_merge_20190624_0904.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-24 09:04
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0016_auto_20190619_1437"),
10 | ("topics", "0015_merge_20190621_1009"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0018_merge_20190624_1248.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-24 12:48
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0017_merge_20190624_0904"),
10 | ("topics", "0017_merge_20190621_1033"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0018_merge_20190624_1252.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-24 12:52
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0016_auto_20190624_1129"),
10 | ("topics", "0017_merge_20190624_0904"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0019_merge_20190625_1257.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-25 12:57
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0018_merge_20190624_1252"),
10 | ("topics", "0018_merge_20190624_1248"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/data/README.md:
--------------------------------------------------------------------------------
1 | # What's in /data/ ?
2 |
3 | - `devportal-topic-icons` is a directory of SVG icons that are intended for upload via the Meta -> Theme -> Icon field on pages that appear as child pages in the navigation (all Topic pages, plus the People page and some Content Pages). They've been added to the repo for convenience and require manual addition because they are technically data, not design.
4 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0007_merge_20190517_1323.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-05-17 13:23
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("articles", "0006_auto_20190516_1303"),
10 | ("articles", "0003_auto_20190517_1038"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0014_merge_20190604_0953.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-04 09:53
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("articles", "0012_auto_20190603_1048"),
10 | ("articles", "0013_merge_20190603_1229"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0027_merge_20190802_1535.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-08-02 15:35
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("articles", "0026_auto_20190731_1109"),
10 | ("articles", "0026_articles_description"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/src/css/organisms/search-results.scss:
--------------------------------------------------------------------------------
1 | .search-results {
2 | .search-results-summary {
3 | color: $color-marketing-gray-60;
4 | }
5 | .no-results {
6 | // padding: 60px 0;
7 | // text-align: center;
8 | height: 20vmax;
9 |
10 | h3::after {
11 | margin-bottom: 0;
12 | }
13 | }
14 | .pagination-block {
15 | margin-top: $spacing-2xl;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0028_merge_20190805_1426.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-05 14:26
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("articles", "0027_merge_20190802_1535"),
10 | ("articles", "0027_article_related_links_mdn"),
11 | ]
12 |
13 | operations = []
14 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0009_auto_20190626_0848.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-26 08:48
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("people", "0008_featuredperson")]
9 |
10 | operations = [
11 | migrations.AlterModelOptions(name="person", options={"ordering": ["title"]})
12 | ]
13 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0009_auto_20190626_1353.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-26 13:53
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("people", "0008_featuredperson")]
9 |
10 | operations = [
11 | migrations.AlterModelOptions(name="person", options={"ordering": ["title"]})
12 | ]
13 |
--------------------------------------------------------------------------------
/k8s/redirector.svc.yaml.j2:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: {{ REDIRECTOR_NAME }}
5 | namespace: {{ REDIRECTOR_NAMESPACE }}
6 | labels:
7 | app: {{ REDIRECTOR_NAME }}
8 | spec:
9 | selector:
10 | app: {{ REDIRECTOR_NAME }}
11 | ports:
12 | - name: http
13 | port: {{ REDIRECTOR_SERVICE_PORT }}
14 | targetPort: {{ REDIRECTOR_CONTAINER_PORT }}
15 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0010_auto_20190625_1258.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-25 12:58
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("people", "0009_auto_20190625_1122")]
9 |
10 | operations = [
11 | migrations.AlterModelOptions(name="person", options={"ordering": ["title"]})
12 | ]
13 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0020_auto_20190612_0426.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-12 04:26
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("articles", "0019_auto_20190611_1453")]
9 |
10 | operations = [
11 | migrations.AlterModelOptions(name="article", options={"ordering": ["-date"]})
12 | ]
13 |
--------------------------------------------------------------------------------
/developerportal/templates/molecules/image-block.html:
--------------------------------------------------------------------------------
1 | {% load wagtailimages_tags %}
2 | {% load app_tags %}
3 |
4 | {% mime_type block.value.file.name as image_mime_type %}
5 |
6 | {% if image_mime_type == 'image/gif' %}
7 | {% render_gif block.value %}
8 | {% else %}
9 | {% image block.value width-800 as rendition %}
10 | {% include "atoms/image.html" with image=block.value rendition=rendition %}
11 | {% endif %}
12 |
--------------------------------------------------------------------------------
/etc/nginx/ssl/cfssl.json:
--------------------------------------------------------------------------------
1 | {
2 | "CN": "developer-portal-127-0-0-1.nip.io",
3 | "hosts": [
4 | "developer-portal-127-0-0-1.nip.io"
5 | ],
6 | "key": {
7 | "algo": "rsa",
8 | "size": 2048
9 | },
10 | "names": [
11 | {
12 | "O": "Mozilla",
13 | "OU": "Developer Portal development",
14 | "C": "US",
15 | "ST": "CA",
16 | "L": "San Francisco"
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/src/css/molecules/pagination.scss:
--------------------------------------------------------------------------------
1 | .pagination-block {
2 | margin-top: $spacing-md;
3 | margin-bottom: $spacing-2xl;
4 | text-align: center;
5 |
6 | & .mzp-c-button {
7 | min-width: 90px;
8 |
9 | @media #{$mq-sm} {
10 | min-width: 135px;
11 | padding: 14px 30px;
12 | }
13 | }
14 | }
15 |
16 | .pagination-current {
17 | display: inline-block;
18 | margin: auto $spacing-md;
19 | }
20 |
--------------------------------------------------------------------------------
/src/img/logos/mdn-dino-white.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/developerportal/templates/organisms/featured-events--four-up.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {% for block in featured %}
4 |
7 | {% endfor %}
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/css/atoms/image.scss:
--------------------------------------------------------------------------------
1 | img {
2 | height: auto;
3 | max-width: 100%;
4 | }
5 |
6 | figcaption {
7 | font-size: 14px;
8 | margin: 10px 0;
9 | text-align: center;
10 | }
11 |
12 | .format-left {
13 | float: left;
14 | margin: 0 24px 24px 0;
15 | }
16 |
17 | .format-center {
18 | display: block;
19 | margin: 0 auto 24px;
20 | }
21 |
22 | .format-right {
23 | float: right;
24 | margin: 0 0 24px 24px;
25 | }
26 |
--------------------------------------------------------------------------------
/developerportal/apps/events/migrations/0005_merge_20190711_2019.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-11 20:19
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("events", "0004_auto_20190708_1100"),
10 | ("events", "0004_merge_20190711_1925"),
11 | ("events", "0004_auto_20190711_1501"),
12 | ]
13 |
14 | operations = []
15 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0015_merge_20190621_1009.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-21 10:09
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("topics", "0014_merge_20190618_1609"),
10 | ("topics", "0013_merge_20190619_1357"),
11 | ("topics", "0013_merge_20190618_1635"),
12 | ]
13 |
14 | operations = []
15 |
--------------------------------------------------------------------------------
/locust/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | master:
5 | image: locustio/locust
6 | ports:
7 | - '8089:8089'
8 | volumes:
9 | - ./:/mnt/locust
10 | command: -f /mnt/locust/locustfile.py --master -H http://master:8089
11 |
12 | worker:
13 | image: locustio/locust
14 | volumes:
15 | - ./:/mnt/locust
16 | command: -f /mnt/locust/locustfile.py --worker --master-host master
17 |
--------------------------------------------------------------------------------
/src/img/icons/social/protocol/white.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/developerportal/apps/events/migrations/0003_auto_20190709_0928.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-09 09:28
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("events", "0002_auto_20190704_1334")]
9 |
10 | operations = [
11 | migrations.AlterModelOptions(
12 | name="events", options={"verbose_name_plural": "Events"}
13 | )
14 | ]
15 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0015_auto_20190709_0928.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-09 09:28
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("people", "0014_merge_20190702_1619")]
9 |
10 | operations = [
11 | migrations.AlterModelOptions(
12 | name="people", options={"verbose_name_plural": "People"}
13 | )
14 | ]
15 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0007_auto_20190611_1542.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-11 15:42
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("topics", "0006_auto_20190611_1453")]
9 |
10 | operations = [
11 | migrations.RenameField(
12 | model_name="topicperson", old_name="author", new_name="person"
13 | )
14 | ]
15 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0027_auto_20190709_0928.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-09 09:28
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("topics", "0026_merge_20190704_1459")]
9 |
10 | operations = [
11 | migrations.AlterModelOptions(
12 | name="topics", options={"verbose_name_plural": "Topics"}
13 | )
14 | ]
15 |
--------------------------------------------------------------------------------
/developerportal/apps/events/migrations/0010_auto_20190718_1551.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-18 15:51
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("events", "0007_auto_20190718_1424")]
9 |
10 | operations = [
11 | migrations.RenameField(
12 | model_name="events", old_name="featured_event", new_name="featured"
13 | )
14 | ]
15 |
--------------------------------------------------------------------------------
/developerportal/apps/events/wagtail_hooks.py:
--------------------------------------------------------------------------------
1 | from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
2 |
3 | from ..common.helpers import ExplorerRedirectAdminURLHelper
4 | from .models import Events
5 |
6 |
7 | class EventsAdmin(ModelAdmin):
8 | model = Events
9 | menu_icon = "date"
10 | menu_order = 220
11 | url_helper_class = ExplorerRedirectAdminURLHelper
12 |
13 |
14 | modeladmin_register(EventsAdmin)
15 |
--------------------------------------------------------------------------------
/developerportal/apps/people/wagtail_hooks.py:
--------------------------------------------------------------------------------
1 | from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
2 |
3 | from ..common.helpers import ExplorerRedirectAdminURLHelper
4 | from .models import People
5 |
6 |
7 | class PeopleAdmin(ModelAdmin):
8 | model = People
9 | menu_icon = "group"
10 | menu_order = 230
11 | url_helper_class = ExplorerRedirectAdminURLHelper
12 |
13 |
14 | modeladmin_register(PeopleAdmin)
15 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/wagtail_hooks.py:
--------------------------------------------------------------------------------
1 | from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
2 |
3 | from ..common.helpers import ExplorerRedirectAdminURLHelper
4 | from .models import Topics
5 |
6 |
7 | class TopicsAdmin(ModelAdmin):
8 | model = Topics
9 | menu_icon = "tag"
10 | menu_order = 200
11 | url_helper_class = ExplorerRedirectAdminURLHelper
12 |
13 |
14 | modeladmin_register(TopicsAdmin)
15 |
--------------------------------------------------------------------------------
/developerportal/apps/videos/wagtail_hooks.py:
--------------------------------------------------------------------------------
1 | from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
2 |
3 | from ..common.helpers import ExplorerRedirectAdminURLHelper
4 | from .models import Videos
5 |
6 |
7 | class VideosAdmin(ModelAdmin):
8 | model = Videos
9 | menu_icon = "media"
10 | menu_order = 240
11 | url_helper_class = ExplorerRedirectAdminURLHelper
12 |
13 |
14 | modeladmin_register(VideosAdmin)
15 |
--------------------------------------------------------------------------------
/k8s/hpa.yaml.j2:
--------------------------------------------------------------------------------
1 | apiVersion: autoscaling/v1
2 | kind: HorizontalPodAutoscaler
3 | metadata:
4 | name: {{ APP_NAME }}
5 | labels:
6 | app: {{ APP_NAME }}
7 | environment: {{ TARGET_ENVIRONMENT }}
8 | spec:
9 | scaleTargetRef:
10 | apiVersion: apps/v1
11 | kind: Deployment
12 | name: {{ APP_NAME }}
13 | minReplicas: {{ APP_REPLICAS }}
14 | maxReplicas: {{ MAX_APP_REPLICAS }}
15 | targetCPUUtilizationPercentage: 80
16 |
17 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0023_auto_20190709_0928.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-09 09:28
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("articles", "0022_auto_20190624_1622")]
9 |
10 | operations = [
11 | migrations.AlterModelOptions(
12 | name="articles", options={"verbose_name_plural": "Articles"}
13 | )
14 | ]
15 |
--------------------------------------------------------------------------------
/.isort.cfg:
--------------------------------------------------------------------------------
1 | [settings]
2 | known_first_party=developerportal
3 | known_third_party=boto3,celery,django_countries,modelcluster,pytz,pygments,readtime,social_core,taggit,urllib3,wagtail
4 | known_django=django
5 | default_section=FIRSTPARTY
6 | sections=FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
7 | multi_line_output=3
8 | include_trailing_comma=True
9 | force_grid_wrap=0
10 | use_parentheses=True
11 | line_length=88
12 | skip=node_modules,migrations
13 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/migrations/0002_auto_20190704_1221.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-04 12:21
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("externalcontent", "0001_initial")]
9 |
10 | operations = [
11 | migrations.RenameField(
12 | model_name="externalcontent", old_name="url", new_name="external_url"
13 | )
14 | ]
15 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0054_remove_topic_color.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-27 11:00
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('topics', '0053_update_streamblock'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='topic',
15 | name='color',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0005_auto_20190516_1236.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-05-16 12:36
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("articles", "0004_auto_20190516_0907")]
9 |
10 | operations = [
11 | migrations.RemoveField(model_name="article", name="date"),
12 | migrations.RemoveField(model_name="article", name="intro"),
13 | ]
14 |
--------------------------------------------------------------------------------
/developerportal/apps/videos/migrations/0012_remove_video_image.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-07 21:13
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('videos', '0011_copy_image_to_card_image'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='video',
15 | name='image',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/src/img/icons/social/protocol/black.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/wagtail_hooks.py:
--------------------------------------------------------------------------------
1 | from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
2 |
3 | from ..common.helpers import ExplorerRedirectAdminURLHelper
4 | from .models import Articles
5 |
6 |
7 | class ArticlesAdmin(ModelAdmin):
8 | model = Articles
9 | menu_icon = "doc-full-inverse"
10 | menu_order = 210
11 | url_helper_class = ExplorerRedirectAdminURLHelper
12 |
13 |
14 | modeladmin_register(ArticlesAdmin)
15 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0037_remove_homepage_show_header.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-26 13:05
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('home', '0036_update_streamblock'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='homepage',
15 | name='show_header',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/src/css/atoms/embed.scss:
--------------------------------------------------------------------------------
1 | .rich-text img {
2 | height: auto;
3 | max-width: 100%;
4 | }
5 |
6 | .responsive-object {
7 | position: relative;
8 |
9 | .article-body & {
10 | margin-bottom: 24px;
11 | }
12 | }
13 |
14 | .responsive-object iframe,
15 | .responsive-object object,
16 | .responsive-object embed {
17 | height: 100%;
18 | left: 0;
19 | position: absolute;
20 | top: 0;
21 | width: 100%;
22 | }
23 |
24 | iframe {
25 | border: none;
26 | }
27 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0036_remove_person_image.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-07 21:13
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('people', '0035_copy_image_field_to_card_image_field'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='person',
15 | name='image',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/developerportal/apps/events/migrations/0023_remove_event_image.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-07 21:13
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('events', '0022_copy_image_field_data_to_card_image_field'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='event',
15 | name='image',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/migrations/0012_auto_20190724_1437.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-24 14:37
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("externalcontent", "0011_auto_20190723_1719")]
9 |
10 | operations = [
11 | migrations.AlterModelOptions(
12 | name="externalcontent", options={"verbose_name_plural": "External Content"}
13 | )
14 | ]
15 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0040_remove_article_image.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-07 21:13
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('articles', '0039_copy_image_field_data_to_card_image_field'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='article',
15 | name='image',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/migrations/0029_rename_image_to_card_image.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-07 20:43
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("externalcontent", "0028_rephrase_articles_as_posts")]
9 |
10 | operations = [
11 | migrations.RenameField(
12 | model_name="externalcontent", old_name="image", new_name="card_image"
13 | )
14 | ]
15 |
--------------------------------------------------------------------------------
/developerportal/apps/people/edit_handlers.py:
--------------------------------------------------------------------------------
1 | from wagtail.admin.edit_handlers import FieldPanel
2 |
3 |
4 | class CustomLabelFieldPanel(FieldPanel):
5 | def __init__(self, *args, label="Full name", **kwargs):
6 | super().__init__(*args, **kwargs)
7 | self._custom_label = label
8 |
9 | def render_as_field(self):
10 | if hasattr(self, "_custom_label"):
11 | self.bound_field.label = self._custom_label
12 | return super().render_as_field()
13 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0046_remove_topic_tabbed_panels_title.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.6 on 2019-10-09 16:25
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('topics', '0045_add_social_image_field'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='topic',
15 | name='tabbed_panels_title',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0050_remove_topic_latest_articles_count.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.11 on 2020-03-23 17:57
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('topics', '0049_topic_nav_description'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='topic',
15 | name='latest_articles_count',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0035_remove_homepage_external_promos.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.11 on 2020-03-25 23:00
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('home', '0034_support_featuring_video_in_homepage'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='homepage',
15 | name='external_promos',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0005_person_is_mozillian.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-05-31 08:24
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("people", "0004_auto_20190530_1441")]
9 |
10 | operations = [
11 | migrations.AddField(
12 | model_name="person",
13 | name="is_mozillian",
14 | field=models.BooleanField(default=True),
15 | )
16 | ]
17 |
--------------------------------------------------------------------------------
/developerportal/apps/content/migrations/0011_remove_contentpage_hero_image.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-07 21:13
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('content', '0010_copy_hero_image_field_to_card_image_field'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='contentpage',
15 | name='hero_image',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0013_topic_icon.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-18 10:27
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("topics", "0012_auto_20190614_1319")]
9 |
10 | operations = [
11 | migrations.AddField(
12 | model_name="topic",
13 | name="icon",
14 | field=models.FileField(default="", upload_to="topics/icons"),
15 | )
16 | ]
17 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0010_auto_20190618_0840.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-18 08:40
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("topics", "0009_topic_color")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="topic",
13 | name="intro",
14 | field=models.TextField(blank=True, default="", max_length=250),
15 | )
16 | ]
17 |
--------------------------------------------------------------------------------
/src/css/templates/content-page.scss:
--------------------------------------------------------------------------------
1 | body.content {
2 | figure,
3 | div.rich-text,
4 | p.button-block,
5 | div.responsive-object,
6 | div.syntax-highlight {
7 | margin-bottom: $spacing-2xl;
8 | }
9 |
10 | .standfirst-wrapper {
11 | .rich-text {
12 | margin-bottom: 0px;
13 | }
14 | }
15 | }
16 |
17 | .mzp-has-sidebar {
18 | &.mzp-l-sidebar-right {
19 | &.content-page {
20 | .mzp-l-main {
21 | padding-right: $spacing-2xl;
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/css/templates/site-search.scss:
--------------------------------------------------------------------------------
1 | body.site-search {
2 | .mzp-has-sidebar {
3 | display: flex;
4 | flex-direction: column-reverse;
5 | @media #{$mq-md} {
6 | display: block;
7 | flex-direction: row;
8 | }
9 |
10 | .mzp-l-sidebar {
11 | @media #{$mq-md} {
12 | // hidden for non-sm viewports
13 | display: none;
14 | }
15 | }
16 | }
17 |
18 | .pagination-block {
19 | @media #{$mq-md} {
20 | text-align: left;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0008_auto_20190612_1759.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-12 17:59
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("topics", "0007_auto_20190611_1542")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="topic",
13 | name="intro",
14 | field=models.CharField(blank=True, default="", max_length=250),
15 | )
16 | ]
17 |
--------------------------------------------------------------------------------
/developerportal/templates/organisms/homepage-header.html:
--------------------------------------------------------------------------------
1 | {% load wagtailcore_tags %}
2 | {% load wagtailimages_tags %}
3 | {% load static %}
4 |
5 |
6 |
7 |
8 | {{page.title}}
9 | {% if page.subtitle %}
10 | {{page.subtitle}}
11 | {% endif %}
12 |
13 |
14 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0010_auto_20190704_1031.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-04 10:31
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("home", "0009_auto_20190702_0904")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="homepage",
13 | name="button_url",
14 | field=models.URLField(blank=True, default="", max_length=2048),
15 | )
16 | ]
17 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0024_auto_20190718_1438.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-18 14:38
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("home", "0023_auto_20190712_1023")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="homepage",
13 | name="button_url",
14 | field=models.CharField(blank=True, default="", max_length=2048),
15 | )
16 | ]
17 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0021_auto_20190618_0840.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-18 08:40
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("articles", "0020_auto_20190612_0426")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="article",
13 | name="intro",
14 | field=models.TextField(blank=True, default="", max_length=250),
15 | )
16 | ]
17 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0016_auto_20190619_1437.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-19 14:37
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("topics", "0015_merge_20190619_1437")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="topic",
13 | name="icon",
14 | field=models.FileField(blank=True, default="", upload_to="topics/icons"),
15 | )
16 | ]
17 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0016_auto_20190619_1506.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-19 15:06
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("topics", "0015_merge_20190619_1506")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="topic",
13 | name="icon",
14 | field=models.FileField(blank=True, default="", upload_to="topics/icons"),
15 | )
16 | ]
17 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0016_auto_20190624_1129.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-24 11:29
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("topics", "0015_merge_20190621_1009")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="topic",
13 | name="icon",
14 | field=models.FileField(blank=True, default="", upload_to="topics/icons"),
15 | )
16 | ]
17 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0032_homepage_show_header.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.6 on 2019-10-15 15:48
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('home', '0031_homepage_featured_people'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='homepage',
15 | name='show_header',
16 | field=models.BooleanField(default=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/developerportal/apps/taskqueue/wagtail_hooks.py:
--------------------------------------------------------------------------------
1 | from wagtail.core.signals import page_published, page_unpublished
2 |
3 | from .tasks import invalidate_entire_cdn
4 |
5 |
6 | def purge_cdn_on_publish(signal, **kwargs):
7 | # TODO: refine this to be more selective and only invalidate the
8 | # keys we know we need to. At the moment we're erring on the side
9 | # of caution.
10 | invalidate_entire_cdn.delay()
11 |
12 |
13 | page_published.connect(purge_cdn_on_publish)
14 | page_unpublished.connect(purge_cdn_on_publish)
15 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Community Participation Guidelines
2 |
3 | This repository is governed by Mozilla's code of conduct and etiquette guidelines.
4 | For more details, please read the
5 | [Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/).
6 |
7 | ## How to Report
8 |
9 | For more information on how to report violations of the Community Participation Guidelines, please read our
10 | [How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/) page.
11 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0009_homepage_featured.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-27 15:23
2 |
3 | from django.db import migrations
4 | import wagtail.core.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("home", "0008_auto_20190625_1119")]
10 |
11 | operations = [
12 | migrations.AddField(
13 | model_name="homepage",
14 | name="featured",
15 | field=wagtail.core.fields.StreamField([], blank=True, null=True),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/src/css/templates/article.scss:
--------------------------------------------------------------------------------
1 | body.article {
2 | .resource-toolbar {
3 | @media #{$mq-md} {
4 | float: right;
5 | }
6 | margin-bottom: $spacing-2xl;
7 | }
8 | .authors-header {
9 | font-family: $body-font-family;
10 | font-size: $h4-font-size-mobile; // TODO: sweep and rename these variables
11 | line-height: heading-line-height($h4-font-size-mobile);
12 |
13 | @media #{$mq-md} {
14 | font-size: $h4-font-size;
15 | line-height: heading-line-height($h4-font-size);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/img/icons/arrow-left.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0003_article_intro.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-05-16 09:06
2 |
3 | from django.db import migrations
4 | import wagtail.core.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("articles", "0002_article_date")]
10 |
11 | operations = [
12 | migrations.AddField(
13 | model_name="article",
14 | name="intro",
15 | field=wagtail.core.fields.RichTextField(default=None, verbose_name="Intro"),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0012_auto_20190702_1059.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-07-02 10:59
2 |
3 | from django.db import migrations
4 | import wagtail.core.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("people", "0011_merge_20190627_1428")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="person",
14 | name="intro",
15 | field=wagtail.core.fields.RichTextField(blank=True, default=""),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0031_person_nickname.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.6 on 2019-10-08 11:40
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('people', '0030_add_social_image_field'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='person',
15 | name='nickname',
16 | field=models.CharField(blank=True, max_length=250, null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/etc/nginx/ssl/ca-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "signing": {
3 | "default": {
4 | "expiry": "168h"
5 | },
6 | "profiles": {
7 | "server": {
8 | "expiry": "8760h",
9 | "usages": [
10 | "signing",
11 | "key encipherment",
12 | "server auth"
13 | ]
14 | },
15 | "client": {
16 | "expiry": "8760h",
17 | "usages": [
18 | "signing",
19 | "key encipherment",
20 | "client auth"
21 | ]
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/img/icons/arrow-left-white.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/migrations/0019_auto_20190813_1302.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-13 13:02
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("externalcontent", "0018_auto_20190807_1244")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="externalcontent",
13 | name="description",
14 | field=models.TextField(blank=True, default="", max_length=400),
15 | )
16 | ]
17 |
--------------------------------------------------------------------------------
/etc/nginx/ssl/gen-cert.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | SSL_DIR=$(dirname "$0")
4 | BASENAME="developer-portal-127-0-0-1.nip.io"
5 | SSL_KEY="${SSL_DIR}/${BASENAME}-key.pem"
6 | SSL_CRT="${SSL_DIR}/${BASENAME}.pem"
7 |
8 |
9 | if [ ! -f "${SSL_KEY}" ] || [ ! -f "${SSL_CRT}" ]; then
10 | cfssl gencert -initca ./cfssl.json | cfssljson -bare ca -
11 | cfssl gencert -ca=./ca.pem -ca-key=./ca-key.pem -config=./ca-config.json -profile=server ./cfssl.json | cfssljson -bare "${BASENAME}"
12 | else
13 | echo "${SSL_KEY} and ${SSL_CRT} already exists."
14 | fi
15 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0004_auto_20190516_0907.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-05-16 09:07
2 |
3 | from django.db import migrations
4 | import wagtail.core.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("articles", "0003_article_intro")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="article",
14 | name="intro",
15 | field=wagtail.core.fields.RichTextField(default="", verbose_name="Intro"),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/migrations/0008_externalcontent_description.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-23 12:59
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("externalcontent", "0007_auto_20190711_1940")]
9 |
10 | operations = [
11 | migrations.AddField(
12 | model_name="externalcontent",
13 | name="description",
14 | field=models.TextField(blank=True, default="", max_length=250),
15 | )
16 | ]
17 |
--------------------------------------------------------------------------------
/src/img/icons/events-white.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/developerportal/apps/common/templates/button_block.html:
--------------------------------------------------------------------------------
1 | {% load wagtailcore_tags %}
2 | {% load app_filters %}
3 |
4 | {% if value.page_link or value.external_link %}
5 |
6 | {% if value.page_link %}
7 |
8 | {% elif value.external_link %}
9 |
10 | {% endif %}
11 | {{ value.text }}
12 |
13 |
{% endif %}
14 |
--------------------------------------------------------------------------------
/src/img/icons/search-black.svg:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/src/css/molecules/site-search-form.scss:
--------------------------------------------------------------------------------
1 | .site-search-form {
2 | margin-bottom: $spacing-xl;
3 |
4 | input.site-search-field {
5 | background: transparent url('/static/img/icons/search-black.svg') 3px 3px
6 | no-repeat;
7 | background-size: 24px auto;
8 | height: 2em;
9 | margin-bottom: $spacing-md;
10 | padding: $spacing-xs $spacing-xs $spacing-xs $spacing-xl;
11 | width: 100%;
12 | -webkit-appearance: none; // override blocking of styling in Safari
13 |
14 | @media #{$mq-md} {
15 | width: 80%;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/data/devportal_topic_icons/search.svg:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0002_article_date.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-05-15 15:19
2 |
3 | import datetime
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("articles", "0001_initial")]
10 |
11 | operations = [
12 | migrations.AddField(
13 | model_name="article",
14 | name="date",
15 | field=models.DateField(
16 | default=datetime.date.today, verbose_name="Article date"
17 | ),
18 | )
19 | ]
20 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | # Load dev settings by default. To override this, set either:
7 | # - DJANGO_ENV to e.g. production, or;
8 | # - DJANGO_SETTINGS_MODULE to e.g. developerportal.settings.production (takes precedence).
9 | env = os.environ.setdefault("DJANGO_ENV", "dev")
10 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", f"developerportal.settings.{env}")
11 |
12 | from django.core.management import execute_from_command_line
13 |
14 | execute_from_command_line(sys.argv)
15 |
--------------------------------------------------------------------------------
/src/img/icons/search-white.svg:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/migrations/0027_relabel_external_article_as_external_post.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.6 on 2019-11-01 11:51
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('externalcontent', '0026_external_person_description'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterModelOptions(
14 | name='externalarticle',
15 | options={'verbose_name': 'External Post', 'verbose_name_plural': 'External Posts'},
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0027_person_country.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-25 10:39
2 |
3 | from django.db import migrations
4 | import django_countries.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('people', '0026_auto_20190819_1304'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='person',
16 | name='country',
17 | field=django_countries.fields.CountryField(blank=True, default='', max_length=2),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0029_update_home_manager.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-30 09:15
2 |
3 | from django.db import migrations
4 | import django.db.models.manager
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('home', '0028_auto_20190814_1600'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterModelManagers(
15 | name='homepage',
16 | managers=[
17 | ('published_objects', django.db.models.manager.Manager()),
18 | ],
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0022_people_description.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-08-02 09:16
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("people", "0021_auto_20190731_1057")]
9 |
10 | operations = [
11 | migrations.AddField(
12 | model_name="people",
13 | name="description",
14 | field=models.TextField(
15 | blank=True, default="", max_length=250, verbose_name="Description"
16 | ),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0034_people_nav_description.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.11 on 2020-03-18 11:28
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('people', '0033_people_icon'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='people',
15 | name='nav_description',
16 | field=models.TextField(blank=True, default='', max_length=400, verbose_name='Navigation description'),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0038_topic_latest_articles_count.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-08-01 15:29
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("topics", "0037_auto_20190730_1057")]
9 |
10 | operations = [
11 | migrations.AddField(
12 | model_name="topic",
13 | name="latest_articles_count",
14 | field=models.IntegerField(
15 | choices=[(3, "3"), (6, "6"), (9, "9")], default=3
16 | ),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0026_articles_description.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-08-02 09:16
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("articles", "0025_auto_20190716_1346")]
9 |
10 | operations = [
11 | migrations.AddField(
12 | model_name="articles",
13 | name="description",
14 | field=models.TextField(
15 | blank=True, default="", max_length=250, verbose_name="Description"
16 | ),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/developerportal/apps/common/validators.py:
--------------------------------------------------------------------------------
1 | from django.core.exceptions import ValidationError
2 |
3 |
4 | def check_for_svg_file(obj):
5 | # A very light, naive check that the file at least has an .svg suffix.
6 | # This is NOT 100% safe/guaranteed, but given the users are trusted, this just a
7 | # small layer of protection against accidental oversights, because saving a bitmap
8 | # into this field by accident will cause `app_tags.render_svg()` to fail.
9 |
10 | if obj.file.name.split(".")[-1] != "svg":
11 | raise ValidationError(u"Only SVG images are allowed here.")
12 |
--------------------------------------------------------------------------------
/developerportal/apps/content/migrations/0004_update_content_manager.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-30 09:15
2 |
3 | from django.db import migrations
4 | import django.db.models.manager
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('content', '0003_auto_20190813_1503'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterModelManagers(
15 | name='contentpage',
16 | managers=[
17 | ('published_objects', django.db.models.manager.Manager()),
18 | ],
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0026_auto_20190813_1302.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-13 13:02
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("home", "0025_homepage_external_promos")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="homepage",
13 | name="card_description",
14 | field=models.TextField(
15 | blank=True, default="", max_length=400, verbose_name="Description"
16 | ),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0024_auto_20190813_1302.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-13 13:02
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("people", "0023_merge_20190802_1535")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="person",
13 | name="card_description",
14 | field=models.TextField(
15 | blank=True, default="", max_length=400, verbose_name="Description"
16 | ),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/src/css/templates/events.scss:
--------------------------------------------------------------------------------
1 | body.events {
2 | div.header-strip {
3 | margin-bottom: 0; // to allow for the four-card-row div of featured items
4 | }
5 |
6 | div.events-top-content {
7 | margin-bottom: $spacing-lg;
8 | @media #{$mq-md} {
9 | margin-top: 76px; // + 24px from mzp-l-content == 100px
10 | }
11 | }
12 |
13 | div.events-top-content,
14 | div.events-bottom-content,
15 | div.events-middle-content {
16 | .rich-text {
17 | max-width: 768px;
18 | }
19 | }
20 |
21 | div.four-card-row {
22 | margin-bottom: $spacing-lg;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/img/icons/map-pin.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/developerportal/apps/content/migrations/0008_contentpage_nav_description.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.11 on 2020-03-18 11:28
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('content', '0007_contentpage_description'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='contentpage',
15 | name='nav_description',
16 | field=models.TextField(blank=True, default='', max_length=400, verbose_name='Navigation description'),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0049_topic_nav_description.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.11 on 2020-03-18 11:28
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('topics', '0048_add_svg_help_text_to_topic_icon_filefield'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='topic',
15 | name='nav_description',
16 | field=models.TextField(blank=True, default='', max_length=400, verbose_name='Navigation description'),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/src/js/organisms/notification-bar.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Handles events related to the notification bar
3 | *
4 | * @class NotificationBar
5 | */
6 |
7 | module.exports = class NotificationBar {
8 | static init() {
9 | const dissmissButtons = document.querySelectorAll(
10 | '.mzp-c-notification-bar-button',
11 | );
12 | for (let i = 0; i < dissmissButtons.length; i += 1) {
13 | dissmissButtons[i].addEventListener(
14 | 'click',
15 | function handler(e) {
16 | e.currentTarget.parentNode.remove();
17 | },
18 | false,
19 | );
20 | }
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0032_auto_20191008_1530.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.6 on 2019-10-08 15:30
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('people', '0031_person_nickname'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='person',
15 | name='role',
16 | field=models.CharField(choices=[('staff', 'Staff'), ('tech-speaker', 'Tech Speaker'), ('community', 'Community')], default='staff', max_length=250),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/developerportal/apps/mozimages/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | from wagtail.images.models import AbstractImage, AbstractRendition, Image
4 |
5 |
6 | class MozImage(AbstractImage):
7 | # Additional fields:
8 | caption = models.CharField(max_length=255, blank=True)
9 |
10 | admin_form_fields = Image.admin_form_fields + ("caption",)
11 |
12 |
13 | class Rendition(AbstractRendition):
14 | image = models.ForeignKey(
15 | MozImage, on_delete=models.CASCADE, related_name="renditions"
16 | )
17 |
18 | class Meta:
19 | unique_together = (("image", "filter_spec", "focal_point_key"),)
20 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0038_make_Person_country_optional.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.14 on 2020-07-06 11:15
2 |
3 | from django.db import migrations
4 | import django_countries.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('people', '0037_auto_20200511_1148'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='person',
16 | name='country',
17 | field=django_countries.fields.CountryField(blank=True, default='', max_length=2, verbose_name='Country or Region'),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/developerportal/apps/common/test_helpers.py:
--------------------------------------------------------------------------------
1 | # Patch wagtail.tests.utils.WagtailPageTests to re-configure use of the ModelBackend
2 | # so that WagtailPageTests.client.login() will work
3 |
4 | from django.test import override_settings
5 |
6 | from wagtail.tests.utils import WagtailPageTests
7 |
8 |
9 | class PatchedWagtailPageTests(WagtailPageTests):
10 | @override_settings(
11 | AUTHENTICATION_BACKENDS=(
12 | "mozilla_django_oidc.auth.OIDCAuthenticationBackend",
13 | "django.contrib.auth.backends.ModelBackend",
14 | )
15 | )
16 | def login(self):
17 | return super().login()
18 |
--------------------------------------------------------------------------------
/developerportal/templatetags/survey_tags.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from django import template
4 | from django.conf import settings
5 |
6 | logger = logging.getLogger(__name__)
7 | register = template.Library()
8 |
9 |
10 | @register.inclusion_tag("survey.html")
11 | def survey_prompt():
12 |
13 | survey_url = settings.TASK_COMPLETION_SURVEY_URL
14 | # If this is "undefined" in config, treat it as if absent
15 | if survey_url == "undefined":
16 | survey_url = None
17 |
18 | survey_percentage = settings.TASK_COMPLETION_SURVEY_PERCENTAGE
19 | return {"survey_url": survey_url, "survey_percentage": survey_percentage}
20 |
--------------------------------------------------------------------------------
/developerportal/apps/common/image_formats.py:
--------------------------------------------------------------------------------
1 | from wagtail.images.formats import (
2 | Format,
3 | register_image_format,
4 | unregister_image_format,
5 | )
6 |
7 | unregister_image_format("fullwidth")
8 | unregister_image_format("left")
9 | unregister_image_format("right")
10 |
11 | register_image_format(
12 | Format("left", "Left-aligned", "richtext-image format-left", "width-300")
13 | )
14 | register_image_format(
15 | Format("right", "Right-aligned", "richtext-image format-right", "width-300")
16 | )
17 | register_image_format(
18 | Format("center", "Center-aligned", "richtext-image format-center", "width-300")
19 | )
20 |
--------------------------------------------------------------------------------
/src/css/molecules/accessibility-nav.scss:
--------------------------------------------------------------------------------
1 | /*
2 | Keyboard & screen reader skip link menu
3 | ********************************************************************** */
4 |
5 | .nav-access {
6 | width: 100%;
7 | position: absolute;
8 | top: -20em;
9 | z-index: 1001;
10 |
11 | a {
12 | position: absolute;
13 | left: 0;
14 | right: 0;
15 | background-color: rgba(255, 255, 255, 0.9);
16 | padding: 12px 10px;
17 | font-weight: bold;
18 | text-align: center;
19 |
20 | &:hover,
21 | &:focus {
22 | box-shadow: 3px 3px 5px #aaa;
23 | top: 20em;
24 | text-decoration: none;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/developerportal/apps/content/migrations/0007_contentpage_description.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.11 on 2020-03-15 15:38
2 |
3 | from django.db import migrations
4 | import wagtail.core.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('content', '0006_contentpage_icon'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='contentpage',
16 | name='description',
17 | field=wagtail.core.fields.RichTextField(blank=True, default='', help_text='Optional short text description, max. 400 characters', max_length=400),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/k8s/redirector.ingress.yaml.j2:
--------------------------------------------------------------------------------
1 | apiVersion: extensions/v1beta1
2 | kind: Ingress
3 | metadata:
4 | name: {{ REDIRECTOR_NAME }}
5 | namespace: {{ REDIRECTOR_NAMESPACE }}
6 | labels:
7 | app: {{ REDIRECTOR_NAME }}
8 | annotations:
9 | kubernetes.io/ingress.class: "nginx"
10 | nginx.ingress.kubernetes.io/ssl-redirect: "true"
11 | spec:
12 | rules:
13 | {% set domains = REDIRECTOR_HOSTS.split(",") -%}
14 | {% for domain in domains -%}
15 | - host: {{ domain }}
16 | http:
17 | paths:
18 | - backend:
19 | serviceName: {{ REDIRECTOR_NAME }}
20 | servicePort: {{ REDIRECTOR_SERVICE_PORT }}
21 | {% endfor %}
22 |
--------------------------------------------------------------------------------
/src/css/molecules/resource-toolbar.scss:
--------------------------------------------------------------------------------
1 | .resource-toolbar {
2 | align-items: flex-start;
3 | display: flex;
4 | flex-direction: column;
5 |
6 | .resource-share {
7 | margin-top: 24px;
8 | }
9 |
10 | @media screen and (min-width: 600px) {
11 | align-items: center;
12 | flex-direction: row;
13 | justify-content: space-between;
14 |
15 | .resource-share {
16 | margin-top: 0;
17 | }
18 | }
19 | }
20 |
21 | .resource-toolbar-bottom {
22 | align-items: flex-start;
23 | margin-top: 24px;
24 |
25 | @media #{$mq-md} {
26 | margin-top: 48px;
27 | }
28 |
29 | .resource-share {
30 | margin-top: 0;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/css/organisms/people-section.scss:
--------------------------------------------------------------------------------
1 | .people-section {
2 | h2 {
3 | font-family: $body-font-family;
4 |
5 | font-size: $h4-font-size;
6 | line-height: heading-line-height($h4-font-size);
7 |
8 | margin: $spacing-md 0 $spacing-2xl;
9 |
10 | @media #{$mq-md} {
11 | font-size: $h4-font-size;
12 | line-height: heading-line-height($h4-font-size);
13 | }
14 |
15 | span {
16 | display: inline-block;
17 | padding-left: $spacing-sm;
18 | font-size: 0.6em;
19 | }
20 | }
21 | &.has-tint {
22 | background-color: $color-marketing-gray-20;
23 | h4 {
24 | margin-top: 16px;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/developerportal/apps/content/tests/test_content.py:
--------------------------------------------------------------------------------
1 | from developerportal.apps.common.test_helpers import PatchedWagtailPageTests
2 |
3 | from ...home.models import HomePage
4 | from ...people.models import People
5 | from ...topics.models import Topic
6 | from ..models import ContentPage
7 |
8 |
9 | class ContentPageTests(PatchedWagtailPageTests):
10 | """Tests for the ContentPage model."""
11 |
12 | def test_content_page_parent_pages(self):
13 | self.assertAllowedParentPageTypes(ContentPage, {ContentPage, HomePage, Topic})
14 |
15 | def test_content_page_subpages(self):
16 | self.assertAllowedSubpageTypes(ContentPage, {ContentPage, People})
17 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0016_auto_20190604_1317.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-04 13:17
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("articles", "0015_auto_20190604_1245")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="articletopic",
14 | name="topic",
15 | field=models.ForeignKey(
16 | null=True,
17 | on_delete=django.db.models.deletion.CASCADE,
18 | to="topics.Topic",
19 | ),
20 | )
21 | ]
22 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0019_auto_20190611_1453.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-11 14:53
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("articles", "0018_auto_20190611_1403")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="articletopic",
14 | name="topic",
15 | field=models.ForeignKey(
16 | on_delete=django.db.models.deletion.CASCADE,
17 | related_name="+",
18 | to="topics.Topic",
19 | ),
20 | )
21 | ]
22 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0035_soft_rename_Article_as_Post_via_meta.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.6 on 2019-11-01 10:54
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("articles", "0034_external_person_description")]
9 |
10 | operations = [
11 | migrations.AlterModelOptions(
12 | name="article",
13 | options={"verbose_name": "post", "verbose_name_plural": "posts"},
14 | ),
15 | migrations.AlterModelOptions(
16 | name="articles",
17 | options={"verbose_name": "posts", "verbose_name_plural": "posts"},
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/developerportal/apps/events/migrations/0003_auto_20190709_1241.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-09 12:41
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("events", "0002_auto_20190704_1334")]
9 |
10 | operations = [
11 | migrations.AddField(
12 | model_name="event",
13 | name="latitude",
14 | field=models.FloatField(blank=True, null=True),
15 | ),
16 | migrations.AddField(
17 | model_name="event",
18 | name="longitude",
19 | field=models.FloatField(blank=True, null=True),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/developerportal/templates/molecules/cards/card.html:
--------------------------------------------------------------------------------
1 | {% if resource.resource_type == "article" %}
2 | {% include "molecules/cards/card-article.html" with resource=resource node_type=node_type show_author=show_author card_number=card_number %}
3 | {% elif resource.resource_type == "event" %}
4 | {% include "molecules/cards/card-event.html" with resource=resource node_type=node_type %}
5 | {% elif resource.resource_type == "person" %}
6 | {% include "molecules/cards/card-person.html" with person=resource node_type=node_type %}
7 | {% elif resource.resource_type == "video" %}
8 | {% include "molecules/cards/card-video.html" with resource=resource node_type=node_type %}
9 | {% endif %}
10 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0011_auto_20190705_1258.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-05 12:58
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("home", "0010_auto_20190704_1031")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="homepagefeaturedarticle",
14 | name="article",
15 | field=models.ForeignKey(
16 | on_delete=django.db.models.deletion.CASCADE,
17 | related_name="+",
18 | to="wagtailcore.Page",
19 | ),
20 | )
21 | ]
22 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0033_auto_20190718_1452.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-18 14:52
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("topics", "0031_auto_20190718_1424")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="topicfeaturedarticle",
14 | name="article",
15 | field=models.ForeignKey(
16 | on_delete=django.db.models.deletion.CASCADE,
17 | related_name="+",
18 | to="wagtailcore.Page",
19 | ),
20 | )
21 | ]
22 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0039_auto_20190805_0806.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-08-05 08:06
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("topics", "0038_topic_latest_articles_count")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="topic",
13 | name="latest_articles_count",
14 | field=models.IntegerField(
15 | choices=[(3, "3"), (6, "6"), (9, "9")],
16 | default=3,
17 | help_text="The number of articles to display for this topic.",
18 | ),
19 | )
20 | ]
21 |
--------------------------------------------------------------------------------
/developerportal/templates/organisms/partials/featured-card-selector.html:
--------------------------------------------------------------------------------
1 | {% if block.block_type == 'post' or block.block_type == 'event' or block.block_type == 'video' or block.block_type == 'content_page' %}
2 | {% with block.value as page %}
3 | {% include "molecules/card-featured.html" with resource=page.specific block_type=block.block_type %}
4 | {% endwith %}
5 | {% elif block.block_type == 'external_page' %}
6 | {% with block.value as external_page %}
7 | {% include "molecules/card-featured.html" with resource=external_page external_page=True block_type=block.block_type %}
8 | {% endwith %}
9 | {% endif %}
10 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0030_add_social_image_field.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.6 on 2019-10-01 15:59
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('mozimages', '0001_initial'),
11 | ('home', '0029_update_home_manager'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='homepage',
17 | name='social_image',
18 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='mozimages.MozImage'),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/templates/topics.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% load static %}
3 | {% load app_filters %}
4 |
5 | {% block body_class %}topics{% endblock %}
6 |
7 | {% block content %}
8 | {% static "img/icons/article-white.svg" as page_icon_asset_url %}
9 | {% include "molecules/header-strip.html" with content=page.title element="h1" page_icon_asset_url=page_icon_asset_url %}
10 |
11 |
12 | {% with page.topics.public.live.specific as topics %}
13 | {% if topics %}
14 | {% include "organisms/topic-links.html" with topics=topics pagetheme='directory' %}
15 | {% endif %}
16 | {% endwith %}
17 |
18 | {% endblock content %}
19 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0005_auto_20190610_1413.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-10 14:13
2 |
3 | from django.db import migrations
4 | import wagtail.core.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("topics", "0004_topicfeaturedarticle")]
10 |
11 | operations = [
12 | migrations.AlterModelOptions(
13 | name="subtopic",
14 | options={"verbose_name": "Sub-topic", "verbose_name_plural": "Sub-topics"},
15 | ),
16 | migrations.AddField(
17 | model_name="topic",
18 | name="intro",
19 | field=wagtail.core.fields.RichTextField(default=""),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/developerportal/apps/content/migrations/0005_add_social_image_field.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.6 on 2019-10-01 15:59
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('mozimages', '0001_initial'),
11 | ('content', '0004_update_content_manager'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='contentpage',
17 | name='social_image',
18 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='mozimages.MozImage'),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/src/img/icons/social/firefox/black.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/migrations/0013_externalevent_venue.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-24 15:38
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("externalcontent", "0012_auto_20190724_1437")]
9 |
10 | operations = [
11 | migrations.AddField(
12 | model_name="externalevent",
13 | name="venue",
14 | field=models.TextField(
15 | blank=True,
16 | default="",
17 | help_text="Full address of the event venue, displayed on the event detail page",
18 | max_length=250,
19 | ),
20 | )
21 | ]
22 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0037_auto_20200511_1148.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-11 11:48
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('people', '0036_remove_person_image'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='person',
16 | name='card_image',
17 | field=models.ForeignKey(blank=True, help_text='An image in 16:9 aspect ratio', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='mozimages.MozImage', verbose_name='Image'),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/developerportal/apps/events/migrations/0028_event_is_mozilla_supported_event.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.13 on 2020-06-29 19:20
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("events", "0027_add_Events_top_content_and_bottom_content")]
9 |
10 | operations = [
11 | migrations.AddField(
12 | model_name="event",
13 | name="is_mozilla_supported_event",
14 | field=models.BooleanField(
15 | blank=True,
16 | default=False,
17 | null=True,
18 | verbose_name="Is this event supported by Mozilla?",
19 | ),
20 | )
21 | ]
22 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0009_auto_20190702_0904.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-07-02 09:04
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("home", "0008_auto_20190625_1119")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="homepage",
13 | name="button_text",
14 | field=models.CharField(blank=True, default="", max_length=30),
15 | ),
16 | migrations.AlterField(
17 | model_name="homepage",
18 | name="button_url",
19 | field=models.URLField(blank=True, default="", max_length=140),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/developerportal/apps/people/templates/people.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% load static %}
3 | {% load wagtailcore_tags %}
4 | {% load wagtailimages_tags %}
5 |
6 | {% block body_class %}people{% endblock %}
7 |
8 | {% block content %}
9 |
10 | {% static "img/icons/people.svg" as page_icon_asset_url %}
11 | {% include "molecules/header-strip.html" with content=page.title element="h1" page_icon_asset_url=page_icon_asset_url %}
12 |
13 |
14 |
15 | {% include "organisms/filter-list.html" with type="person" resources=people no_resources_message="No people found" %}
16 |
17 |
18 | {% include "organisms/newsletter-signup.html" %}
19 | {% endblock content %}
20 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0010_article_labels.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-05-22 16:03
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("topics", "0001_initial"), ("articles", "0009_auto_20190521_1048")]
10 |
11 | operations = [
12 | migrations.AddField(
13 | model_name="article",
14 | name="labels",
15 | field=models.ForeignKey(
16 | blank=True,
17 | null=True,
18 | on_delete=django.db.models.deletion.SET_NULL,
19 | to="topics.Topic",
20 | ),
21 | )
22 | ]
23 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0011_auto_20190522_1630.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-05-22 16:30
2 |
3 | from django.db import migrations
4 | import modelcluster.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("topics", "0001_initial"), ("articles", "0010_article_labels")]
10 |
11 | operations = [
12 | migrations.RemoveField(model_name="article", name="labels"),
13 | migrations.AddField(
14 | model_name="article",
15 | name="labels",
16 | field=modelcluster.fields.ParentalManyToManyField(
17 | blank=True, related_name="_article_labels_+", to="topics.Topic"
18 | ),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/developerportal/apps/events/migrations/0017_auto_20190819_1304.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-19 13:04
2 |
3 | from django.db import migrations
4 | import wagtail.core.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("events", "0016_auto_20190814_1600")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="event",
14 | name="description",
15 | field=wagtail.core.fields.RichTextField(
16 | blank=True,
17 | default="",
18 | help_text="Optional short text description, max. 400 characters",
19 | max_length=400,
20 | ),
21 | )
22 | ]
23 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0004_auto_20190530_1441.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-05-30 14:41
2 |
3 | from django.db import migrations
4 | import modelcluster.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("people", "0003_auto_20190530_1437")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="person",
14 | name="labels",
15 | field=modelcluster.fields.ParentalManyToManyField(
16 | blank=True,
17 | related_name="_person_labels_+",
18 | to="topics.Topic",
19 | verbose_name="Topics interested in",
20 | ),
21 | )
22 | ]
23 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0026_auto_20190819_1304.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-19 13:04
2 |
3 | from django.db import migrations
4 | import wagtail.core.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("people", "0025_auto_20190813_1503")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="people",
14 | name="description",
15 | field=wagtail.core.fields.RichTextField(
16 | blank=True,
17 | default="",
18 | help_text="Optional short text description, max. 400 characters",
19 | max_length=400,
20 | ),
21 | )
22 | ]
23 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0043_auto_20190819_1304.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-19 13:04
2 |
3 | from django.db import migrations
4 | import wagtail.core.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("topics", "0042_auto_20190814_1600")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="topic",
14 | name="description",
15 | field=wagtail.core.fields.RichTextField(
16 | blank=True,
17 | default="",
18 | help_text="Optional short text description, max. 400 characters",
19 | max_length=400,
20 | ),
21 | )
22 | ]
23 |
--------------------------------------------------------------------------------
/developerportal/apps/videos/migrations/0007_auto_20190819_1304.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-19 13:04
2 |
3 | from django.db import migrations
4 | import wagtail.core.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("videos", "0006_auto_20190814_1600")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="video",
14 | name="description",
15 | field=wagtail.core.fields.RichTextField(
16 | blank=True,
17 | default="",
18 | help_text="Optional short text description, max. 400 characters",
19 | max_length=400,
20 | ),
21 | )
22 | ]
23 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0031_homepage_featured_people.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.6 on 2019-10-08 13:59
2 |
3 | from django.db import migrations
4 | import wagtail.core.blocks
5 | import wagtail.core.fields
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('home', '0030_add_social_image_field'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='homepage',
17 | name='featured_people',
18 | field=wagtail.core.fields.StreamField([('person', wagtail.core.blocks.PageChooserBlock(page_type=['people.Person']))], blank=True, help_text='Optional featured people, max. 3', null=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/developerportal/apps/content/migrations/0012_auto_20200511_1148.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-11 11:48
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('content', '0011_remove_contentpage_hero_image'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='contentpage',
16 | name='card_image',
17 | field=models.ForeignKey(blank=True, help_text='An image in 16:9 aspect ratio', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='mozimages.MozImage', verbose_name='Image'),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/migrations/0025_add_social_image_field.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.6 on 2019-10-01 15:59
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('mozimages', '0001_initial'),
11 | ('externalcontent', '0024_update_externalcontent_manager'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='externalcontent',
17 | name='social_image',
18 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='mozimages.MozImage'),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/data/devportal_topic_icons/default-d.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/developerportal/templates/wagtailadmin/login.html:
--------------------------------------------------------------------------------
1 | {% extends "wagtailadmin/login.html" %}
2 | {% load i18n app_tags %}
3 |
4 | {% block login_form %}
5 |
6 | {% use_conventional_auth as conventional_auth_enabled %}
7 |
8 | {% if conventional_auth_enabled %}
9 |
10 | {{ block.super }}
11 |
12 | {% else %}
13 |
14 | Admin
15 |
16 |
17 |
18 | {% trans 'Sign in with Mozilla SSO' %}
19 |
20 |
21 | If you lack SSO access, please ask your contact within Mozilla.
22 | {% endif %}
23 | {% endblock %}
24 |
25 |
--------------------------------------------------------------------------------
/src/img/icons/social/facebook/black.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/img/icons/social/facebook/brand.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/img/icons/social/facebook/white.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0017_auto_20190611_1344.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-11 13:44
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("articles", "0016_auto_20190604_1317")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="article",
14 | name="author",
15 | field=models.ForeignKey(
16 | blank=True,
17 | null=True,
18 | on_delete=django.db.models.deletion.SET_NULL,
19 | related_name="articles",
20 | to="people.Person",
21 | ),
22 | )
23 | ]
24 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/migrations/0022_auto_20190819_1304.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-19 13:04
2 |
3 | from django.db import migrations
4 | import wagtail.core.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("externalcontent", "0021_auto_20190814_1600")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="externalcontent",
14 | name="description",
15 | field=wagtail.core.fields.RichTextField(
16 | blank=True,
17 | default="",
18 | help_text="Optional short text description, max. 400 characters",
19 | max_length=400,
20 | ),
21 | )
22 | ]
23 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0006_auto_20190625_1111.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-25 11:11
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("home", "0005_auto_20190618_1635")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="homepage",
14 | name="header_image",
15 | field=models.ForeignKey(
16 | blank=True,
17 | null=True,
18 | on_delete=django.db.models.deletion.SET_NULL,
19 | related_name="+",
20 | to="mozimages.MozImage",
21 | ),
22 | )
23 | ]
24 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0007_auto_20190625_1112.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-25 11:12
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("home", "0006_auto_20190625_1111")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="homepage",
14 | name="header_image",
15 | field=models.ForeignKey(
16 | blank=True,
17 | null=True,
18 | on_delete=django.db.models.deletion.SET_NULL,
19 | related_name="+",
20 | to="wagtailimages.Image",
21 | ),
22 | )
23 | ]
24 |
--------------------------------------------------------------------------------
/developerportal/apps/home/migrations/0008_auto_20190625_1119.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-25 11:19
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("home", "0007_auto_20190625_1112")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="homepage",
14 | name="header_image",
15 | field=models.ForeignKey(
16 | blank=True,
17 | null=True,
18 | on_delete=django.db.models.deletion.SET_NULL,
19 | related_name="+",
20 | to="mozimages.MozImage",
21 | ),
22 | )
23 | ]
24 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0033_people_icon.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.11 on 2020-03-15 15:23
2 |
3 | import developerportal.apps.common.validators
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('people', '0032_auto_20191008_1530'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='people',
16 | name='icon',
17 | field=models.FileField(blank=True, default='', help_text='MUST be a black-on-transparent SVG icon ONLY, with no bitmap embedded in it.', upload_to='people/icons', validators=[developerportal.apps.common.validators.check_for_svg_file]),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0052_auto_20200511_1148.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-11 11:48
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('topics', '0051_remove_tabbed_panel_and_add_recent_work_streamfield'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='topic',
16 | name='card_image',
17 | field=models.ForeignKey(blank=True, help_text='An image in 16:9 aspect ratio', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='mozimages.MozImage', verbose_name='Image'),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/developerportal/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for developerportal project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | # Load dev settings by default. To override this, set either:
15 | # - DJANGO_ENV to e.g. production, or;
16 | # - DJANGO_SETTINGS_MODULE to e.g. developerportal.settings.production (takes precedence). # noqa
17 | env = os.environ.setdefault("DJANGO_ENV", "dev")
18 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", f"developerportal.settings.{env}")
19 |
20 | application = get_wsgi_application()
21 |
--------------------------------------------------------------------------------
/developerportal/apps/common/settings_helpers.py:
--------------------------------------------------------------------------------
1 | """Functionality to help with configuring settings.
2 | DO NOT IMPORT django.conf.settings INTO THIS MODULE because it is imported
3 | into settings.base
4 | """
5 | import os
6 |
7 | from developerportal.regex import REDIS_DB_URL_PATTERN
8 |
9 |
10 | def _get_redis_url_for_cache(redis_cache_db_number):
11 | _redis_cache_url = os.environ.get("REDIS_URL", "redis://redis:6379")
12 | if REDIS_DB_URL_PATTERN.match(_redis_cache_url):
13 | raise RuntimeError(
14 | "REDIS_URL specifies a specific database, not just the server"
15 | )
16 | if _redis_cache_url[-1] == "/":
17 | _redis_cache_url = _redis_cache_url[:-1]
18 | return _redis_cache_url + f"/{redis_cache_db_number}"
19 |
--------------------------------------------------------------------------------
/developerportal/templates/atoms/icons/facebook.svg:
--------------------------------------------------------------------------------
1 | {% load app_tags %}
2 |
3 | {% random_hash as hash %}
4 |
5 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/migrations/0018_auto_20190807_1244.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-07 12:44
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("externalcontent", "0017_auto_20190806_1041")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="externalvideo",
13 | name="duration",
14 | field=models.CharField(
15 | blank=True,
16 | help_text="Optional. Video duration in MM:SS format e.g. “12:34”. Shown as a small hint when the video is displayed as a card.",
17 | max_length=30,
18 | null=True,
19 | ),
20 | )
21 | ]
22 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0012_auto_20190603_1048.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-03 10:48
2 |
3 | from django.db import migrations
4 | import modelcluster.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("topics", "0003_subtopic"),
11 | ("articles", "0011_auto_20190522_1630"),
12 | ]
13 |
14 | operations = [
15 | migrations.RemoveField(model_name="article", name="labels"),
16 | migrations.AddField(
17 | model_name="article",
18 | name="topics",
19 | field=modelcluster.fields.ParentalManyToManyField(
20 | blank=True, related_name="_article_topics_+", to="topics.Topic"
21 | ),
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/developerportal/apps/content/migrations/0006_contentpage_icon.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.11 on 2020-03-15 15:23
2 |
3 | import developerportal.apps.common.validators
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('content', '0005_add_social_image_field'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='contentpage',
16 | name='icon',
17 | field=models.FileField(blank=True, default='', help_text='MUST be a black-on-transparent SVG icon ONLY, with no bitmap embedded in it.', upload_to='contentpage/icons', validators=[developerportal.apps.common.validators.check_for_svg_file]),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0055_topic_relevant_events.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.14 on 2020-07-03 13:05
2 |
3 | from django.db import migrations
4 | import wagtail.core.blocks
5 | import wagtail.core.fields
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('topics', '0054_remove_topic_color'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='topic',
17 | name='relevant_events',
18 | field=wagtail.core.fields.StreamField([('event', wagtail.core.blocks.PageChooserBlock(page_type=['events.Event', 'externalcontent.ExternalEvent']))], blank=True, help_text='Optional space for featured Events, max. 4.', null=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/developerportal/templates/atoms/icons/person.svg:
--------------------------------------------------------------------------------
1 | {% load app_tags %}
2 |
3 | {% random_hash as hash %}
4 |
5 |
--------------------------------------------------------------------------------
/src/css/templates/event.scss:
--------------------------------------------------------------------------------
1 | body.event {
2 | div.outbound-links {
3 | margin-top: $spacing-lg;
4 | li {
5 | @media #{$mq-md} {
6 | float: left;
7 | margin-right: $spacing-md;
8 | }
9 | a {
10 | display: block;
11 | margin-bottom: $spacing-md;
12 | @media #{$mq-md} {
13 | display: inline-block;
14 | }
15 | }
16 | }
17 |
18 | .resource-share {
19 | a {
20 | display: inherit;
21 | }
22 | display: inline-block;
23 | margin: $spacing-md 0px $spacing-2xl 0;
24 |
25 | @media #{$mq-md} {
26 | float: right;
27 | margin-top: 10px; // for vertical centering
28 | margin-left: $spacing-md;
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/developerportal/apps/content/migrations/0002_contentpage_hero_image.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-12 10:15
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("mozimages", "0001_initial"), ("content", "0001_initial")]
10 |
11 | operations = [
12 | migrations.AddField(
13 | model_name="contentpage",
14 | name="hero_image",
15 | field=models.ForeignKey(
16 | blank=True,
17 | null=True,
18 | on_delete=django.db.models.deletion.SET_NULL,
19 | related_name="+",
20 | to="mozimages.MozImage",
21 | ),
22 | )
23 | ]
24 |
--------------------------------------------------------------------------------
/developerportal/apps/content/migrations/0014_contentpage_card_image_3_2.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.14 on 2020-07-15 10:29
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('mozimages', '0001_initial'),
11 | ('content', '0013_make_sidebar_optional'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='contentpage',
17 | name='card_image_3_2',
18 | field=models.ForeignKey(blank=True, help_text='An image in 3:2 aspect ratio', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='mozimages.MozImage', verbose_name='Image'),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0009_topic_color.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-12 18:14
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("topics", "0008_auto_20190612_1759")]
9 |
10 | operations = [
11 | migrations.AddField(
12 | model_name="topic",
13 | name="color",
14 | field=models.CharField(
15 | choices=[
16 | ("blue", "Blue"),
17 | ("orange", "Orange"),
18 | ("green", "Green"),
19 | ("red", "Red"),
20 | ],
21 | default="blue",
22 | max_length=14,
23 | ),
24 | )
25 | ]
26 |
--------------------------------------------------------------------------------
/developerportal/templates/atoms/icons/location.svg:
--------------------------------------------------------------------------------
1 | {% load app_tags %}
2 |
3 | {% random_hash as hash %}
4 |
5 |
--------------------------------------------------------------------------------
/data/devportal_topic_icons/html.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/developerportal/apps/content/migrations/0015_hide_about_page_from_menu.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.14 on 2020-07-13 12:00
2 |
3 | from django.db import migrations
4 |
5 | ABOUT_PAGE_SLUG = "about"
6 |
7 |
8 | def forwards(apps, schema_editor):
9 | ContentPage = apps.get_model("content", "ContentPage")
10 |
11 | ContentPage.objects.filter(slug=ABOUT_PAGE_SLUG).update(show_in_menus=False)
12 |
13 |
14 | def backwards(apps, schema_editor):
15 | ContentPage = apps.get_model("content", "ContentPage")
16 | ContentPage.objects.filter(slug=ABOUT_PAGE_SLUG).update(show_in_menus=True)
17 |
18 |
19 | class Migration(migrations.Migration):
20 |
21 | dependencies = [("content", "0014_contentpage_card_image_3_2")]
22 |
23 | operations = [migrations.RunPython(forwards, backwards)]
24 |
--------------------------------------------------------------------------------
/developerportal/apps/events/migrations/0014_auto_20190813_1302.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-13 13:02
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("events", "0013_auto_20190731_1054")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="event",
13 | name="card_description",
14 | field=models.TextField(
15 | blank=True, default="", max_length=400, verbose_name="Description"
16 | ),
17 | ),
18 | migrations.AlterField(
19 | model_name="event",
20 | name="description",
21 | field=models.TextField(blank=True, default="", max_length=400),
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0028_auto_20190926_1049.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-26 10:49
2 |
3 | from django.db import migrations, models
4 | import django_countries.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('people', '0027_person_country'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='person',
16 | name='city',
17 | field=models.CharField(blank=True, default='', max_length=250),
18 | ),
19 | migrations.AlterField(
20 | model_name='person',
21 | name='country',
22 | field=django_countries.fields.CountryField(max_length=2, verbose_name='Country or Region'),
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0040_auto_20190813_1302.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-13 13:02
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("topics", "0039_auto_20190805_0806")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="topic",
13 | name="card_description",
14 | field=models.TextField(
15 | blank=True, default="", max_length=400, verbose_name="Description"
16 | ),
17 | ),
18 | migrations.AlterField(
19 | model_name="topic",
20 | name="description",
21 | field=models.TextField(blank=True, default="", max_length=400),
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/developerportal/apps/videos/migrations/0004_auto_20190813_1302.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-13 13:02
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("videos", "0003_auto_20190807_1244")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="video",
13 | name="card_description",
14 | field=models.TextField(
15 | blank=True, default="", max_length=400, verbose_name="Description"
16 | ),
17 | ),
18 | migrations.AlterField(
19 | model_name="video",
20 | name="description",
21 | field=models.TextField(blank=True, default="", max_length=400),
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/developerportal/apps/events/migrations/0018_update_event_manager.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-30 09:15
2 |
3 | from django.db import migrations
4 | import django.db.models.manager
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('events', '0017_auto_20190819_1304'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterModelManagers(
15 | name='event',
16 | managers=[
17 | ('published_objects', django.db.models.manager.Manager()),
18 | ],
19 | ),
20 | migrations.AlterModelManagers(
21 | name='events',
22 | managers=[
23 | ('published_objects', django.db.models.manager.Manager()),
24 | ],
25 | ),
26 | ]
27 |
--------------------------------------------------------------------------------
/developerportal/apps/topics/migrations/0044_update_topic_manager.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-30 09:15
2 |
3 | from django.db import migrations
4 | import django.db.models.manager
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('topics', '0043_auto_20190819_1304'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterModelManagers(
15 | name='topic',
16 | managers=[
17 | ('published_objects', django.db.models.manager.Manager()),
18 | ],
19 | ),
20 | migrations.AlterModelManagers(
21 | name='topics',
22 | managers=[
23 | ('published_objects', django.db.models.manager.Manager()),
24 | ],
25 | ),
26 | ]
27 |
--------------------------------------------------------------------------------
/developerportal/apps/videos/migrations/0008_update_video_manager.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-30 09:15
2 |
3 | from django.db import migrations
4 | import django.db.models.manager
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('videos', '0007_auto_20190819_1304'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterModelManagers(
15 | name='video',
16 | managers=[
17 | ('published_objects', django.db.models.manager.Manager()),
18 | ],
19 | ),
20 | migrations.AlterModelManagers(
21 | name='videos',
22 | managers=[
23 | ('published_objects', django.db.models.manager.Manager()),
24 | ],
25 | ),
26 | ]
27 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0029_auto_20190813_1302.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-13 13:02
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [("articles", "0028_merge_20190805_1426")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="article",
13 | name="card_description",
14 | field=models.TextField(
15 | blank=True, default="", max_length=400, verbose_name="Description"
16 | ),
17 | ),
18 | migrations.AlterField(
19 | model_name="article",
20 | name="description",
21 | field=models.TextField(blank=True, default="", max_length=400),
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0029_update_person_manager.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-30 09:15
2 |
3 | from django.db import migrations
4 | import django.db.models.manager
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('people', '0028_auto_20190926_1049'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterModelManagers(
15 | name='people',
16 | managers=[
17 | ('published_objects', django.db.models.manager.Manager()),
18 | ],
19 | ),
20 | migrations.AlterModelManagers(
21 | name='person',
22 | managers=[
23 | ('published_objects', django.db.models.manager.Manager()),
24 | ],
25 | ),
26 | ]
27 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0032_update_article_manager.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-30 09:15
2 |
3 | from django.db import migrations
4 | import django.db.models.manager
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('articles', '0031_auto_20190819_1304'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterModelManagers(
15 | name='article',
16 | managers=[
17 | ('published_objects', django.db.models.manager.Manager()),
18 | ],
19 | ),
20 | migrations.AlterModelManagers(
21 | name='articles',
22 | managers=[
23 | ('published_objects', django.db.models.manager.Manager()),
24 | ],
25 | ),
26 | ]
27 |
--------------------------------------------------------------------------------
/developerportal/templates/atoms/icons/video.svg:
--------------------------------------------------------------------------------
1 | {% load app_tags %}
2 |
3 | {% random_hash as hash %}
4 |
5 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0002_article_body.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-05-16 15:06
2 |
3 | from django.db import migrations
4 | import wagtail.core.blocks
5 | import wagtail.core.fields
6 | import wagtail.images.blocks
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [("articles", "0001_initial")]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name="article",
16 | name="body",
17 | field=wagtail.core.fields.StreamField(
18 | [
19 | ("paragraph", wagtail.core.blocks.RichTextBlock()),
20 | ("image", wagtail.images.blocks.ImageChooserBlock()),
21 | ],
22 | default=None,
23 | ),
24 | )
25 | ]
26 |
--------------------------------------------------------------------------------
/developerportal/apps/externalcontent/migrations/0004_auto_20190705_1306.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-05 13:06
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("externalcontent", "0003_externalarticle_externalevent_externalvideo")
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="externalarticle",
15 | name="readtime",
16 | field=models.CharField(blank=True, default="0 min read", max_length=30),
17 | ),
18 | migrations.AddField(
19 | model_name="externalvideo",
20 | name="video_duration",
21 | field=models.CharField(blank=True, default="0:00", max_length=30),
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/developerportal/templates/molecules/site-search-form.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Component for displaying site-search input.
3 |
4 | Optional params:
5 | - hide_label
6 | - placeholder_text
7 | - search_input_id
8 |
9 |
10 | {% endcomment %}
11 |
12 |
13 |
24 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/templates/articles.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% load static %}
3 | {% load wagtailcore_tags %}
4 |
5 | {% comment %} For now we're not renaming CSS classes from articles to posts {% endcomment %}
6 | {% block body_class %}articles{% endblock %}
7 |
8 | {% block content %}
9 |
10 | {% static "img/icons/article-white.svg" as page_icon_asset_url %}
11 | {% include "molecules/header-strip.html" with content=page.title element="h1" page_icon_asset_url=page_icon_asset_url %}
12 |
13 |
14 | {% include "organisms/filter-list.html" with type="article_or_video" resources=resources no_resources_message="No relevant posts found" hide_pagination=False %}
15 |
16 | {% include "organisms/newsletter-signup.html" %}
17 | {% endblock content %}
18 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 |
3 | services:
4 | - docker
5 |
6 | branches:
7 | except:
8 | - dev-push
9 | - stage-push
10 | - prod-push
11 |
12 | env:
13 | global:
14 | - DOCKER_COMPOSE_VERSION="1.24.1"
15 |
16 | before_install:
17 | - echo "Installing newer docker-compose"
18 | - sudo rm /usr/local/bin/docker-compose
19 | - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
20 | - chmod +x docker-compose
21 | - sudo mv docker-compose /usr/local/bin
22 | - docker version
23 | - docker-compose version
24 |
25 | install:
26 | - scripts/ci-setup --build
27 |
28 | script:
29 | - scripts/ci-tests
30 |
31 | after_script:
32 | - echo "Cleanup"
33 | - docker-compose down --volumes --remove-orphans
34 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0022_auto_20190624_1622.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-24 16:22
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("mozimages", "0001_initial"),
11 | ("articles", "0021_auto_20190618_0840"),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name="article",
17 | name="header_image",
18 | field=models.ForeignKey(
19 | blank=True,
20 | null=True,
21 | on_delete=django.db.models.deletion.SET_NULL,
22 | related_name="+",
23 | to="mozimages.MozImage",
24 | ),
25 | )
26 | ]
27 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0006_auto_20190604_1050.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-04 10:50
2 |
3 | from django.db import migrations
4 | import modelcluster.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [("topics", "0003_subtopic"), ("people", "0005_person_is_mozillian")]
10 |
11 | operations = [
12 | migrations.RemoveField(model_name="person", name="labels"),
13 | migrations.AddField(
14 | model_name="person",
15 | name="topics",
16 | field=modelcluster.fields.ParentalManyToManyField(
17 | blank=True,
18 | related_name="_person_topics_+",
19 | to="topics.Topic",
20 | verbose_name="Topics interested in",
21 | ),
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/developerportal/templates/organisms/article-read-more.html:
--------------------------------------------------------------------------------
1 | {% load wagtailcore_tags %}
2 |
3 | {% if page.related_resources %}
4 |
5 |
6 |
13 |
14 |
15 | {% for page in page.related_resources|slice:":3" %}
16 |
17 | {% include "molecules/card-featured.html" with resource=page block_type=page.block_type %}
18 |
19 | {% endfor %}
20 |
21 |
22 |
23 | {% endif %}
24 |
--------------------------------------------------------------------------------
/src/img/icons/video.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0006_auto_20190516_1303.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-05-16 13:03
2 |
3 | import datetime
4 | from django.db import migrations, models
5 | import wagtail.core.fields
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [("articles", "0005_auto_20190516_1236")]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="article",
15 | name="date",
16 | field=models.DateField(
17 | default=datetime.date.today, verbose_name="Article date"
18 | ),
19 | ),
20 | migrations.AddField(
21 | model_name="article",
22 | name="intro",
23 | field=wagtail.core.fields.RichTextField(default="", verbose_name="Intro"),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0012_article_header_image.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-05-30 09:07
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("wagtailimages", "0001_squashed_0021"),
11 | ("articles", "0011_auto_20190522_1630"),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name="article",
17 | name="header_image",
18 | field=models.ForeignKey(
19 | blank=True,
20 | null=True,
21 | on_delete=django.db.models.deletion.SET_NULL,
22 | related_name="+",
23 | to="wagtailimages.Image",
24 | ),
25 | )
26 | ]
27 |
--------------------------------------------------------------------------------
/developerportal/apps/common/tests/test_survey_tags.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase, override_settings
2 |
3 |
4 | class SurveyTagTests(TestCase):
5 | def test_survey_content_only_rendered_if_survey_url_configured(self):
6 | with override_settings(TASK_COMPLETION_SURVEY_URL="https://example.com/test"):
7 | response = self.client.get("/")
8 | self.assertContains(response, "complete a short survey", 1)
9 |
10 | with override_settings(TASK_COMPLETION_SURVEY_URL=None):
11 | response = self.client.get("/")
12 | self.assertNotContains(response, "complete a short survey")
13 |
14 | with override_settings(TASK_COMPLETION_SURVEY_URL="undefined"):
15 | response = self.client.get("/")
16 | self.assertNotContains(response, "complete a short survey")
17 |
--------------------------------------------------------------------------------
/developerportal/apps/events/migrations/0022_copy_image_field_data_to_card_image_field.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-07 12:15
2 |
3 | """Copy any image set as `Event.image` to populate the `Event.card_image` field
4 | instead, including updating the latest revision of the page (draft or live)"""
5 |
6 | from django.db import migrations
7 |
8 | from developerportal.apps.common.migration_utils import (
9 | move_Page_image_to_Page_card_image,
10 | )
11 |
12 |
13 | def forwards(apps, schema_editor):
14 | PageSubclass = apps.get_model("events", "Event")
15 | move_Page_image_to_Page_card_image(PageSubclass)
16 |
17 |
18 | class Migration(migrations.Migration):
19 |
20 | dependencies = [("events", "0021_auto_20200326_1339")]
21 |
22 | operations = [migrations.RunPython(forwards, migrations.RunPython.noop)]
23 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0035_copy_image_field_to_card_image_field.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-07 13:52
2 |
3 | """Copy any image set as `Person.image` to populate the `Person.card_image` field
4 | instead, including updating the latest revision of the page (draft or live)"""
5 |
6 | from django.db import migrations
7 |
8 | from developerportal.apps.common.migration_utils import (
9 | move_Page_image_to_Page_card_image,
10 | )
11 |
12 |
13 | def forwards(apps, schema_editor):
14 | PageSubclass = apps.get_model("people", "Person")
15 | move_Page_image_to_Page_card_image(PageSubclass)
16 |
17 |
18 | class Migration(migrations.Migration):
19 |
20 | dependencies = [("people", "0034_people_nav_description")]
21 |
22 | operations = [migrations.RunPython(forwards, migrations.RunPython.noop)]
23 |
--------------------------------------------------------------------------------
/developerportal/apps/videos/migrations/0011_copy_image_to_card_image.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-07 12:49
2 |
3 | """Copy any image set as `Video.image` to populate the `Video.card_image` field
4 | instead, including updating the latest revision of the page (draft or live)"""
5 |
6 | from django.db import migrations
7 |
8 | from developerportal.apps.common.migration_utils import (
9 | move_Page_image_to_Page_card_image,
10 | )
11 |
12 |
13 | def forwards(apps, schema_editor):
14 | PageSubclass = apps.get_model("videos", "Video")
15 | move_Page_image_to_Page_card_image(PageSubclass)
16 |
17 |
18 | class Migration(migrations.Migration):
19 |
20 | dependencies = [("videos", "0010_rename_related_links_without_data_port")]
21 |
22 | operations = [migrations.RunPython(forwards, migrations.RunPython.noop)]
23 |
--------------------------------------------------------------------------------
/developerportal/apps/videos/tests/test_videos.py:
--------------------------------------------------------------------------------
1 | from developerportal.apps.common.test_helpers import PatchedWagtailPageTests
2 |
3 | from ...home.models import HomePage
4 | from ..models import Video, Videos
5 |
6 |
7 | class VideoTests(PatchedWagtailPageTests):
8 | """Tests for the Video model."""
9 |
10 | def test_video_parent_pages(self):
11 | self.assertAllowedParentPageTypes(Video, {Videos})
12 |
13 | def test_video_subpages(self):
14 | self.assertAllowedSubpageTypes(Video, {})
15 |
16 |
17 | class VideosTests(PatchedWagtailPageTests):
18 | """Tests for the Videos model."""
19 |
20 | def test_videos_parent_pages(self):
21 | self.assertAllowedParentPageTypes(Videos, {HomePage})
22 |
23 | def test_videos_subpages(self):
24 | self.assertAllowedSubpageTypes(Videos, {Video})
25 |
--------------------------------------------------------------------------------
/src/img/icons/video-white.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/developerportal/templates/organisms/homepage-about.html:
--------------------------------------------------------------------------------
1 | {% load wagtailcore_tags %}
2 | {% load wagtailimages_tags %}
3 |
4 |
5 |
6 |
7 |
8 |
{{ title }}
9 | {% if subtitle %}
10 | {{ subtitle }}
11 | {% endif %}
12 |
13 |
14 | {% if button_url and button_text %}
15 |
20 | {% endif %}
21 |
22 |
23 |
--------------------------------------------------------------------------------
/k8s/db-migration-job.yaml.j2:
--------------------------------------------------------------------------------
1 | kind: Job
2 | apiVersion: batch/v1
3 | metadata:
4 | name: db-migration
5 | spec:
6 | template:
7 | metadata:
8 | name: db-migration
9 | spec:
10 | restartPolicy: Never
11 | containers:
12 | - name: db-migration
13 | image: {{ APP_IMAGE }}:{{ APP_IMAGE_TAG }}
14 | imagePullPolicy: {{ APP_IMAGE_PULL_POLICY }}
15 | command:
16 | - python
17 | args:
18 | - manage.py
19 | - migrate
20 | - "--noinput"
21 | resources:
22 | requests:
23 | cpu: {{ APP_CPU_REQUEST }}
24 | memory: {{ APP_MEMORY_REQUEST }}
25 | limits:
26 | cpu: {{ APP_CPU_LIMIT }}
27 | memory: {{ APP_MEMORY_LIMIT }}
28 | {% include 'app.env.yaml.j2' %}
29 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0012_article_author.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-05-30 16:15
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("wagtailcore", "0041_group_collection_permissions_verbose_name_plural"),
11 | ("articles", "0011_auto_20190522_1630"),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name="article",
17 | name="author",
18 | field=models.ForeignKey(
19 | blank=True,
20 | null=True,
21 | on_delete=django.db.models.deletion.SET_NULL,
22 | related_name="+",
23 | to="wagtailcore.Page",
24 | ),
25 | )
26 | ]
27 |
--------------------------------------------------------------------------------
/developerportal/apps/home/tests/test_home.py:
--------------------------------------------------------------------------------
1 | from wagtail.core.models import Page
2 |
3 | from developerportal.apps.common.test_helpers import PatchedWagtailPageTests
4 |
5 | from ...articles.models import Articles
6 | from ...content.models import ContentPage
7 | from ...events.models import Events
8 | from ...people.models import People
9 | from ...topics.models import Topics
10 | from ...videos.models import Videos
11 | from ..models import HomePage
12 |
13 |
14 | class HomePageTests(PatchedWagtailPageTests):
15 | """Tests for the HomePage model."""
16 |
17 | def test_topic_parent_pages(self):
18 | self.assertAllowedParentPageTypes(HomePage, {Page})
19 |
20 | def test_home_page_subpages(self):
21 | self.assertAllowedSubpageTypes(
22 | HomePage, {Articles, ContentPage, Events, Topics, People, Videos}
23 | )
24 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0018_people_keywords.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-23 16:59
2 |
3 | from django.db import migrations
4 | import modelcluster.contrib.taggit
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("taggit", "0002_auto_20150616_2121"),
11 | ("people", "0017_auto_20190718_1424"),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name="people",
17 | name="keywords",
18 | field=modelcluster.contrib.taggit.ClusterTaggableManager(
19 | blank=True,
20 | help_text="A comma-separated list of tags.",
21 | through="people.PeopleTag",
22 | to="taggit.Tag",
23 | verbose_name="Tags",
24 | ),
25 | )
26 | ]
27 |
--------------------------------------------------------------------------------
/k8s/search-index-update-job.yaml.j2:
--------------------------------------------------------------------------------
1 | kind: Job
2 | apiVersion: batch/v1
3 | metadata:
4 | name: search-index-update
5 | spec:
6 | template:
7 | metadata:
8 | name: search-index-update
9 | spec:
10 | restartPolicy: Never
11 | containers:
12 | - name: search-index-update
13 | image: {{ APP_IMAGE }}:{{ APP_IMAGE_TAG }}
14 | imagePullPolicy: {{ APP_IMAGE_PULL_POLICY }}
15 | command:
16 | - python
17 | args:
18 | - manage.py
19 | - wagtail_update_index
20 | resources:
21 | requests:
22 | cpu: {{ APP_CPU_REQUEST }}
23 | memory: {{ APP_MEMORY_REQUEST }}
24 | limits:
25 | cpu: {{ APP_CPU_LIMIT }}
26 | memory: {{ APP_MEMORY_LIMIT }}
27 | {% include 'app.env.yaml.j2' %}
28 |
--------------------------------------------------------------------------------
/developerportal/apps/events/migrations/0021_auto_20200326_1339.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.11 on 2020-03-26 13:39
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('events', '0020_events_body'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='event',
15 | name='event_content',
16 | field=models.URLField(blank=True, default='', help_text='Link to a page (in this site or elsewhere) with content about this event.', verbose_name='Event content'),
17 | ),
18 | migrations.AddField(
19 | model_name='event',
20 | name='official_website',
21 | field=models.URLField(blank=True, default='', verbose_name='Official website'),
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/developerportal/apps/people/migrations/0020_people_keywords.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.3 on 2019-07-25 12:26
2 |
3 | from django.db import migrations
4 | import modelcluster.contrib.taggit
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("taggit", "0002_auto_20150616_2121"),
11 | ("people", "0019_remove_people_keywords"),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name="people",
17 | name="keywords",
18 | field=modelcluster.contrib.taggit.ClusterTaggableManager(
19 | blank=True,
20 | help_text="A comma-separated list of tags.",
21 | through="people.PeopleTag",
22 | to="taggit.Tag",
23 | verbose_name="Tags",
24 | ),
25 | )
26 | ]
27 |
--------------------------------------------------------------------------------
/developerportal/apps/articles/migrations/0039_copy_image_field_data_to_card_image_field.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-06 22:10
2 |
3 | """Copy any image set as `Article.image` to populate the `Article.card_image` field
4 | instead, including updating the latest revision of the page (draft or live)"""
5 |
6 | from django.db import migrations
7 |
8 | from developerportal.apps.common.migration_utils import (
9 | move_Page_image_to_Page_card_image,
10 | )
11 |
12 |
13 | def forwards(apps, schema_editor):
14 | PageSubclass = apps.get_model("articles", "Article")
15 | move_Page_image_to_Page_card_image(PageSubclass)
16 |
17 |
18 | class Migration(migrations.Migration):
19 |
20 | dependencies = [("articles", "0038_rename_related_links_without_data_port")]
21 |
22 | operations = [migrations.RunPython(forwards, migrations.RunPython.noop)]
23 |
--------------------------------------------------------------------------------
/k8s/wait_for_job.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | GET_JOB_JSON="kubectl -n ${K8S_NAMESPACE} get job ${JOB_NAME} -o json"
4 |
5 | check_job() {
6 | echo "Checking..."
7 | ${GET_JOB_JSON} | jq -e '(.status.succeeded != null) or (.status.failed != null)'
8 | }
9 |
10 | wait_for_job() {
11 | echo "Waiting for job \"${JOB_NAME}\" to complete..."
12 | until check_job
13 | do
14 | sleep 1
15 | done
16 | # Set the exit status based on the job's status.
17 | if ${GET_JOB_JSON} | jq -e '(.status.succeeded != null)'
18 | then
19 | echo "Job \"${JOB_NAME}\" was successful!"
20 | exit 0
21 | else
22 | echo "Job \"${JOB_NAME}\" failed!"
23 | exit 1
24 | fi;
25 | }
26 |
27 | # Wait until the job completes (succeeds or fails), and
28 | # return the exit status based on the status of the job.
29 | wait_for_job
30 |
--------------------------------------------------------------------------------
/developerportal/apps/common/tests/test_models.py:
--------------------------------------------------------------------------------
1 | from unittest import mock
2 |
3 | from django.test import TestCase
4 |
5 | from ...content.models import ContentPage
6 |
7 |
8 | class PageBaseModelTestsUsingConcreteClass(TestCase):
9 | """Tests that use a concrete ContentPage class to test behaviour
10 | from the BasePage"""
11 |
12 | def test_save(self):
13 |
14 | with mock.patch(
15 | "developerportal.apps.common.models.cache.delete_many"
16 | ) as mock_delete_many:
17 |
18 | self.assertEqual(ContentPage._bulk_invalidation_cache_keys, [])
19 |
20 | page = ContentPage(slug="test", path="00010022", depth=2, title="Test")
21 | page._bulk_invalidation_cache_keys = ["foo", "bar", "baz"]
22 | page.save()
23 | mock_delete_many.assert_called_once_with(["foo", "bar", "baz"])
24 |
--------------------------------------------------------------------------------
/developerportal/apps/taskqueue/tests/test_wagtail_hooks.py:
--------------------------------------------------------------------------------
1 | from unittest import mock
2 |
3 | from django.test import TestCase
4 |
5 | from wagtail.core.models import Page
6 | from wagtail.core.signals import page_published, page_unpublished
7 |
8 |
9 | class SignalsTestCase(TestCase):
10 | @mock.patch(
11 | "developerportal.apps.taskqueue.wagtail_hooks.invalidate_entire_cdn.delay"
12 | )
13 | def test_cdn_invalidation_signal_handler(self, mock_invalidate_entire_cdn__delay):
14 |
15 | cases = [{"signal": page_published}, {"signal": page_unpublished}]
16 |
17 | for case in cases:
18 | mock_invalidate_entire_cdn__delay.reset_mock()
19 | with self.subTest(case=case):
20 | case["signal"].send(sender=Page, instance=None)
21 | mock_invalidate_entire_cdn__delay.assert_called_once_with()
22 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Django==2.2.14
2 | celery==4.4.6 # Be careful when updating this - ensure works with kombu
3 | redis==3.5.3
4 | kombu==4.6.11 # Be careful when updating this - ensure works with celery
5 | django-celery-results==1.2.1
6 | django-countries==6.1.2
7 | django-redis==4.12.1
8 | gunicorn==20.0.4
9 | gevent==20.6.2
10 | greenlet==0.4.16
11 | gevent-socketio==0.3.6
12 | gevent-websocket==0.10.1
13 | mozilla-django-oidc==1.2.3
14 | django-storages==1.9.1
15 | boto3==1.14.42
16 | psycopg2==2.8.5
17 | Pygments==2.6.1
18 | raven==6.10.0
19 | readtime==1.1.1
20 | wagtail==2.9.3
21 | whitenoise==5.1.0
22 | urlwait==1.0
23 | newrelic==5.16.0.145
24 | feedparser==5.2.1
25 | python-dateutil==2.8.1
26 | bleach==3.1.5
27 | django-ratelimit==3.0.1
28 |
29 | # Specific versions of dependencies to satisfy clashing requirements:
30 | beautifulsoup4==4.8.2 # from Wagtail 2.9
31 |
--------------------------------------------------------------------------------
/src/img/icons/speaker.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/developerportal/settings/dev.py:
--------------------------------------------------------------------------------
1 | from .base import *
2 |
3 | # SECURITY WARNING: don't run with debug turned on in production!
4 | DEBUG = True
5 |
6 | # SECURITY WARNING: define the correct hosts in production!
7 | ALLOWED_HOSTS = ["*"]
8 |
9 | CELERY_BROKER_URL = "redis://redis:6379"
10 |
11 | EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
12 |
13 | # Disable production defaults that get in the way of local development
14 | SECURE_SSL_REDIRECT = False
15 | CSRF_COOKIE_SECURE = False
16 | SESSION_COOKIE_SECURE = False
17 | SECURE_HSTS_SECONDS = 0
18 |
19 | # Swap out the default use of S3 for user media to instead use local machine
20 | DEFAULT_FILE_STORAGE = "django.core.files.storage.FileSystemStorage"
21 | MEDIA_URL = "/media/"
22 | MEDIA_ROOT = os.path.join(BASE_DIR, "media")
23 |
24 | try:
25 | from .local import *
26 | except ImportError:
27 | pass
28 |
--------------------------------------------------------------------------------
/k8s/app.svc.yaml.j2:
--------------------------------------------------------------------------------
1 | kind: Service
2 | apiVersion: v1
3 | metadata:
4 | name: {{ APP_SERVICE_NAME }}
5 | annotations:
6 | service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
7 | service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
8 | service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "{{ APP_SERVICE_CERT_ARN }}"
9 | service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "{{ APP_SERVICE_IDLE_TIMEOUT }}"
10 | service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: "Stack={{ AWS_RESOURCE_STACK }},Environment={{ TARGET_ENVIRONMENT }}"
11 | service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
12 | spec:
13 | type: LoadBalancer
14 | selector:
15 | app: {{ APP_NAME }}
16 | ports:
17 | - port: 443
18 | targetPort: {{ APP_PORT }}
19 | protocol: TCP
20 |
--------------------------------------------------------------------------------
/developerportal/apps/content/migrations/0010_copy_hero_image_field_to_card_image_field.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.12 on 2020-05-07 13:57
2 | """Copy any image set as `ContentPage.hero_image` to populate the
3 | `ContentPage.card_image` field instead, including updating the latest
4 | revision of the page (draft or live)"""
5 |
6 | from django.db import migrations
7 |
8 | from developerportal.apps.common.migration_utils import (
9 | move_Page_image_to_Page_card_image,
10 | )
11 |
12 |
13 | def forwards(apps, schema_editor):
14 | PageSubclass = apps.get_model("content", "ContentPage")
15 | move_Page_image_to_Page_card_image(PageSubclass, source_field="hero_image")
16 |
17 |
18 | class Migration(migrations.Migration):
19 |
20 | dependencies = [("content", "0009_contentpage_sidebar")]
21 |
22 | operations = [migrations.RunPython(forwards, migrations.RunPython.noop)]
23 |
--------------------------------------------------------------------------------
/developerportal/templates/atoms/icons/reading-time.svg:
--------------------------------------------------------------------------------
1 | {% load app_tags %}
2 |
3 | {% random_hash as hash %}
4 |
5 |
--------------------------------------------------------------------------------
/src/css/molecules/search-result.scss:
--------------------------------------------------------------------------------
1 | .search-result-item {
2 | margin-left: calc(#{$spacing-sm} * -1);
3 | margin-bottom: $spacing-md;
4 | .mzp-c-card-block-link {
5 | padding: $spacing-sm $spacing-sm $spacing-xs $spacing-sm;
6 | }
7 |
8 | h2 {
9 | font-size: 1.4rem;
10 | line-height: 1.5;
11 | margin-bottom: 0.2em;
12 | @media #{$mq-md} {
13 | font-size: 1.5rem;
14 | }
15 | }
16 |
17 | .search-result-title {
18 | margin-right: $spacing-md;
19 | }
20 |
21 | .search-result-type {
22 | background-color: $color-marketing-gray-70;
23 | border-radius: 4px;
24 | color: $color-white;
25 | display: inline-block;
26 | font-size: 0.7em;
27 | line-height: 1.2em;
28 | padding: 4px 6px;
29 | vertical-align: 1px;
30 | width: auto;
31 | }
32 |
33 | .rich-text {
34 | margin-bottom: $spacing-md;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------