├── nda ├── __init__.py ├── migrations │ └── __init__.py ├── models.py ├── admin.py ├── apps.py ├── templates │ └── nda │ │ ├── already-signed.html │ │ ├── success.html │ │ ├── nda.html │ │ ├── buy_nda.html │ │ └── markdown │ │ ├── nda.md │ │ └── buy_nda.md ├── forms.py ├── tests │ ├── test_markdown.py │ ├── test_buy_nda.py │ └── test_blanket_nda.py └── views.py ├── news ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0004_auto_20161126_0105.py │ ├── 0002_auto_20161125_2020.py │ ├── 0006_auto_20161128_1656.py │ ├── 0005_post_slug.py │ ├── 0003_news_authors.py │ ├── 0001_initial.py │ └── 0001_squashed_0006_auto_20161128_1656.py ├── tests.py ├── apps.py ├── admin.py ├── urls.py ├── templates │ └── news │ │ ├── post.html │ │ └── posts.html ├── management │ └── commands │ │ └── create_content.py ├── factories.py ├── feeds.py ├── views.py └── models.py ├── web ├── __init__.py ├── migrations │ └── __init__.py ├── admin.py ├── tests.py ├── static │ └── web │ │ ├── img │ │ ├── astronaut.jpg │ │ └── gsa-logo-dark.jpg │ │ └── css │ │ └── style.css ├── models.py ├── apps.py ├── templates │ ├── 404.html │ ├── 500.html │ ├── rest_framework_docs │ │ └── docs.html │ └── web │ │ ├── guides.html │ │ ├── profile.html │ │ ├── index.html │ │ ├── includes │ │ └── footer.html │ │ └── base.html └── views.py ├── .cfignore ├── projects ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0004_remove_buy_locked.py │ ├── 0024_remove_project_active.py │ ├── 0007_remove_buy_procurement_method.py │ ├── 0020_auto_20170131_0419.py │ ├── 0008_auto_20170117_1819.py │ ├── 0016_auto_20170123_1550.py │ ├── 0023_auto_20170201_1640.py │ ├── 0018_auto_20170131_0411.py │ ├── 0021_auto_20170131_0428.py │ ├── 0009_procurementmethod_short_name.py │ ├── 0013_auto_20170123_0350.py │ ├── 0006_new_procurement_methods.py │ ├── 0019_auto_20170131_0412.py │ ├── 0003_auto_20170110_1459.py │ ├── 0022_auto_20170201_1639.py │ ├── 0012_auto_20170123_0145.py │ ├── 0025_auto_20170201_2018.py │ ├── 0017_auto_20170123_1652.py │ ├── 0010_auto_20170117_2357.py │ ├── 0005_auto_20170117_1752.py │ ├── 0014_auto_20170123_0403.py │ ├── 0015_auto_20170123_1444.py │ └── 0002_auto_20170109_1724.py ├── templatetags │ ├── __init__.py │ └── document_tags.py ├── apps.py ├── fixtures │ └── procurement_methods.json ├── management │ └── commands │ │ ├── create_projects.py │ │ └── create_buys.py ├── templates │ └── projects │ │ ├── private-page.html │ │ ├── create_buy.html │ │ ├── document.html │ │ ├── project.html │ │ ├── client.html │ │ ├── iaa.html │ │ ├── edit_client.html │ │ ├── financials.html │ │ ├── edit_iaa.html │ │ ├── edit_project.html │ │ └── buys.html ├── filters.py ├── tests │ ├── test_admin_views.py │ ├── test_iaa_model.py │ ├── test_projects_model.py │ ├── test_form.py │ ├── test_private_buys.py │ ├── test_private_projects.py │ ├── test_projects_api.py │ └── test_buys_api.py ├── fields.py ├── widgets.py ├── serializers.py ├── urls.py └── forms.py ├── uaa_client ├── __init__.py ├── tests │ └── __init__.py ├── urls.py ├── templates │ ├── uaa_client │ │ ├── logged_out.html │ │ └── oauth2_error.html │ └── admin │ │ └── add_user_form.html ├── views.py └── authentication.py ├── acquisitions ├── __init__.py ├── management │ └── commands │ │ ├── staff_projects.py │ │ └── init_groups.py ├── factories.py ├── wsgi.py └── urls.py ├── runtime.txt ├── team ├── migrations │ ├── __init__.py │ ├── 0003_auto_20161029_1649.py │ ├── 0010_remove_teammate_read_only.py │ ├── 0002_teammate_bio.py │ ├── 0005_teammate_read_only.py │ ├── 0011_auto_20161105_2006.py │ ├── 0009_auto_20161031_2306.py │ ├── 0007_teammate_photo.py │ ├── 0008_auto_20161031_2304.py │ ├── 0002_auto_20161208_1623.py │ ├── 0004_auto_20161029_1650.py │ ├── 0006_auto_20161031_0210.py │ ├── 0001_initial.py │ └── 0001_squashed_0011_auto_20161105_2006.py ├── __init__.py ├── tests.py ├── admin.py ├── apps.py ├── management │ └── commands │ │ └── create_team.py ├── signals.py ├── factories.py ├── urls.py ├── templates │ └── team │ │ └── teammate.html ├── serializers.py ├── models.py ├── tests │ └── test_team_api.py └── views.py ├── fake_uaa_provider ├── __init__.py ├── urls.py └── templates │ └── fake_uaa_provider │ └── fake_uaa_provider.html ├── pytest.ini ├── .bandit ├── media └── team │ └── photos │ └── default.png ├── third-party ├── uswds-0.13.1 │ ├── img │ │ ├── hero.png │ │ ├── plus.png │ │ ├── close.png │ │ ├── minus.png │ │ ├── search.png │ │ ├── correct8.png │ │ ├── correct9.png │ │ ├── logo-img.png │ │ ├── minus-alt.png │ │ ├── plus-alt.png │ │ ├── alerts │ │ │ ├── error.png │ │ │ ├── info.png │ │ │ ├── success.png │ │ │ ├── warning.png │ │ │ ├── success.svg │ │ │ ├── warning.svg │ │ │ ├── error.svg │ │ │ └── info.svg │ │ ├── arrow-down.png │ │ ├── arrow-right.png │ │ ├── circle-124.png │ │ ├── search-alt.png │ │ ├── external-link.png │ │ ├── us_flag_small.png │ │ ├── angle-arrow-down.png │ │ ├── external-link-alt.png │ │ ├── favicons │ │ │ ├── favicon.ico │ │ │ ├── favicon.png │ │ │ ├── favicon-16.png │ │ │ ├── favicon-40.png │ │ │ ├── favicon-57.png │ │ │ ├── favicon-72.png │ │ │ ├── favicon-114.png │ │ │ ├── favicon-144.png │ │ │ └── favicon-192.png │ │ ├── external-link-hover.png │ │ ├── angle-arrow-down-hover.png │ │ ├── angle-arrow-up-primary.png │ │ ├── social-icons │ │ │ ├── png │ │ │ │ ├── rss25.png │ │ │ │ ├── facebook25.png │ │ │ │ ├── twitter16.png │ │ │ │ └── youtube15.png │ │ │ └── svg │ │ │ │ ├── facebook25.svg │ │ │ │ ├── twitter16.svg │ │ │ │ ├── rss25.svg │ │ │ │ └── youtube15.svg │ │ ├── angle-arrow-down-primary.png │ │ ├── external-link-alt-hover.png │ │ ├── angle-arrow-up-primary-hover.png │ │ ├── angle-arrow-down-primary-hover.png │ │ ├── arrow-down.svg │ │ ├── minus.svg │ │ ├── minus-alt.svg │ │ ├── icon-https.svg │ │ ├── correct8.svg │ │ ├── correct9.svg │ │ ├── angle-arrow-down.svg │ │ ├── angle-arrow-down-hover.svg │ │ ├── angle-arrow-down-primary.svg │ │ ├── angle-arrow-up-primary.svg │ │ ├── angle-arrow-down-primary-hover.svg │ │ ├── angle-arrow-up-primary-hover.svg │ │ ├── arrow-right.svg │ │ ├── icon-dot-gov.svg │ │ ├── plus.svg │ │ ├── plus-alt.svg │ │ ├── close.svg │ │ ├── search.svg │ │ ├── search-alt.svg │ │ ├── external-link.svg │ │ ├── external-link-alt.svg │ │ ├── external-link-hover.svg │ │ └── external-link-alt-hover.svg │ └── fonts │ │ ├── merriweather-bold-webfont.eot │ │ ├── merriweather-bold-webfont.ttf │ │ ├── merriweather-bold-webfont.woff │ │ ├── merriweather-bold-webfont.woff2 │ │ ├── merriweather-italic-webfont.eot │ │ ├── merriweather-italic-webfont.ttf │ │ ├── merriweather-light-webfont.eot │ │ ├── merriweather-light-webfont.ttf │ │ ├── merriweather-light-webfont.woff │ │ ├── sourcesanspro-bold-webfont.eot │ │ ├── sourcesanspro-bold-webfont.ttf │ │ ├── sourcesanspro-bold-webfont.woff │ │ ├── sourcesanspro-light-webfont.eot │ │ ├── sourcesanspro-light-webfont.ttf │ │ ├── merriweather-italic-webfont.woff │ │ ├── merriweather-italic-webfont.woff2 │ │ ├── merriweather-light-webfont.woff2 │ │ ├── merriweather-regular-webfont.eot │ │ ├── merriweather-regular-webfont.ttf │ │ ├── merriweather-regular-webfont.woff │ │ ├── merriweather-regular-webfont.woff2 │ │ ├── sourcesanspro-bold-webfont.woff2 │ │ ├── sourcesanspro-italic-webfont.eot │ │ ├── sourcesanspro-italic-webfont.ttf │ │ ├── sourcesanspro-italic-webfont.woff │ │ ├── sourcesanspro-italic-webfont.woff2 │ │ ├── sourcesanspro-light-webfont.woff │ │ ├── sourcesanspro-light-webfont.woff2 │ │ ├── sourcesanspro-regular-webfont.eot │ │ ├── sourcesanspro-regular-webfont.ttf │ │ ├── sourcesanspro-regular-webfont.woff │ │ └── sourcesanspro-regular-webfont.woff2 └── a11y-dialog │ └── js │ └── a11y-dialog.min.js ├── Procfile ├── Dockerfile ├── bin ├── cf-ssh-env ├── seed-db.sh └── deploy ├── requirements-dev.in ├── manage.py ├── .codeclimate.yml ├── requirements.in ├── manifest.yml ├── manifest-staging.yml ├── opencontrol.yaml ├── docker-compose.yaml ├── CONTRIBUTING.md ├── LICENSE.md ├── requirements.txt ├── .gitignore ├── docs └── deploy.md ├── requirements-dev.txt ├── .travis.yml └── system-security-plan.yml /nda/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /news/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.cfignore: -------------------------------------------------------------------------------- 1 | .gitignore -------------------------------------------------------------------------------- /projects/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /uaa_client/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /acquisitions/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /nda/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /news/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.5.1 2 | -------------------------------------------------------------------------------- /team/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /uaa_client/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /fake_uaa_provider/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /acquisitions/management/commands/staff_projects.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /team/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'team.apps.TeamConfig' 2 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | DJANGO_SETTINGS_MODULE=acquisitions.settings 3 | -------------------------------------------------------------------------------- /nda/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /nda/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /news/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /team/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /web/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /web/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /.bandit: -------------------------------------------------------------------------------- 1 | [bandit] 2 | exclude: team/tests,/projects/tests,/nda/tests,uaa_auth/tests,/projects/factories.py 3 | -------------------------------------------------------------------------------- /nda/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class NdaConfig(AppConfig): 5 | name = 'nda' 6 | -------------------------------------------------------------------------------- /news/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class NewsConfig(AppConfig): 5 | name = 'news' 6 | -------------------------------------------------------------------------------- /media/team/photos/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/media/team/photos/default.png -------------------------------------------------------------------------------- /web/static/web/img/astronaut.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/web/static/web/img/astronaut.jpg -------------------------------------------------------------------------------- /web/models.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.db import models 4 | 5 | # Create your models here. 6 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/hero.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/plus.png -------------------------------------------------------------------------------- /web/static/web/img/gsa-logo-dark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/web/static/web/img/gsa-logo-dark.jpg -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: python manage.py migrate --noinput && python manage.py collectstatic --noinput && python manage.py runserver 0.0.0.0:$PORT 2 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/close.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/minus.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/search.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/correct8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/correct8.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/correct9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/correct9.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/logo-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/logo-img.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/minus-alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/minus-alt.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/plus-alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/plus-alt.png -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.5 2 | 3 | WORKDIR /app 4 | ADD . /app 5 | RUN pip install -r requirements.txt 6 | RUN pip install -r requirements-dev.txt 7 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/alerts/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/alerts/error.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/alerts/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/alerts/info.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/arrow-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/arrow-down.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/arrow-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/arrow-right.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/circle-124.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/circle-124.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/search-alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/search-alt.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/alerts/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/alerts/success.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/alerts/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/alerts/warning.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/external-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/external-link.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/us_flag_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/us_flag_small.png -------------------------------------------------------------------------------- /bin/cf-ssh-env: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export HOME=/home/vcap/app 4 | export TMPDIR=/home/vcap/tmp 5 | cd /home/vcap/app 6 | source .profile.d/python.sh 7 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/angle-arrow-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/angle-arrow-down.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/external-link-alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/external-link-alt.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/favicons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/favicons/favicon.ico -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/favicons/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/favicons/favicon.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/external-link-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/external-link-hover.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/favicons/favicon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/favicons/favicon-16.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/favicons/favicon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/favicons/favicon-40.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/favicons/favicon-57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/favicons/favicon-57.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/favicons/favicon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/favicons/favicon-72.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/angle-arrow-down-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/angle-arrow-down-hover.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/angle-arrow-up-primary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/angle-arrow-up-primary.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/favicons/favicon-114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/favicons/favicon-114.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/favicons/favicon-144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/favicons/favicon-144.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/favicons/favicon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/favicons/favicon-192.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/social-icons/png/rss25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/social-icons/png/rss25.png -------------------------------------------------------------------------------- /web/apps.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.apps import AppConfig 4 | 5 | 6 | class MainSiteConfig(AppConfig): 7 | name = 'main_site' 8 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/angle-arrow-down-primary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/angle-arrow-down-primary.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/external-link-alt-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/external-link-alt-hover.png -------------------------------------------------------------------------------- /projects/apps.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.apps import AppConfig 4 | 5 | 6 | class ProjectApiConfig(AppConfig): 7 | name = 'project_api' 8 | -------------------------------------------------------------------------------- /requirements-dev.in: -------------------------------------------------------------------------------- 1 | bandit 2 | codeclimate-test-reporter 3 | coverage 4 | ipython 5 | pip-tools 6 | poirot 7 | pycodestyle 8 | pytest 9 | pytest-cov 10 | pytest-django 11 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-bold-webfont.eot -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-bold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-bold-webfont.ttf -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/social-icons/png/facebook25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/social-icons/png/facebook25.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/social-icons/png/twitter16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/social-icons/png/twitter16.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/social-icons/png/youtube15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/social-icons/png/youtube15.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-bold-webfont.woff -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-bold-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-bold-webfont.woff2 -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-italic-webfont.eot -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-italic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-italic-webfont.ttf -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-light-webfont.eot -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-light-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-light-webfont.ttf -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-light-webfont.woff -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-bold-webfont.eot -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-bold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-bold-webfont.ttf -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-bold-webfont.woff -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-light-webfont.eot -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-light-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-light-webfont.ttf -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/angle-arrow-up-primary-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/angle-arrow-up-primary-hover.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-italic-webfont.woff -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-italic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-italic-webfont.woff2 -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-light-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-light-webfont.woff2 -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-regular-webfont.eot -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-regular-webfont.ttf -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-regular-webfont.woff -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/merriweather-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/merriweather-regular-webfont.woff2 -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-bold-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-bold-webfont.woff2 -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-italic-webfont.eot -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-italic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-italic-webfont.ttf -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-italic-webfont.woff -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-italic-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-italic-webfont.woff2 -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-light-webfont.woff -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-light-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-light-webfont.woff2 -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-regular-webfont.eot -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-regular-webfont.ttf -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-regular-webfont.woff -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/angle-arrow-down-primary-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/img/angle-arrow-down-primary-hover.png -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/fonts/sourcesanspro-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/acquisitions.18f.gov/develop/third-party/uswds-0.13.1/fonts/sourcesanspro-regular-webfont.woff2 -------------------------------------------------------------------------------- /bin/seed-db.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | python manage.py init_groups 4 | 5 | python manage.py create_team 6 | python manage.py create_projects 7 | python manage.py create_buys --add 8 | python manage.py create_content 9 | -------------------------------------------------------------------------------- /team/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from team.models import Teammate, Role 3 | 4 | 5 | # Register your models here. 6 | @admin.register(Teammate, Role) 7 | class TeamAdmin(admin.ModelAdmin): 8 | pass 9 | -------------------------------------------------------------------------------- /team/apps.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.apps import AppConfig 4 | 5 | 6 | class TeamConfig(AppConfig): 7 | name = 'team' 8 | 9 | def ready(self): 10 | from team import signals 11 | -------------------------------------------------------------------------------- /fake_uaa_provider/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | url(r'^oauth/authorize$', views.authorize, name='auth'), 7 | url(r'^oauth/token$', views.access_token, name='token'), 8 | ] 9 | -------------------------------------------------------------------------------- /news/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from news.models import Post 3 | 4 | 5 | # Register your models here. 6 | # @admin.register(Post) 7 | class PostAdmin(admin.ModelAdmin): 8 | prepopulated_fields = {"slug": ("title",)} 9 | 10 | admin.site.register(Post, PostAdmin) 11 | -------------------------------------------------------------------------------- /uaa_client/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | url(r'^callback$', views.oauth2_callback, name='callback'), 7 | url(r'^login$', views.login, name='login'), 8 | url(r'^logout$', views.logout, name='logout'), 9 | ] 10 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "acquisitions.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /news/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import include, url 2 | from news import views 3 | from news.feeds import LatestPosts 4 | 5 | urlpatterns = [ 6 | url(r'^$', views.posts, name='posts'), 7 | url(r'^rss/$', LatestPosts(), name='rss'), 8 | url(r'^(?P[a-z\-]+)$', views.post, name='post'), 9 | ] 10 | -------------------------------------------------------------------------------- /projects/fixtures/procurement_methods.json: -------------------------------------------------------------------------------- 1 | [{"model": "projects.procurementmethod", "pk": 1, "fields": {"name": "Agile Delivery Services BPA", "short_name": "agile_bpa", "vendors": []}}, {"model": "projects.procurementmethod", "pk": 2, "fields": {"name": "Micro-Purchase Platform", "short_name": "micropurchase", "vendors": []}}] -------------------------------------------------------------------------------- /web/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

404 - Page not found

7 |
Looks like that page doesn't exist. Back home?
8 |
9 |
10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /web/templates/500.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

500 - Server Error

7 |
Oops, something went wrong. Sorry about that! Back home?
8 |
9 |
10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /news/templates/news/post.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

{{ post.title }}

7 |
8 | {{ post.content }} 9 |
10 |
11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /nda/templates/nda/already-signed.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

Already signed!

7 |

8 | You've previously signed the NDA. No need to do it again! 9 |

10 |
11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /nda/templates/nda/success.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

Success!

7 |

8 | Thank you for signing the NDA. You've now been granted access to items requiring an NDA. 9 |

10 |
11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /projects/management/commands/create_projects.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | from django.core.management.base import BaseCommand, CommandError 3 | from projects.factories import ProjectFactory 4 | 5 | 6 | class Command(BaseCommand): 7 | help = 'Create a team' 8 | 9 | def handle(self, *args, **options): 10 | ProjectFactory.create_batch(5) 11 | -------------------------------------------------------------------------------- /team/management/commands/create_team.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | from django.core.management.base import BaseCommand, CommandError 3 | from team.factories import TeammateFactory, RoleFactory 4 | 5 | 6 | class Command(BaseCommand): 7 | help = 'Create a team' 8 | 9 | def handle(self, *args, **options): 10 | TeammateFactory.create_batch(5) 11 | -------------------------------------------------------------------------------- /projects/templates/projects/private-page.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

Not public yet!

7 |

We're working on something, but we're not yet ready to tell you about it publicly. Check back soon!

8 |
9 |
10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /nda/forms.py: -------------------------------------------------------------------------------- 1 | import floppyforms.__future__ as forms 2 | 3 | 4 | class NDAForm(forms.Form): 5 | agree = forms.BooleanField() 6 | 7 | def clean_agree(self): 8 | agree = self.cleaned_data['agree'] 9 | if agree == True: 10 | return agree 11 | else: 12 | raise forms.ValidationError("You must agree to the terms of the NDA") 13 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | pep8: 3 | enabled: true 4 | eslint: 5 | enabled: true 6 | csslint: 7 | enabled: true 8 | duplication: 9 | enabled: true 10 | config: 11 | languages: 12 | - python 13 | ratings: 14 | paths: 15 | - "**.py" 16 | exclude_paths: 17 | - "third-party/**" 18 | - "projects/migrations/*" 19 | - "team/migrations/*" 20 | -------------------------------------------------------------------------------- /projects/templates/projects/create_buy.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |
7 | {% csrf_token %} 8 | {{ form }} 9 | 10 |
11 |
12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /projects/templates/projects/document.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | {% load markdown_deux_tags %} 3 | 4 | {% block content %} 5 |
6 |
7 |

Back

8 | {% markdown %} 9 | {{ document | safe }} 10 | {% endmarkdown %} 11 |
12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /nda/tests/test_markdown.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from django.template.loader import render_to_string 3 | 4 | 5 | def test_markdown(): 6 | rendered = render_to_string('nda/nda.html') 7 | # The h1 tag has a tab due to markdown rendering for some reason 8 | expected = "

Non-Disclosure Agreement for TTS Office of "\ 9 | "Acquisitions

" 10 | assert expected in rendered 11 | -------------------------------------------------------------------------------- /requirements.in: -------------------------------------------------------------------------------- 1 | cfenv 2 | dj-database-url 3 | Django 4 | django-filter 5 | django-floppyforms 6 | django-form-utils 7 | django-markdown-deux 8 | djangorestframework 9 | djangorestframework-csv 10 | drfdocs 11 | factory_boy 12 | httmock 13 | markdown 14 | newrelic 15 | Pillow 16 | psycopg2 17 | PyJWT 18 | pypandoc 19 | requests 20 | whitenoise 21 | 22 | -e git+https://github.com/18f/acq-templates@develop#egg=acq_templates 23 | -------------------------------------------------------------------------------- /uaa_client/templates/uaa_client/logged_out.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

Logged out

7 | 8 |
9 |

You have successfully logged out.

10 |

Return to the home page.

11 |
12 |
13 |
14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/arrow-down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/minus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/social-icons/svg/facebook25.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /projects/templatetags/document_tags.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | 3 | register = template.Library() 4 | 5 | 6 | @register.filter 7 | def has_document(obj, doc): 8 | return getattr(obj, doc) 9 | 10 | 11 | @register.filter 12 | def title_format(name): 13 | name = name.replace('_', ' ').title() 14 | # If length is very short, it's likely to be an acronym 15 | if len(name) <= 4: 16 | name = name.upper() 17 | return name 18 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/minus-alt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /acquisitions/factories.py: -------------------------------------------------------------------------------- 1 | import factory 2 | from django.contrib.auth.models import User 3 | 4 | 5 | class UserFactory(factory.django.DjangoModelFactory): 6 | class Meta: 7 | model = User 8 | 9 | username = factory.Faker('user_name') 10 | email = factory.Faker('safe_email') 11 | first_name = factory.Faker('first_name') 12 | last_name = factory.Faker('last_name') 13 | is_active = True 14 | is_staff = False 15 | is_superuser = False 16 | -------------------------------------------------------------------------------- /manifest.yml: -------------------------------------------------------------------------------- 1 | applications: 2 | - name: acquisitions 3 | instances: 1 4 | memory: 512M 5 | disk_quota: 1024M 6 | routes: 7 | - route: acquisitions.fr.cloud.gov 8 | services: 9 | - acquisitions-psql 10 | - acquisitions-new-relic 11 | stack: cflinuxfs2 12 | env: 13 | DEBUG: "False" 14 | NEW_RELIC_APP_NAME: "acquisitions.18f.gov (production)" 15 | NEW_RELIC_CONFIG_FILE: "newrelic.ini" 16 | NEW_RELIC_ENV: "production" 17 | NEW_RELIC_LOG: "stdout" 18 | -------------------------------------------------------------------------------- /uaa_client/templates/admin/add_user_form.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/change_form.html" %} 2 | {% load i18n %} 3 | 4 | {# This file is based on https://github.com/django/django/blob/master/django/contrib/admin/templates/admin/auth/user/add_form.html. #} 5 | 6 | {% block form_top %} 7 | {% if not is_popup %} 8 |

First, enter an email address. Then, you'll be able to edit more user options.

9 | {% else %} 10 |

Enter an email address.

11 | {% endif %} 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /news/migrations/0004_auto_20161126_0105.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-11-26 01:05 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('news', '0003_news_authors'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RenameModel( 16 | old_name='News', 17 | new_name='Post', 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /team/migrations/0003_auto_20161029_1649.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.1 on 2016-10-29 16:49 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('team', '0002_teammate_bio'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RenameModel( 16 | old_name='Roles', 17 | new_name='Role', 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /manifest-staging.yml: -------------------------------------------------------------------------------- 1 | applications: 2 | - name: acquisitions-staging 3 | instances: 1 4 | memory: 512M 5 | disk_quota: 1024M 6 | routes: 7 | - route: acquisitions-staging.fr.cloud.gov 8 | services: 9 | - acquisitions-staging-psql 10 | - acquisitions-new-relic 11 | - acquisitions-uaa-creds 12 | stack: cflinuxfs2 13 | env: 14 | NEW_RELIC_APP_NAME: "acquisitions.18f.gov (staging)" 15 | NEW_RELIC_CONFIG_FILE: "newrelic.ini" 16 | NEW_RELIC_ENV: "staging" 17 | NEW_RELIC_LOG: "stdout" 18 | -------------------------------------------------------------------------------- /projects/migrations/0004_remove_buy_locked.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-12 02:17 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0003_auto_20170110_1459'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RemoveField( 16 | model_name='buy', 17 | name='locked', 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /projects/migrations/0024_remove_project_active.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-02-01 19:31 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0023_auto_20170201_1640'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RemoveField( 16 | model_name='project', 17 | name='active', 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /team/migrations/0010_remove_teammate_read_only.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.1 on 2016-11-05 17:43 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('team', '0009_auto_20161031_2306'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RemoveField( 16 | model_name='teammate', 17 | name='read_only', 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /news/migrations/0002_auto_20161125_2020.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-11-25 20:20 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('news', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RenameField( 16 | model_name='news', 17 | old_name='update', 18 | new_name='content', 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /projects/migrations/0007_remove_buy_procurement_method.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-17 18:18 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0006_new_procurement_methods'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RemoveField( 16 | model_name='buy', 17 | name='procurement_method', 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/icon-https.svg: -------------------------------------------------------------------------------- 1 | https icon -------------------------------------------------------------------------------- /web/templates/rest_framework_docs/docs.html: -------------------------------------------------------------------------------- 1 | {% extends "rest_framework_docs/base.html" %} 2 | {% load static from staticfiles %} 3 | 4 | {# {% block style %}#} 5 | 6 | 7 | {# {% endblock %}#} 8 | 9 | {% block github_badge %}{% endblock %} 10 | 11 | {% block logo %} 12 | API Docs 13 | {% endblock %} 14 | 15 | {% block jumbotron %}{% endblock %} 16 | 17 | {% block footer %}{% endblock %} 18 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/correct8.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /team/signals.py: -------------------------------------------------------------------------------- 1 | from django.db.models.signals import post_save 2 | from django.contrib.auth.models import Group 3 | from django.dispatch import receiver 4 | from team.models import Teammate 5 | 6 | 7 | @receiver(post_save, sender=Teammate) 8 | def add_to_teammate_group(sender, instance, created, **kwargs): 9 | try: 10 | group = Group.objects.get(name='Teammates') 11 | except Group.DoesNotExist: 12 | print('Teammates group not yet created') 13 | return 14 | if created: 15 | instance.user.groups.add(group) 16 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/correct9.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/migrations/0020_auto_20170131_0419.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-31 04:19 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0019_auto_20170131_0412'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RenameField( 16 | model_name='buy', 17 | old_name='dollars', 18 | new_name='budget', 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /projects/templates/projects/project.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

{{ project.name }} {% if user.is_staff %}Edit{% endif %}

7 | {% if project.is_private %}
This project is not yet public.
{% endif %} 8 |

Description

9 |
10 | {{ project.description }} 11 |
12 |
13 |
14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /news/migrations/0006_auto_20161128_1656.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-11-28 16:56 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('news', '0005_post_slug'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='post', 17 | name='slug', 18 | field=models.SlugField(blank=True, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /projects/filters.py: -------------------------------------------------------------------------------- 1 | import django_filters 2 | from projects.models import IAA, Project, Buy 3 | 4 | 5 | class BuyFilter(django_filters.rest_framework.FilterSet): 6 | project_id = django_filters.CharFilter(name="project__id") 7 | 8 | class Meta: 9 | model = Buy 10 | fields = ['id', 'name', 'project_id'] 11 | 12 | 13 | class ProjectFilter(django_filters.rest_framework.FilterSet): 14 | iaa_id = django_filters.CharFilter(name="iaa__id") 15 | 16 | class Meta: 17 | model = Project 18 | fields = ['id', 'name', 'iaa_id'] 19 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/angle-arrow-down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/angle-arrow-down-hover.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/angle-arrow-down-primary.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /team/migrations/0002_teammate_bio.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.1 on 2016-10-27 22:41 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('team', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='teammate', 17 | name='bio', 18 | field=models.TextField(blank=True, max_length=1000, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /team/migrations/0005_teammate_read_only.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.1 on 2016-10-31 01:27 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('team', '0004_auto_20161029_1650'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='teammate', 17 | name='read_only', 18 | field=models.BooleanField(default=False), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /team/migrations/0011_auto_20161105_2006.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.1 on 2016-11-05 20:06 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('team', '0010_remove_teammate_read_only'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='teammate', 17 | options={'permissions': (('view_private', 'Can view private team info'),)}, 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/angle-arrow-up-primary.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /news/migrations/0005_post_slug.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-11-28 16:46 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('news', '0004_auto_20161126_0105'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='post', 17 | name='slug', 18 | field=models.SlugField(blank=True, editable=False, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/angle-arrow-down-primary-hover.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/angle-arrow-up-primary-hover.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/migrations/0008_auto_20170117_1819.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-17 18:19 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0007_remove_buy_procurement_method'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RenameField( 16 | model_name='buy', 17 | old_name='procurement_method_link', 18 | new_name='procurement_method', 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /projects/migrations/0016_auto_20170123_1550.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-23 15:50 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0015_auto_20170123_1444'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='iaa', 17 | name='budget', 18 | field=models.DecimalField(decimal_places=2, max_digits=20), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/arrow-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/templates/projects/client.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

{{ client }} {% if user.is_staff %}Edit{% endif %}

7 |

Signed IAAs

8 |
    9 | {% for iaa in client.signed_iaas %} 10 |
  • {{ iaa }}
  • 11 | {% empty %} 12 |
    No signed IAAs yet.
    13 | {% endfor %} 14 |
15 |
16 |
17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /bin/deploy: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | set -e 4 | 5 | API="https://api.fr.cloud.gov" 6 | ORG="gsa-acq-proto" 7 | SPACE=$1 8 | 9 | if [ $# -ne 1 ]; then 10 | echo "Usage: deploy " 11 | exit 12 | fi 13 | 14 | if [ $SPACE = 'production' ]; then 15 | NAME="acquisitions" 16 | MANIFEST="manifest.yml" 17 | elif [ $SPACE = 'staging' ]; then 18 | NAME="acquisitions-staging" 19 | MANIFEST="manifest-staging.yml" 20 | else 21 | echo "Unknown space: $SPACE" 22 | exit 23 | fi 24 | 25 | cf login --a $API --u $CF_USERNAME --p $CF_PASSWORD --o $ORG -s $SPACE 26 | cf zero-downtime-push $NAME -f $MANIFEST 27 | -------------------------------------------------------------------------------- /team/migrations/0009_auto_20161031_2306.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.1 on 2016-10-31 23:06 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('team', '0008_auto_20161031_2304'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='teammate', 17 | name='photo', 18 | field=models.ImageField(default='/team/photos/default.png', upload_to='/team/photos'), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /projects/migrations/0023_auto_20170201_1640.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-02-01 16:40 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0022_auto_20170201_1639'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='buy', 17 | name='github_repository', 18 | field=models.URLField(blank=True, null=True, verbose_name='GitHub repository'), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /team/migrations/0007_teammate_photo.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.1 on 2016-10-31 23:01 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('team', '0006_auto_20161031_0210'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='teammate', 17 | name='photo', 18 | field=models.ImageField(default='/third-party/favicons/favicon-192.png', upload_to='/team/photos'), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /team/migrations/0008_auto_20161031_2304.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.1 on 2016-10-31 23:04 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('team', '0007_teammate_photo'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='teammate', 17 | name='photo', 18 | field=models.ImageField(default='third-party/favicons/favicon-192.png', upload_to='/team/photos'), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /nda/templates/nda/nda.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | {% load floppyforms %} 3 | {% load markdown_deux_tags %} 4 | 5 | {% block content %} 6 |
7 |
8 | {% markdown %} 9 | {% include "nda/markdown/nda.md" %} 10 | {% endmarkdown %} 11 |
12 | {% csrf_token %} 13 | {% form nda_form using %} 14 | {% formfield form.agree %} 15 | 16 | {% endform %} 17 |

18 |
19 |
20 |
21 | {% endblock %} 22 | -------------------------------------------------------------------------------- /projects/tests/test_admin_views.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from django.shortcuts import reverse 3 | from acquisitions.factories import UserFactory 4 | # from projects.views import financials 5 | from projects.factories import IAAFactory 6 | 7 | 8 | class TestFinancialView: 9 | @pytest.mark.django_db 10 | def test_displays_iaas(self, client): 11 | user = UserFactory(is_staff=True) 12 | client.force_login(user) 13 | iaa = IAAFactory.create() 14 | response = client.get(reverse('financials')) 15 | assert response.status_code == 200 16 | assert str.encode(iaa.client.name) in response.content 17 | -------------------------------------------------------------------------------- /news/management/commands/create_content.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | from django.core.management.base import BaseCommand, CommandError 3 | from news.factories import NewsFactory 4 | 5 | 6 | class Command(BaseCommand): 7 | help = 'Create some content' 8 | 9 | def add_arguments(self, parser): 10 | parser.add_argument( 11 | '-n', '--number', 12 | action='store', 13 | default=5, 14 | help='The amount of content to create' 15 | ) 16 | 17 | def handle(self, *args, **options): 18 | number = int(options['number']) 19 | 20 | NewsFactory.create_batch(number) 21 | -------------------------------------------------------------------------------- /nda/templates/nda/buy_nda.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | {% load floppyforms %} 3 | {% load markdown_deux_tags %} 4 | 5 | {% block content %} 6 |
7 |
8 | {% markdown %} 9 | {% include "nda/markdown/buy_nda.md" %} 10 | {% endmarkdown %} 11 |
12 | {% csrf_token %} 13 | {% form nda_form using %} 14 | {% formfield form.agree %} 15 | 16 | {% endform %} 17 |

18 |
19 |
20 |
21 | {% endblock %} 22 | -------------------------------------------------------------------------------- /projects/tests/test_iaa_model.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from datetime import date, timedelta 3 | from projects.factories import ( 4 | IAAFactory, 5 | ) 6 | 7 | 8 | @pytest.mark.django_db 9 | def test_active(): 10 | iaa = IAAFactory() 11 | iaa.performance_begins = date.today() - timedelta(days=1) 12 | iaa.performance_ends = date.today() + timedelta(days=1) 13 | assert iaa.active() 14 | 15 | 16 | @pytest.mark.django_db 17 | def test_inactive(): 18 | iaa = IAAFactory() 19 | iaa.performance_begins = date.today() - timedelta(days=10) 20 | iaa.performance_ends = date.today() - timedelta(days=5) 21 | assert not iaa.active() 22 | -------------------------------------------------------------------------------- /uaa_client/templates/uaa_client/oauth2_error.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

Login Error

7 | {% if error_code == 'invalid_code_or_nonexistent_user' %} 8 |

9 | Either you don't have permission to log in to this system, or 10 | an error occurred when trying to log you in. 11 |

12 | {% else %} 13 |

Unfortunately, an error occurred when trying to log you in.

14 |

Error code: {{ error_code }}

15 | {% endif %} 16 |
17 |
18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /team/factories.py: -------------------------------------------------------------------------------- 1 | import factory 2 | from team.models import Teammate, Role 3 | from acquisitions.factories import UserFactory 4 | 5 | 6 | class RoleFactory(factory.django.DjangoModelFactory): 7 | class Meta: 8 | model = Role 9 | 10 | name = factory.Faker('job') 11 | 12 | 13 | class TeammateFactory(factory.django.DjangoModelFactory): 14 | class Meta: 15 | model = Teammate 16 | 17 | user = factory.SubFactory(UserFactory) 18 | name = factory.Faker('name') 19 | bio = factory.Faker('paragraphs') 20 | github = factory.Faker('user_name') 21 | slack = factory.Faker('user_name') 22 | role = factory.SubFactory(RoleFactory) 23 | -------------------------------------------------------------------------------- /team/migrations/0002_auto_20161208_1623.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-12-08 16:23 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('team', '0001_squashed_0011_auto_20161105_2006'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='teammate', 18 | name='role', 19 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='team.Role'), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/icon-dot-gov.svg: -------------------------------------------------------------------------------- 1 | dot gov icon -------------------------------------------------------------------------------- /projects/fields.py: -------------------------------------------------------------------------------- 1 | from django.db.models.fields import TextField 2 | 3 | 4 | class DocumentField(TextField): 5 | 6 | description = "A field for storing a document and marking it as public or " 7 | "private" 8 | 9 | def __init__(self, *args, **kwargs): 10 | public = kwargs.pop('public', None) 11 | public_after = kwargs.pop('public_after', None) 12 | if public_after is not None: 13 | self.public_after = public_after 14 | self.public = None 15 | elif public is not None: 16 | self.public_after = None 17 | self.public = public 18 | super(DocumentField, self).__init__(*args, **kwargs) 19 | -------------------------------------------------------------------------------- /projects/migrations/0018_auto_20170131_0411.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-31 04:11 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('projects', '0017_auto_20170123_1652'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='project', 18 | name='iaa', 19 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='projects.IAA', verbose_name='IAA'), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /news/migrations/0003_news_authors.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-11-26 00:23 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 13 | ('news', '0002_auto_20161125_2020'), 14 | ] 15 | 16 | operations = [ 17 | migrations.AddField( 18 | model_name='news', 19 | name='authors', 20 | field=models.ManyToManyField(to=settings.AUTH_USER_MODEL), 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /projects/migrations/0021_auto_20170131_0428.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-31 04:28 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0020_auto_20170131_0419'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='buy', 17 | name='contract_type', 18 | field=models.CharField(blank=True, choices=[('Labor Hours', 'Labor Hours'), ('Time and Materials', 'Time and Materials'), ('Firm Fixed Price', 'Firm Fixed Price')], max_length=200, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /projects/migrations/0009_procurementmethod_short_name.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-17 22:33 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0008_auto_20170117_1819'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='procurementmethod', 17 | name='short_name', 18 | field=models.CharField(default='agile_bpa', help_text='This should correspond to the folder name used for this procurment method in the templates.', max_length=30), 19 | preserve_default=False, 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /web/templates/web/guides.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 | 15 |
16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/plus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/templates/projects/iaa.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

{{ iaa.client }} {% if user.is_staff %}Edit{% endif %}

7 | {% if not iaa.is_signed %}
This IAA is not yet signed.
8 | {% else %} 9 |

Signed On

10 |
11 | {{ iaa.signed_on }} 12 |
13 |

Expires On

14 |
15 | {{ iaa.expires_on }} 16 |
17 | {% endif %} 18 |

Value

19 |
20 | $ {{ iaa.budget | floatformat:2 }} 21 |
22 |
23 |
24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /opencontrol.yaml: -------------------------------------------------------------------------------- 1 | schema_version: "1.0.0" 2 | name: acquisitions.18f.gov 3 | metadata: 4 | description: > 5 | acquisitions.18f.gov is a homepage for the TTS Office of Acquisitions, as 6 | well as a collection of tools to help members of the office perform their 7 | functions and share information of interest to the public. 8 | maintainers: 9 | - steven.reilly@gsa.gov 10 | components: 11 | - ./compliance 12 | certifications: 13 | # paths 14 | standards: 15 | # paths 16 | dependencies: 17 | certifications: 18 | # LATO 19 | - url: https://github.com/18F/GSA-Certifications 20 | revision: master 21 | systems: 22 | # Cloud.gov 23 | - url: https://github.com/18F/cg-compliance 24 | revision: master 25 | standards: 26 | # data 27 | -------------------------------------------------------------------------------- /projects/migrations/0013_auto_20170123_0350.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-23 03:50 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0012_auto_20170123_0145'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RemoveField( 16 | model_name='agency', 17 | name='component_tas_number', 18 | ), 19 | migrations.AddField( 20 | model_name='agency', 21 | name='treasury_account_symbol', 22 | field=models.CharField(default='2015X213', max_length=8), 23 | preserve_default=False, 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /team/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import include, url 2 | from team import views 3 | from rest_framework.urlpatterns import format_suffix_patterns 4 | 5 | api_patterns = [ 6 | url(r'^team/$', views.TeammateList.as_view(), name='team-list'), 7 | url( 8 | r'^team/(?P[0-9]+)', 9 | views.TeammateDetail.as_view(), 10 | name='team-detail', 11 | ), 12 | url(r'^roles/$', views.RoleList.as_view(), name='role-list'), 13 | url( 14 | r'^roles/(?P[0-9]+)', 15 | views.RoleDetail.as_view(), 16 | name='role-detail', 17 | ), 18 | ] 19 | 20 | urlpatterns = [ 21 | url(r'^$', views.home, name='home'), 22 | url(r'(?P\w+)', views.teammate), 23 | ] 24 | 25 | api_patterns = format_suffix_patterns(api_patterns) 26 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/plus-alt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /news/factories.py: -------------------------------------------------------------------------------- 1 | import factory 2 | from datetime import datetime, timedelta, tzinfo 3 | from dateutil.tz import tzlocal 4 | from acquisitions.factories import UserFactory 5 | from news.models import Post 6 | 7 | 8 | class NewsFactory(factory.django.DjangoModelFactory): 9 | class Meta: 10 | model = Post 11 | 12 | title = factory.Faker('catch_phrase') 13 | slug = factory.Faker('slug') 14 | content = factory.Faker('paragraph') 15 | authors = factory.RelatedFactory(UserFactory) 16 | publication_date = factory.Faker( 17 | 'date_time_between_dates', 18 | datetime_start=datetime.now() - timedelta(days=5), 19 | datetime_end=datetime.now() + timedelta(days=5), 20 | tzinfo=tzlocal(), 21 | ) 22 | draft = False 23 | -------------------------------------------------------------------------------- /team/migrations/0004_auto_20161029_1650.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.1 on 2016-10-29 16:50 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('team', '0003_auto_20161029_1649'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='teammate', 17 | name='github', 18 | field=models.CharField(blank=True, max_length=100, null=True), 19 | ), 20 | migrations.AlterField( 21 | model_name='teammate', 22 | name='slack', 23 | field=models.CharField(blank=True, max_length=100, null=True), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /news/feeds.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from dateutil.tz import tzlocal 3 | from django.contrib.syndication.views import Feed 4 | from django.urls import reverse 5 | from news.models import Post 6 | 7 | 8 | class LatestPosts(Feed): 9 | title = "TTS Office of Acquisitions Updates" 10 | link = "/news/" 11 | description = "Updates from the TTS Office of Acquisitions team about "\ 12 | "experiments, buys, events, and more" 13 | 14 | def items(self): 15 | return Post.objects.filter( 16 | draft=False, 17 | publication_date__lte=datetime.now(tzlocal()), 18 | ).order_by('publication_date')[:20] 19 | 20 | def item_title(self, item): 21 | return item.title 22 | 23 | def item_description(self, item): 24 | return item.content 25 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | migration: 4 | build: . 5 | image: app 6 | volumes: 7 | - .:/app 8 | links: 9 | - db 10 | environment: 11 | DATABASE_URL: "postgres://postgres@db/acquisitions" 12 | command: ./wait-for-it.sh -s -q -t 0 db:5432 -- ./manage.py migrate 13 | 14 | web: 15 | image: app 16 | volumes: 17 | - .:/app 18 | ports: 19 | - "8000:8000" 20 | links: 21 | - db 22 | depends_on: 23 | - migration 24 | environment: 25 | DATABASE_URL: "postgres://postgres@db/acquisitions" 26 | command: ./wait-for-it.sh -s -q -t 0 db:5432 -- ./manage.py runserver 0.0.0.0:8000 27 | 28 | db: 29 | image: postgres 30 | expose: 31 | - "5432" 32 | environment: 33 | POSTGRES_DB: "acquisitions" 34 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /team/migrations/0006_auto_20161031_0210.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.1 on 2016-10-31 02:10 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('team', '0005_teammate_read_only'), 13 | ] 14 | 15 | operations = [ 16 | migrations.RenameField( 17 | model_name='role', 18 | old_name='title', 19 | new_name='name', 20 | ), 21 | migrations.AddField( 22 | model_name='teammate', 23 | name='role', 24 | field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='team.Role'), 25 | preserve_default=False, 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /nda/tests/test_buy_nda.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from django.contrib.auth.models import User, Group 3 | from projects.factories import BuyFactory 4 | from acquisitions.factories import UserFactory 5 | 6 | 7 | class TestBuyNDA: 8 | @pytest.fixture 9 | @pytest.mark.django_db 10 | def user(self): 11 | user = UserFactory() 12 | group = Group.objects.create(name='NDA Signed') 13 | user.groups.add(group) 14 | return user 15 | 16 | @pytest.fixture 17 | @pytest.mark.django_db 18 | def buy(self): 19 | buy = BuyFactory() 20 | return buy 21 | 22 | @pytest.mark.django_db 23 | def test_signing_nda(self, user, buy): 24 | buy.technical_evaluation_panel.add(user) 25 | assert buy.all_nda_signed() is False 26 | buy.nda_signed.add(user) 27 | assert buy.all_nda_signed() is True 28 | -------------------------------------------------------------------------------- /projects/templates/projects/edit_client.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |
7 | {% csrf_token %} 8 | {{ form.non_field_errors }} 9 |
10 | {{ form.name.errors }} 11 | {{ form.name.label_tag }} 12 | {{ form.name }} 13 |
14 |
15 | {{ form.agency.errors }} 16 | {{ form.agency.label_tag }} 17 | {{ form.agency }} 18 |
19 |
20 | {{ form.address.errors }} 21 | {{ form.address.label_tag }} 22 | {{ form.address }} 23 |
24 | 25 |
26 |
27 |
28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /news/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-11-25 20:13 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='News', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('title', models.CharField(max_length=100)), 21 | ('update', models.TextField()), 22 | ('publication_date', models.DateTimeField(blank=True, null=True)), 23 | ('draft', models.BooleanField(default=True)), 24 | ], 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /projects/migrations/0006_new_procurement_methods.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-17 17:54 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | def link_procurement_methods(apps, schema_editor): 8 | Buy = apps.get_model('projects', 'Buy') 9 | ProcurementMethod = apps.get_model('projects', 'ProcurementMethod') 10 | for buy in Buy.objects.all(): 11 | pm, created = ProcurementMethod.objects.get_or_create( 12 | name=buy.get_procurement_method_display 13 | ) 14 | buy.procurement_method_link = pm 15 | buy.save() 16 | 17 | class Migration(migrations.Migration): 18 | 19 | dependencies = [ 20 | ('projects', '0005_auto_20170117_1752'), 21 | ] 22 | 23 | operations = [ 24 | migrations.RunPython(link_procurement_methods) 25 | ] 26 | -------------------------------------------------------------------------------- /projects/migrations/0019_auto_20170131_0412.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-31 04:12 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0018_auto_20170131_0411'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='project', 17 | name='cogs_amount', 18 | field=models.DecimalField(decimal_places=2, max_digits=20, verbose_name='Cost of Goods Sold (COGS)'), 19 | ), 20 | migrations.AlterField( 21 | model_name='project', 22 | name='non_cogs_amount', 23 | field=models.DecimalField(decimal_places=2, max_digits=20, verbose_name='Cost of Team Labor (non-COGS)'), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /projects/migrations/0003_auto_20170110_1459.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-10 14:59 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0002_auto_20170109_1724'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='buy', 17 | name='award_date', 18 | field=models.DateTimeField(blank=True, null=True), 19 | ), 20 | migrations.AlterField( 21 | model_name='buy', 22 | name='delivery_date', 23 | field=models.DateTimeField(blank=True, null=True), 24 | ), 25 | migrations.AlterField( 26 | model_name='buy', 27 | name='issue_date', 28 | field=models.DateTimeField(blank=True, null=True), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /team/templates/team/teammate.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

{{ teammate.name }}

7 |
8 |

9 |
10 |
11 |
12 | 26 | {% endblock %} 27 | -------------------------------------------------------------------------------- /nda/templates/nda/markdown/nda.md: -------------------------------------------------------------------------------- 1 | Non-Disclosure Agreement for TTS Office of Acquisitions 2 | ======================================================= 3 | 4 | I, {{ user.get_full_name }}, do solemnly swear (or affirm) that I will not 5 | knowingly disclose procurement-sensitive information for potential or active 6 | procurements to any unauthorized person for any purpose. 7 | 8 | I understand that authorized persons refers only to others who have signed a 9 | non-disclosure certification, and who are also included in the disclosure 10 | prohibition. 11 | 12 | I am aware that the unauthorized use or disclosure of information may be a 13 | violation of law (41 U.S.C. 423 as amended, or 18 U.S.C. 1905 as amended), 14 | executive order, or regulation (Federal Acquisition Regulation, Part 3 - 15 | Improper Business Practices and Personal Conflicts of Interest, and subject to 16 | criminal, or civil penalties punishable by fine, imprisonment, or both, or 17 | administrative remedies. 18 | -------------------------------------------------------------------------------- /projects/migrations/0022_auto_20170201_1639.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-02-01 16:39 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0021_auto_20170131_0428'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='buy', 17 | name='planned_award_date', 18 | field=models.DateTimeField(blank=True, null=True), 19 | ), 20 | migrations.AddField( 21 | model_name='buy', 22 | name='planned_delivery_date', 23 | field=models.DateTimeField(blank=True, null=True), 24 | ), 25 | migrations.AddField( 26 | model_name='buy', 27 | name='planned_issue_date', 28 | field=models.DateTimeField(blank=True, null=True), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /nda/views.py: -------------------------------------------------------------------------------- 1 | import os 2 | from django.shortcuts import render 3 | from django.shortcuts import redirect 4 | from django.http import Http404 5 | from django.contrib.auth.decorators import login_required 6 | from django.contrib.auth.models import Group 7 | from nda.forms import NDAForm 8 | 9 | 10 | # Create your views here. 11 | @login_required 12 | def sign_nda(request): 13 | try: 14 | group = Group.objects.get(name='NDA Signed') 15 | except Group.DoesNotExist: 16 | print('NDA Signed group not yet created') 17 | raise Http404 18 | try: 19 | request.user.groups.get(id=group.id) 20 | return render(request, 'nda/already-signed.html') 21 | except Group.DoesNotExist: 22 | pass 23 | nda_form = NDAForm(request.POST or None) 24 | if nda_form.is_valid(): 25 | request.user.groups.add(group) 26 | return render(request, 'nda/success.html') 27 | return render(request, 'nda/nda.html', { 28 | 'nda_form': nda_form 29 | }) 30 | -------------------------------------------------------------------------------- /projects/management/commands/create_buys.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | from django.core.management.base import BaseCommand, CommandError 3 | from projects.factories import ( 4 | BuyFactory, 5 | AddBuyFactory, 6 | ) 7 | 8 | 9 | class Command(BaseCommand): 10 | help = 'Create some buys' 11 | 12 | def add_arguments(self, parser): 13 | parser.add_argument( 14 | '-a', '--add', 15 | action='store_true', 16 | default=False, 17 | help='Add to existing projects instead of creating new ones' 18 | ) 19 | parser.add_argument( 20 | '-n', '--number', 21 | action='store', 22 | default=5, 23 | help='The number of buys to create' 24 | ) 25 | 26 | def handle(self, *args, **options): 27 | number = int(options['number']) 28 | 29 | if options['add']: 30 | AddBuyFactory.create_batch(number) 31 | else: 32 | BuyFactory.create_batch(number) 33 | -------------------------------------------------------------------------------- /team/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from team.models import Teammate, Role 3 | 4 | 5 | class TeammateSerializer(serializers.HyperlinkedModelSerializer): 6 | role = serializers.CharField(source='role.name') 7 | 8 | class Meta: 9 | model = Teammate 10 | fields = ( 11 | 'name', 12 | 'role', 13 | 'photo', 14 | ) 15 | 16 | 17 | class TeammatePlusSerializer(serializers.HyperlinkedModelSerializer): 18 | role = serializers.CharField(source='role.name') 19 | email = serializers.EmailField(source='user.email') 20 | 21 | class Meta: 22 | model = Teammate 23 | fields = ( 24 | 'name', 25 | 'role', 26 | 'photo', 27 | 'github', 28 | 'slack', 29 | 'email', 30 | ) 31 | 32 | 33 | class RoleSerializer(serializers.HyperlinkedModelSerializer): 34 | class Meta: 35 | model = Role 36 | fields = ('name',) 37 | -------------------------------------------------------------------------------- /projects/migrations/0012_auto_20170123_0145.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-23 01:45 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0011_auto_20170118_1449'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RemoveField( 16 | model_name='agency', 17 | name='business_type_event_code', 18 | ), 19 | migrations.AddField( 20 | model_name='agency', 21 | name='business_event_type_code', 22 | field=models.CharField(default='abcd1234', help_text='An 8-character alphanumeric code indicating the type of activity (e.g. payments, collections, investments) taking place. For more information, see https://www.fiscal.treasury.gov/fsservices/gov/acctg/cars/factsheet_betc.htm', max_length=8), 23 | preserve_default=False, 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /web/templates/web/profile.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

{{ user }}

7 |
8 |

API Token

9 | {% if user.auth_token %} 10 |
11 | Token: {{ user.auth_token }} 12 |
13 | Refresh token 14 | {% else %} 15 |
16 | No API Token 17 |
18 | Get a token 19 | {% endif %} 20 |
21 |
22 |

Non-Disclosure Agreement

23 |
24 | {% if perms.projects.view_project %} 25 | You've signed the NDA. 26 | {% else %} 27 | Sign the NDA 28 | {% endif %} 29 |
30 |
31 |
32 |
33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /projects/migrations/0025_auto_20170201_2018.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-02-01 20:18 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0024_remove_project_active'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='buy', 17 | name='public', 18 | field=models.BooleanField(default=False, help_text='Whether this buy will be displayed to people outside of the TTS Office of Acquisitions. It\'s likely that a buy should become public (as "Planning") before it is issued.'), 19 | ), 20 | migrations.AlterField( 21 | model_name='project', 22 | name='public', 23 | field=models.BooleanField(default=False, help_text='Whether this project will be displayed to people outside of the TTS Office of Acquisitions. A project must be public for buys within it to also be public.'), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/search-alt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/tests/test_projects_model.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from projects.factories import IAAFactory, ProjectFactory, BuyFactory 3 | 4 | 5 | class TestProjectsModel: 6 | @pytest.mark.django_db 7 | def test_budget(self): 8 | project = ProjectFactory.create( 9 | cogs_amount=75, 10 | non_cogs_amount=25, 11 | ) 12 | assert project.budget() == 100 13 | 14 | @pytest.mark.django_db 15 | def test_budget_remaining(self): 16 | project = ProjectFactory.create(non_cogs_amount=200, cogs_amount=0) 17 | buy = BuyFactory.create(budget=50, project=project) 18 | assert project.budget_remaining() == 150 19 | buy2 = BuyFactory.create(budget=50, project=project) 20 | assert project.budget_remaining() == 100 21 | 22 | @pytest.mark.django_db 23 | def test_budget_remaining_clean(self): 24 | project = ProjectFactory.create(non_cogs_amount=200) 25 | buy = BuyFactory.create( 26 | budget=150, 27 | project=project, 28 | public=project.public 29 | ) 30 | buy.full_clean() 31 | -------------------------------------------------------------------------------- /projects/migrations/0017_auto_20170123_1652.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-23 16:52 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0016_auto_20170123_1550'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='buy', 17 | name='dollars', 18 | field=models.DecimalField(decimal_places=2, default=500, max_digits=20), 19 | preserve_default=False, 20 | ), 21 | migrations.AlterField( 22 | model_name='project', 23 | name='cogs_amount', 24 | field=models.DecimalField(decimal_places=2, max_digits=20, verbose_name='Cost of Goods Sold'), 25 | ), 26 | migrations.AlterField( 27 | model_name='project', 28 | name='non_cogs_amount', 29 | field=models.DecimalField(decimal_places=2, max_digits=20, verbose_name='Cost of Team Labor'), 30 | ), 31 | ] 32 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/social-icons/svg/twitter16.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /team/models.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.db import models 4 | from django.contrib.auth.models import User 5 | 6 | 7 | # Create your models here. 8 | class Role(models.Model): 9 | name = models.CharField(max_length=100) 10 | 11 | def __str__(self): 12 | return self.name 13 | 14 | 15 | class Teammate(models.Model): 16 | user = models.OneToOneField(User, on_delete=models.CASCADE) 17 | name = models.CharField(max_length=100, blank=False, null=False) 18 | bio = models.TextField(max_length=1000, blank=True, null=True) 19 | github = models.CharField(max_length=100, blank=True, null=True) 20 | slack = models.CharField(max_length=100, blank=True, null=True) 21 | role = models.ForeignKey(Role) 22 | photo = models.ImageField( 23 | upload_to='/team/photos', 24 | default='/team/photos/default.png' 25 | ) 26 | 27 | def __str__(self): 28 | return self.name 29 | 30 | def is_teammate(self): 31 | return True 32 | 33 | class Meta: 34 | permissions = ( 35 | ('view_private', 'Can view private team info'), 36 | ) 37 | -------------------------------------------------------------------------------- /projects/tests/test_form.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from projects.forms import CreateBuyForm, EditBuyForm 3 | from projects.factories import ( 4 | ProjectFactory, 5 | BuyFactory, 6 | ProcurementMethodFactory, 7 | ) 8 | 9 | 10 | @pytest.mark.django_db 11 | def test_create_buy_form(): 12 | project = ProjectFactory.create() 13 | procurement_method = ProcurementMethodFactory.create() 14 | data = { 15 | "name": "New Buy", 16 | "description": "This is a new buy for things", 17 | "budget": 50, 18 | "project": project.id, 19 | "procurement_method": procurement_method.id 20 | } 21 | form = CreateBuyForm(data) 22 | assert form.is_valid(), form.errors 23 | 24 | 25 | @pytest.mark.django_db 26 | def test_edit_buy_form(): 27 | buy = BuyFactory.create() 28 | data = { 29 | "name": buy.name, 30 | "description": buy.description, 31 | "budget": buy.budget, 32 | "project": buy.project.id, 33 | "procurement_method": buy.procurement_method, 34 | "qasp": "something new" 35 | } 36 | form = EditBuyForm(instance=buy) 37 | # assert form.is_valid(), form.errors 38 | # assert buy.qasp == "something new" 39 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/alerts/success.svg: -------------------------------------------------------------------------------- 1 | 3 | 12 | 13 | -------------------------------------------------------------------------------- /projects/migrations/0010_auto_20170117_2357.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-17 23:57 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0009_procurementmethod_short_name'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RemoveField( 16 | model_name='iaa', 17 | name='dollars', 18 | ), 19 | migrations.AddField( 20 | model_name='iaa', 21 | name='cogs_amount', 22 | field=models.IntegerField(blank=True, null=True, verbose_name='Cost of Goods Sold'), 23 | ), 24 | migrations.AddField( 25 | model_name='iaa', 26 | name='non_cogs_amount', 27 | field=models.IntegerField(blank=True, null=True, verbose_name='Cost of Team Labor'), 28 | ), 29 | migrations.AlterField( 30 | model_name='iaa', 31 | name='authority', 32 | field=models.CharField(blank=True, choices=[('asf', 'Acquisition Services Fund'), ('economy', 'Economy Act')], max_length=100, null=True), 33 | ), 34 | ] 35 | -------------------------------------------------------------------------------- /projects/templates/projects/financials.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | {% load humanize %} 3 | 4 | {% block content %} 5 |
6 |
7 |

Financials Overview

8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
Total Budgeted${{ totals.budgeted|intcomma }}
Total Allocated${{ totals.allocated|intcomma }}
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {% for doc in docs %} 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | {% endfor %} 38 | 39 |
ClientTotalAllocatedCOGSNon-COGS
{{ doc.client }}${{ doc.budget|intcomma }}${{ doc.allocated|intcomma }}${{ doc.total_cogs|intcomma }}${{ doc.total_non_cogs|intcomma }}
40 |
41 |
42 | {% endblock %} 43 | -------------------------------------------------------------------------------- /acquisitions/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for acquisitions 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/1.8/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | import newrelic.agent 12 | from cfenv import AppEnv 13 | 14 | env = AppEnv() 15 | 16 | from django.core.wsgi import get_wsgi_application 17 | 18 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "acquisitions.settings") 19 | 20 | # Initialize New Relic monitoring if on Cloud Foundry 21 | new_relic = env.get_service(name='acquisitions-new-relic') 22 | if new_relic is not None: 23 | new_relic_license = new_relic.credentials['NEW_RELIC_LICENSE_KEY'] 24 | new_relic_app_name = os.environ.get('NEW_RELIC_APP_NAME') 25 | if new_relic_license and new_relic_app_name: 26 | new_relic_settings = newrelic.agent.global_settings() 27 | new_relic_settings.license_key = new_relic_license 28 | new_relic_settings.app_name = new_relic_app_name 29 | newrelic.agent.initialize() 30 | 31 | # Whitenoise import must come after settings are loaded 32 | from whitenoise.django import DjangoWhiteNoise 33 | 34 | application = get_wsgi_application() 35 | application = DjangoWhiteNoise(application) 36 | -------------------------------------------------------------------------------- /web/templates/web/index.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |
7 |

Agile Delivery Services BPA: Making Procurements Joyful

8 | {# Current BPA orders#} 9 | See current task orders 10 |
11 |
12 |
13 |
14 |
15 |

The Latest

16 | {% for post in posts %} 17 |

{{ post.title }}

18 |

19 | Posted on {{ post.publication_date }}
by {% for author in post.authors.all %} 20 | {{ author.get_full_name }}{% if not forloop.last %}, {% endif %} 21 | {% endfor %}
22 |

23 |
24 | {{ post.content }} 25 |

Permalink

26 |
27 | {% empty %} 28 |

No updates yet, but stay tuned!

29 | {% endfor %} 30 |
31 |
32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Welcome! 2 | 3 | We're so glad you're thinking about contributing to an 18F open source project! If you're unsure about anything, just ask -- or submit the issue or pull request anyway. The worst that can happen is you'll be politely asked to change something. We love all friendly contributions. 4 | 5 | We want to ensure a welcoming environment for all of our projects. Our staff follow the [18F Code of Conduct](https://github.com/18F/code-of-conduct/blob/master/code-of-conduct.md) and all contributors should do the same. 6 | 7 | We encourage you to read this project's CONTRIBUTING policy (you are here), its [LICENSE](LICENSE.md), and its [README](README.md). 8 | 9 | If you have any questions or want to read more, check out the [18F Open Source Policy GitHub repository](https://github.com/18f/open-source-policy), or just [shoot us an email](mailto:18f@gsa.gov). 10 | 11 | ## Public domain 12 | 13 | This project is in the public domain within the United States, and 14 | copyright and related rights in the work worldwide are waived through 15 | the [CC0 1.0 Universal public domain dedication](https://creativecommons.org/publicdomain/zero/1.0/). 16 | 17 | All contributions to this project will be released under the CC0 18 | dedication. By submitting a pull request, you are agreeing to comply 19 | with this waiver of copyright interest. 20 | -------------------------------------------------------------------------------- /projects/widgets.py: -------------------------------------------------------------------------------- 1 | from datetime import timedelta 2 | from django.forms import widgets 3 | from django import forms 4 | 5 | 6 | class DurationMultiWidget(widgets.MultiWidget): 7 | def __init__(self, attrs=None): 8 | # Create duration options 9 | DURATIONS = ( 10 | ('days', 'days'), 11 | ('weeks', 'weeks'), 12 | ) 13 | _widgets = ( 14 | widgets.NumberInput(attrs=attrs), 15 | widgets.Select(attrs=attrs, choices=DURATIONS), 16 | ) 17 | super(DurationMultiWidget, self).__init__(_widgets, attrs) 18 | 19 | def decompress(self, value): 20 | if value: 21 | return value.split(' ') 22 | else: 23 | return '' 24 | 25 | def format_output(self, rendered_widgets): 26 | return ''.join(rendered_widgets) 27 | 28 | def value_from_datadict(self, data, files, name): 29 | length = [ 30 | widget.value_from_datadict(data, files, name + '_%s' % i) 31 | for i, widget in enumerate(self.widgets)] 32 | try: 33 | if length[0] is not '': 34 | length = '{0} {1}'.format(length[0], length[1]) 35 | else: 36 | raise ValueError 37 | except ValueError: 38 | return None 39 | else: 40 | return length 41 | -------------------------------------------------------------------------------- /projects/tests/test_private_buys.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import Permission, User 2 | from django.contrib.contenttypes.models import ContentType 3 | from django.test import TestCase, Client 4 | from django.shortcuts import reverse 5 | from projects.models import Buy, Project 6 | from projects.factories import BuyFactory 7 | from acquisitions.factories import UserFactory 8 | 9 | 10 | class TestPrivateBuys(TestCase): 11 | def setUp(self): 12 | self.buy = BuyFactory.create(public=False) 13 | self.user = UserFactory.create() 14 | self.client = Client() 15 | 16 | def test_with_permission(self): 17 | content_type = ContentType.objects.get_for_model(Project) 18 | permission = Permission.objects.get( 19 | codename='view_project', 20 | content_type=content_type, 21 | ) 22 | self.user.user_permissions.add(permission) 23 | self.client.force_login(self.user) 24 | print(reverse('buys:buy', args=[self.buy.id])) 25 | response = self.client.get(reverse('buys:buy', args=[self.buy.id])) 26 | self.assertTemplateUsed(response, 'projects/buy.html') 27 | 28 | def test_without_permission(self): 29 | response = self.client.get(reverse('buys:buy', args=[self.buy.id])) 30 | self.assertTemplateUsed(response, 'projects/private-page.html') 31 | -------------------------------------------------------------------------------- /projects/tests/test_private_projects.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import Permission, User 2 | from django.contrib.contenttypes.models import ContentType 3 | from django.test import TestCase, Client 4 | from django.shortcuts import reverse 5 | from projects.models import Buy, Project 6 | from projects.factories import BuyFactory, ProjectFactory 7 | from acquisitions.factories import UserFactory 8 | 9 | 10 | class TestPrivateProjects(TestCase): 11 | def setUp(self): 12 | self.project = ProjectFactory.create(public=False) 13 | self.user = UserFactory.create() 14 | self.client = Client() 15 | 16 | def test_with_permission(self): 17 | content_type = ContentType.objects.get_for_model(Project) 18 | permission = Permission.objects.get( 19 | codename='view_project', 20 | content_type=content_type, 21 | ) 22 | self.user.user_permissions.add(permission) 23 | self.client.force_login(self.user) 24 | response = self.client.get(reverse('projects:project', args=[self.project.id])) 25 | self.assertTemplateUsed(response, 'projects/project.html') 26 | 27 | def test_without_permission(self): 28 | response = self.client.get(reverse('projects:project', args=[self.project.id])) 29 | self.assertTemplateUsed(response, 'projects/private-page.html') 30 | -------------------------------------------------------------------------------- /news/views.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from dateutil.tz import tzlocal 3 | from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 4 | from django.shortcuts import render 5 | from django.shortcuts import get_object_or_404 6 | from news.models import Post 7 | 8 | 9 | # Create your views here. 10 | def posts(request): 11 | post_list = Post.objects.filter( 12 | draft=False, 13 | publication_date__lte=datetime.now(tzlocal()) 14 | ).order_by('publication_date') 15 | # Pagination: https://docs.djangoproject.com/en/1.10/topics/pagination/ 16 | paginator = Paginator(post_list, 10) 17 | page = request.GET.get('page') 18 | try: 19 | posts = paginator.page(page) 20 | except PageNotAnInteger: 21 | # If page is not an integer, deliver first page. 22 | posts = paginator.page(1) 23 | except EmptyPage: 24 | # If page is out of range (e.g. 9999), deliver last page of results. 25 | posts = paginator.page(paginator.num_pages) 26 | 27 | return render(request, "news/posts.html", {"posts": posts}) 28 | 29 | 30 | def post(request, slug): 31 | post = get_object_or_404( 32 | Post, 33 | slug=slug, 34 | draft=False, 35 | publication_date__lte=datetime.now(tzlocal()), 36 | ) 37 | return render(request, "news/post.html", {'post': post}) 38 | -------------------------------------------------------------------------------- /news/migrations/0001_squashed_0006_auto_20161128_1656.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-12-08 15:04 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | replaces = [('news', '0001_initial'), ('news', '0002_auto_20161125_2020'), ('news', '0003_news_authors'), ('news', '0004_auto_20161126_0105'), ('news', '0005_post_slug'), ('news', '0006_auto_20161128_1656')] 12 | 13 | initial = True 14 | 15 | dependencies = [ 16 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 17 | ] 18 | 19 | operations = [ 20 | migrations.CreateModel( 21 | name='Post', 22 | fields=[ 23 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 24 | ('title', models.CharField(max_length=100)), 25 | ('content', models.TextField()), 26 | ('publication_date', models.DateTimeField(blank=True, null=True)), 27 | ('draft', models.BooleanField(default=True)), 28 | ('authors', models.ManyToManyField(to=settings.AUTH_USER_MODEL)), 29 | ('slug', models.SlugField(blank=True, null=True)), 30 | ], 31 | ), 32 | ] 33 | -------------------------------------------------------------------------------- /team/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.1 on 2016-10-25 20:11 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | initial = True 13 | 14 | dependencies = [ 15 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 16 | ] 17 | 18 | operations = [ 19 | migrations.CreateModel( 20 | name='Roles', 21 | fields=[ 22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 23 | ('title', models.CharField(max_length=100)), 24 | ], 25 | ), 26 | migrations.CreateModel( 27 | name='Teammate', 28 | fields=[ 29 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 30 | ('name', models.CharField(max_length=100)), 31 | ('github', models.CharField(max_length=100)), 32 | ('slack', models.CharField(max_length=100)), 33 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 34 | ], 35 | ), 36 | ] 37 | -------------------------------------------------------------------------------- /projects/migrations/0005_auto_20170117_1752.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-17 17:52 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('projects', '0004_remove_buy_locked'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='ProcurementMethod', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('name', models.CharField(max_length=100)), 21 | ('vendors', models.ManyToManyField(blank=True, to='projects.Vendor')), 22 | ], 23 | ), 24 | migrations.AlterField( 25 | model_name='buy', 26 | name='procurement_method', 27 | field=models.CharField(choices=[('agile_bpa', 'Agile Development Services BPA'), ('micropurchase', 'Micro-purchase Platform')], max_length=100), 28 | ), 29 | migrations.AddField( 30 | model_name='buy', 31 | name='procurement_method_link', 32 | field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='projects.ProcurementMethod'), 33 | ), 34 | ] 35 | -------------------------------------------------------------------------------- /projects/migrations/0014_auto_20170123_0403.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-23 04:03 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0013_auto_20170123_0350'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RemoveField( 16 | model_name='agency', 17 | name='business_event_type_code', 18 | ), 19 | migrations.RemoveField( 20 | model_name='agency', 21 | name='treasury_account_symbol', 22 | ), 23 | migrations.AddField( 24 | model_name='iaa', 25 | name='business_event_type_code', 26 | field=models.CharField(default='abcd1234', help_text='An 8-character alphanumeric code indicating the type of activity (e.g. payments, collections, investments) taking place. For more information, see https://www.fiscal.treasury.gov/fsservices/gov/acctg/cars/factsheet_betc.htm', max_length=8), 27 | preserve_default=False, 28 | ), 29 | migrations.AddField( 30 | model_name='iaa', 31 | name='treasury_account_symbol', 32 | field=models.CharField(default='00120160171', max_length=20), 33 | preserve_default=False, 34 | ), 35 | ] 36 | -------------------------------------------------------------------------------- /web/views.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, tzinfo 2 | from dateutil.tz import tzlocal 3 | from django.shortcuts import render 4 | from django.shortcuts import redirect 5 | from django.contrib.auth.decorators import login_required 6 | from rest_framework.authtoken.models import Token 7 | from rest_framework.response import Response 8 | from rest_framework.reverse import reverse 9 | from rest_framework.decorators import api_view 10 | from news.models import Post 11 | 12 | 13 | # Create your views here. 14 | def index(request): 15 | posts = Post.objects.filter( 16 | draft=False, 17 | publication_date__lte=datetime.now(tzlocal()) 18 | ).order_by('publication_date')[:5] 19 | return render(request, 'web/index.html', {'posts': posts}) 20 | 21 | 22 | def guides(request): 23 | return render(request, 'web/guides.html') 24 | 25 | 26 | @login_required 27 | def profile(request): 28 | return render(request, 'web/profile.html') 29 | 30 | 31 | @login_required 32 | def refresh_token(request): 33 | # TODO: Updating in place seems better, but couldn't get that to work. 34 | # Commented lines below are what I tried. 35 | token = Token.objects.get_or_create(user=request.user)[0] 36 | # token.key = token.generate_key() 37 | # token.save(update_fields=['key']) 38 | token.delete() 39 | Token.objects.create(user=request.user) 40 | return redirect("/profile/") 41 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/external-link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/external-link-alt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/external-link-hover.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/external-link-alt-hover.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | As a work of the United States government, this project is in the 2 | public domain within the United States. 3 | 4 | Additionally, we waive copyright and related rights in the work 5 | worldwide through the CC0 1.0 Universal public domain dedication. 6 | 7 | ## CC0 1.0 Universal summary 8 | 9 | This is a human-readable summary of the [Legal Code (read the full text)](https://creativecommons.org/publicdomain/zero/1.0/legalcode). 10 | 11 | ### No copyright 12 | 13 | The person who associated a work with this deed has dedicated the work to 14 | the public domain by waiving all of his or her rights to the work worldwide 15 | under copyright law, including all related and neighboring rights, to the 16 | extent allowed by law. 17 | 18 | You can copy, modify, distribute and perform the work, even for commercial 19 | purposes, all without asking permission. 20 | 21 | ### Other information 22 | 23 | In no way are the patent or trademark rights of any person affected by CC0, 24 | nor are the rights that other persons may have in the work or in how the 25 | work is used, such as publicity or privacy rights. 26 | 27 | Unless expressly stated otherwise, the person who associated a work with 28 | this deed makes no warranties about the work, and disclaims liability for 29 | all uses of the work, to the fullest extent permitted by applicable law. 30 | When using or citing the work, you should not imply endorsement by the 31 | author or the affirmer. 32 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/social-icons/svg/rss25.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /acquisitions/management/commands/init_groups.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | from django.core.management.base import BaseCommand, CommandError 3 | from django.contrib.auth.models import Group, Permission, ContentType 4 | from projects.models import Project 5 | from team.models import Teammate 6 | 7 | 8 | class Command(BaseCommand): 9 | help = 'Initialize groups' 10 | 11 | def handle(self, *args, **options): 12 | 13 | try: 14 | group = Group.objects.get(name='NDA Signed') 15 | except Group.DoesNotExist: 16 | group = Group( 17 | name='NDA Signed' 18 | ) 19 | group.save() 20 | content_type = ContentType.objects.get_for_model(Project) 21 | group.permissions = [ 22 | Permission.objects.get( 23 | codename='view_project', 24 | content_type=content_type, 25 | ), 26 | ] 27 | group.save() 28 | 29 | try: 30 | group = Group.objects.get(name='Teammates') 31 | except Group.DoesNotExist: 32 | group = Group( 33 | name='Teammates' 34 | ) 35 | group.save() 36 | content_type = ContentType.objects.get_for_model(Teammate) 37 | group.permissions = [ 38 | Permission.objects.get( 39 | codename='view_private', 40 | content_type=content_type, 41 | ), 42 | ] 43 | group.save() 44 | -------------------------------------------------------------------------------- /projects/migrations/0015_auto_20170123_1444.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-23 14:44 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('projects', '0014_auto_20170123_0403'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RemoveField( 16 | model_name='iaa', 17 | name='cogs_amount', 18 | ), 19 | migrations.RemoveField( 20 | model_name='iaa', 21 | name='non_cogs_amount', 22 | ), 23 | migrations.RemoveField( 24 | model_name='project', 25 | name='dollars', 26 | ), 27 | migrations.AddField( 28 | model_name='iaa', 29 | name='budget', 30 | field=models.IntegerField(default=5000), 31 | preserve_default=False, 32 | ), 33 | migrations.AddField( 34 | model_name='project', 35 | name='cogs_amount', 36 | field=models.IntegerField(default=2000, verbose_name='Cost of Goods Sold'), 37 | preserve_default=False, 38 | ), 39 | migrations.AddField( 40 | model_name='project', 41 | name='non_cogs_amount', 42 | field=models.IntegerField(default=2000, verbose_name='Cost of Team Labor'), 43 | preserve_default=False, 44 | ), 45 | ] 46 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile 3 | # To update, run: 4 | # 5 | # pip-compile --output-file requirements.txt requirements.in 6 | # 7 | -e git+https://github.com/18f/acq-templates@develop#egg=acq_templates 8 | appdirs==1.4.0 # via setuptools 9 | cfenv==0.5.2 10 | dj-database-url==0.4.1 11 | django-filter==1.0.1 12 | django-floppyforms==1.7.0 13 | django-form-utils==1.0.3 14 | django-markdown-deux==1.0.5 15 | django==1.10.4 16 | djangorestframework-csv==2.0.0 17 | djangorestframework==3.5.3 18 | drfdocs==0.0.11 19 | factory-boy==2.8.1 20 | faker==0.7.5 # via factory-boy 21 | furl==0.5.6 # via cfenv 22 | httmock==1.2.6 23 | markdown2==2.3.2 # via django-markdown-deux 24 | markdown==2.6.7 25 | newrelic==2.76.0.55 26 | orderedmultidict==0.7.11 # via furl 27 | packaging==16.8 # via setuptools 28 | pillow==3.4.2 29 | psycopg2==2.6.2 30 | pyjwt==1.4.2 31 | pypandoc==1.3.3 32 | pyparsing==2.1.10 # via packaging 33 | python-dateutil==2.6.0 # via faker 34 | requests==2.12.4 35 | six==1.10.0 # via djangorestframework-csv, faker, furl, orderedmultidict, packaging, python-dateutil, setuptools 36 | unicodecsv==0.14.1 # via djangorestframework-csv 37 | wheel==0.29.0 # via pypandoc 38 | whitenoise==3.2.2 39 | 40 | # The following packages are considered to be unsafe in a requirements file: 41 | # pip # via pypandoc 42 | # setuptools # via pypandoc 43 | -------------------------------------------------------------------------------- /web/static/web/css/style.css: -------------------------------------------------------------------------------- 1 | blockquote { 2 | border-left: 1px solid black; 3 | padding-left: 10px; 4 | } 5 | 6 | .astronaut { 7 | background-image: url('../img/astronaut.jpg'); 8 | } 9 | 10 | .usa-nav-submenu { 11 | box-shadow: 0 2px 3px #3e94cf, 0 2px 5px #3e94cf; 12 | } 13 | 14 | /* Forms */ 15 | .required { 16 | border-left: 5px solid #3e94cf; 17 | padding-left: 5px; 18 | } 19 | 20 | .helptext { 21 | font-size: 90%; 22 | font-style: italic; 23 | } 24 | 25 | .form-sidebar { 26 | padding-top: 3rem; 27 | } 28 | 29 | /* Buys */ 30 | 31 | .acq-documents { 32 | margin-bottom: 1.5em; 33 | } 34 | 35 | .acq-documents > div { 36 | background-color: #e4e4e4; 37 | padding: 25px; 38 | } 39 | 40 | /* Team */ 41 | 42 | .teammateName { 43 | font-weight: bold; 44 | } 45 | 46 | @media screen and (min-width: 600px) { 47 | .teammateRight { 48 | height: 96px; 49 | display: flex; 50 | flex-direction: column; 51 | justify-content: center; 52 | } 53 | } 54 | 55 | /* Modals */ 56 | 57 | .dialog[aria-hidden="true"] { 58 | display: none; 59 | } 60 | 61 | .dialog-overlay { 62 | z-index: 2; 63 | background-color: rgba(0, 0, 0, 0.66); 64 | position: fixed; 65 | top: 0; 66 | left: 0; 67 | bottom: 0; 68 | right: 0; 69 | } 70 | 71 | .dialog-content { 72 | background-color: rgb(255, 255, 255); 73 | z-index: 3; 74 | position: fixed; 75 | top: 50%; 76 | left: 50%; 77 | -webkit-transform: translate(-50%, -50%); 78 | -ms-transform: translate(-50%, -50%); 79 | transform: translate(-50%, -50%); 80 | } 81 | -------------------------------------------------------------------------------- /news/templates/news/posts.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | {% load static from staticfiles %} 3 | 4 | {% block content %} 5 |
6 |
7 |

All updates

8 | {% for post in posts %} 9 |

{{ post.title }}

10 |

11 | Posted on {{ post.publication_date }}
by {% for author in post.authors.all %} 12 | {{ author.get_full_name }}{% if not forloop.last %}, {% endif %} 13 | {% endfor %}
14 |

15 |
16 | {{ post.content }} 17 |

Permalink

18 |
19 | {% empty %} 20 |

No updates yet, but stay tuned!

21 | {% endfor %} 22 |
23 | 38 |
39 |

RSS Feed rss icon

40 |
41 |
42 |
43 | {% endblock %} 44 | -------------------------------------------------------------------------------- /nda/templates/nda/markdown/buy_nda.md: -------------------------------------------------------------------------------- 1 | Non-Disclosure Agreement for {{ buy.name }} 2 | =========================================== 3 | 4 | I, {{ user.get_full_name }}, do solemnly swear (or affirm) that I will not 5 | knowingly disclose contractor proposal information or evaluation information 6 | (proposed prices, technical information, evaluations of proposals, rankings of 7 | proposals, or source selection decisions) relating to any offeror's proposal 8 | submitted in response to the RFP/RFQ issued pursuant to this project to any 9 | unauthorized person for any purpose. Neither will I knowingly disclose, directly 10 | or indirectly, any other data relative to this procurement to any unauthorized 11 | person for any purpose. 12 | 13 | I understand that authorized persons refers only to persons assigned by 14 | Government Services Administration to participate in the evaluation of the 15 | proposals received in response to the above mentioned Project/Title, or directly 16 | in the line of management over this project, requiring access to the data, who 17 | have also signed a non-disclosure certification, and who are also included in 18 | the disclosure prohibition. 19 | 20 | I am aware that the unauthorized use or disclosure of information may be a 21 | violation of law (41 U.S.C. 423 as amended, or 18 U.S.C. 1905 as amended), 22 | executive order, or regulation (Federal Acquisition Regulation, Part 3 - 23 | Improper Business Practices and Personal Conflicts of Interest, and subject to 24 | criminal, or civil penalties punishable by fine, imprisonment, or both, or 25 | administrative remedies. 26 | -------------------------------------------------------------------------------- /news/models.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from dateutil.tz import tzlocal 3 | from django.db import models 4 | from django.core.exceptions import ValidationError 5 | from django.contrib.auth.models import User 6 | from django.urls import reverse 7 | 8 | 9 | # Create your models here. 10 | class Post(models.Model): 11 | title = models.CharField( 12 | max_length=100, 13 | blank=False, 14 | null=False, 15 | ) 16 | slug = models.SlugField( 17 | max_length=50, 18 | blank=True, 19 | null=True, 20 | ) 21 | authors = models.ManyToManyField( 22 | User, 23 | blank=False, 24 | ) 25 | content = models.TextField( 26 | blank=False, 27 | null=False, 28 | ) 29 | publication_date = models.DateTimeField( 30 | blank=True, 31 | null=True, 32 | ) 33 | draft = models.BooleanField( 34 | default=True, 35 | ) 36 | 37 | def __str__(self): 38 | return "{0} | {1}".format(self.title, self.publication_date) 39 | 40 | def get_absolute_url(self): 41 | return reverse('news:post', args=[self.slug]) 42 | 43 | def clean(self): 44 | if self.draft and self.publication_date is not None: 45 | raise ValidationError({ 46 | 'publication_date': 'Drafts may not have a publication date' 47 | }) 48 | if not self.draft and self.publication_date is None: 49 | raise ValidationError({ 50 | 'publication_date': 'Please set a publication date' 51 | }) 52 | 53 | class Meta: 54 | pass 55 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/alerts/warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 16 | 17 | -------------------------------------------------------------------------------- /projects/templates/projects/edit_iaa.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

{% if iaa %}Edit: {{ iaa.id }}{% else %}Create IAA{% endif %}

7 |
8 | {% csrf_token %} 9 | {{ form.non_field_errors }} 10 |
11 | {{ form.id.errors }} 12 | {{ form.id.label_tag }} 13 | {{ form.id }} 14 |
15 |
16 | {{ form.client.errors }} 17 | {{ form.client.label_tag }} 18 | {{ form.client }} 19 |
20 |
21 | {{ form.signed_on.errors }} 22 | {{ form.signed_on.label_tag }} 23 | {{ form.signed_on }} 24 |
25 |
26 | {{ form.expires_on.errors }} 27 | {{ form.expires_on.label_tag }} 28 | {{ form.expires_on }} 29 |
30 |
31 | {{ form.budget.errors }} 32 | {{ form.budget.label_tag }} 33 | {{ form.budget }} 34 |
35 |
36 | {{ form.authority.errors }} 37 | {{ form.authority.label_tag }} 38 | {{ form.authority }} 39 |
40 | 41 |
42 |
43 |
44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/alerts/error.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 17 | 18 | -------------------------------------------------------------------------------- /projects/migrations/0002_auto_20170109_1724.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.4 on 2017-01-09 17:24 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | import projects.fields 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('projects', '0001_squashed_0020_auto_20170104_1734'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='buy', 18 | name='acquisition_plan', 19 | field=projects.fields.DocumentField(blank=True, null=True), 20 | ), 21 | migrations.AlterField( 22 | model_name='buy', 23 | name='interview_questions', 24 | field=projects.fields.DocumentField(blank=True, null=True), 25 | ), 26 | migrations.AlterField( 27 | model_name='buy', 28 | name='market_research', 29 | field=projects.fields.DocumentField(blank=True, null=True), 30 | ), 31 | migrations.AlterField( 32 | model_name='buy', 33 | name='pws', 34 | field=projects.fields.DocumentField(blank=True, null=True, verbose_name='Performance Work Statement'), 35 | ), 36 | migrations.AlterField( 37 | model_name='buy', 38 | name='qasp', 39 | field=projects.fields.DocumentField(blank=True, null=True, verbose_name='Quality Assurance Surveillance Plan'), 40 | ), 41 | migrations.AlterField( 42 | model_name='buy', 43 | name='rfq', 44 | field=projects.fields.DocumentField(blank=True, null=True, verbose_name='Request for Quotations'), 45 | ), 46 | ] 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/python 3 | 4 | ### Python ### 5 | # Byte-compiled / optimized / DLL files 6 | __pycache__/ 7 | *.py[cod] 8 | *$py.class 9 | 10 | # C extensions 11 | *.so 12 | 13 | # Distribution / packaging 14 | .Python 15 | env/ 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *,cover 50 | .hypothesis/ 51 | 52 | # Translations 53 | *.mo 54 | *.pot 55 | 56 | # Django stuff: 57 | *.log 58 | local_settings.py 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # IPython Notebook 74 | .ipynb_checkpoints 75 | 76 | # pyenv 77 | .python-version 78 | 79 | # celery beat schedule file 80 | celerybeat-schedule 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | venv/ 87 | ENV/ 88 | 89 | # Spyder project settings 90 | .spyderproject 91 | 92 | # Rope project settings 93 | .ropeproject 94 | 95 | # Project-specific 96 | staticfiles 97 | db.sqlite3 98 | acquisitions_manifest.yml 99 | cf-ssh.yml 100 | -------------------------------------------------------------------------------- /docs/deploy.md: -------------------------------------------------------------------------------- 1 | # Deployment 2 | 3 | ## On Cloud Foundry 4 | 5 | The cloud.gov documentation provides some [general steps](https://cloud.gov/docs/apps/django/) for deploying a Django application. 6 | 7 | ### Creating the application 8 | 9 | If no application exists yet, begin by targeting the correct space: 10 | 11 | ``` 12 | cf target -o gsa-acq-proto -s staging 13 | ``` 14 | 15 | Create a non-functioning app so that services can bind to something: 16 | 17 | ``` 18 | cf push -f manifest-staging.yml --no-start 19 | ``` 20 | 21 | Create and bind a database as discussed in [the cloud.gov database documentation](https://cloud.gov/docs/apps/databases/): 22 | 23 | ``` 24 | cf create-service aws-rds shared-psql acquisitions-staging-psql 25 | cf bind-service acquisitions-staging acquisitions-staging-psql 26 | ``` 27 | 28 | Further configuration is stored in [**user-provided services**](https://docs.cloudfoundry.org/devguide/services/user-provided.html), as discussed below. 29 | 30 | ### New Relic 31 | 32 | Create a user-provided service, replacing `the-license-key` with the New Relic license key: 33 | 34 | ``` 35 | cf create-user-provided-service acquisitions-new-relic -p '{"NEW_RELIC_LICENSE_KEY": "the-license-key"}' 36 | ``` 37 | 38 | ### Pushing the application 39 | 40 | Deployment is handled via Travis CI, so manual pushing is typically not required. 41 | 42 | In the event that a manual push is required, a zero-downtime push is preferred. Make sure that `autopilot` is installed: 43 | 44 | ``` 45 | cf install-plugin autopilot -f -r CF-Community 46 | ``` 47 | 48 | Check the target: 49 | 50 | ``` 51 | cf target -o gsa-acq-proto -s staging 52 | ``` 53 | 54 | And push: 55 | 56 | ``` 57 | cf zero-downtime-push acquisitions-staging -f manifest-staging.yml 58 | ``` 59 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile 3 | # To update, run: 4 | # 5 | # pip-compile --output-file requirements-dev.txt requirements-dev.in 6 | # 7 | appnope==0.1.0 # via ipython 8 | bandit==1.3.0 9 | click==6.6 # via pip-tools 10 | codeclimate-test-reporter==0.2.0 11 | coverage==4.2 12 | decorator==4.0.10 # via ipython, traitlets 13 | first==2.0.1 # via pip-tools 14 | gitdb2==2.0.0 # via gitpython 15 | GitPython==2.1.1 # via bandit 16 | ipython-genutils==0.1.0 # via traitlets 17 | ipython==5.1.0 18 | Jinja2==2.8 # via poirot 19 | MarkupSafe==0.23 # via jinja2 20 | pbr==1.10.0 # via stevedore 21 | pexpect==4.2.1 # via ipython 22 | pickleshare==0.7.4 # via ipython 23 | pip-tools==1.8.0 24 | poirot==1.0.1 25 | prompt-toolkit==1.0.9 # via ipython 26 | ptyprocess==0.5.1 # via pexpect 27 | py==1.4.32 # via pytest 28 | pycodestyle==2.2.0 29 | pygments==2.1.3 # via ipython 30 | pytest-cov==2.4.0 31 | pytest-django==3.1.2 32 | pytest==3.0.5 33 | PyYAML==3.12 # via bandit 34 | regex==2016.11.21 # via poirot 35 | requests==2.12.4 # via codeclimate-test-reporter, poirot 36 | simplegeneric==0.8.1 # via ipython 37 | six==1.10.0 # via bandit, pip-tools, prompt-toolkit, stevedore, traitlets 38 | smmap2==2.0.1 # via gitdb2 39 | stevedore==1.19.1 # via bandit 40 | tqdm==4.10.0 # via poirot 41 | traitlets==4.3.1 # via ipython 42 | wcwidth==0.1.7 # via prompt-toolkit 43 | 44 | # The following packages are considered to be unsafe in a requirements file: 45 | # setuptools # via ipython 46 | -------------------------------------------------------------------------------- /web/templates/web/includes/footer.html: -------------------------------------------------------------------------------- 1 | {% load static from staticfiles %} 2 | 3 |
4 | 7 | 32 | 33 | 40 | 41 |
42 | -------------------------------------------------------------------------------- /projects/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from projects.models import Agency, AgencyOffice, IAA, Project, Buy 3 | 4 | 5 | class AgencySerializer(serializers.ModelSerializer): 6 | class Meta: 7 | model = Agency 8 | fields = ( 9 | 'name', 10 | 'address', 11 | ) 12 | 13 | 14 | class ClientSerializer(serializers.ModelSerializer): 15 | agency = AgencySerializer() 16 | client = serializers.CharField( 17 | source='__str__' 18 | ) 19 | 20 | class Meta: 21 | model = AgencyOffice 22 | fields = ( 23 | 'id', 24 | 'client', 25 | 'agency', 26 | ) 27 | 28 | 29 | class IAASerializer(serializers.ModelSerializer): 30 | client = ClientSerializer() 31 | 32 | class Meta: 33 | model = IAA 34 | fields = ( 35 | 'id', 36 | 'client', 37 | 'signed_on', 38 | ) 39 | 40 | 41 | class ProjectSerializer(serializers.ModelSerializer): 42 | iaa = IAASerializer() 43 | 44 | class Meta: 45 | model = Project 46 | fields = ( 47 | 'id', 48 | 'name', 49 | 'project_type', 50 | 'description', 51 | 'public', 52 | 'iaa', 53 | ) 54 | 55 | 56 | class BuySerializer(serializers.ModelSerializer): 57 | project = ProjectSerializer() 58 | set_aside_status = serializers.CharField( 59 | source='get_set_aside_status_display' 60 | ) 61 | 62 | class Meta: 63 | model = Buy 64 | fields = ( 65 | 'id', 66 | 'name', 67 | 'description', 68 | 'public', 69 | 'project', 70 | 'procurement_method', 71 | 'status', 72 | 'set_aside_status', 73 | 'period_of_performance', 74 | ) 75 | -------------------------------------------------------------------------------- /projects/tests/test_projects_api.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from rest_framework.test import APIRequestFactory 3 | from rest_framework.test import force_authenticate 4 | from projects.views import ProjectList 5 | from projects.models import Project 6 | from projects.factories import ProjectFactory 7 | from projects.factories import UserFactory 8 | from django.contrib.auth.models import Permission 9 | from django.contrib.contenttypes.models import ContentType 10 | from rest_framework.authtoken.models import Token 11 | 12 | 13 | @pytest.mark.django_db 14 | def test_unauthenticated(): 15 | ProjectFactory.create_batch(10, public=True) 16 | ProjectFactory.create_batch(10, public=False) 17 | view = ProjectList.as_view() 18 | factory = APIRequestFactory() 19 | 20 | request = factory.get('/projects/api/projects') 21 | response = view(request) 22 | 23 | assert len(response.data) == 10 24 | 25 | 26 | @pytest.mark.django_db 27 | def test_authenticated(): 28 | ProjectFactory.create_batch(10, public=True) 29 | ProjectFactory.create_batch(10, public=False) 30 | # Create a user 31 | user = UserFactory.create() 32 | # Get required permission 33 | content_type = ContentType.objects.get_for_model(Project) 34 | permission = Permission.objects.get( 35 | codename='view_project', 36 | content_type=content_type, 37 | ) 38 | user.user_permissions.add(permission) 39 | # Make authenticated request 40 | view = ProjectList.as_view() 41 | factory = APIRequestFactory() 42 | request = factory.get('/projects/api/projects') 43 | force_authenticate(request, user=user) 44 | response = view(request) 45 | 46 | assert len(response.data) == 20 47 | 48 | 49 | @pytest.mark.django_db 50 | def test_no_token_if_new(): 51 | user = UserFactory.create() 52 | try: 53 | Token.objects.get(user=user) 54 | except: 55 | assert True 56 | return 57 | assert False 58 | -------------------------------------------------------------------------------- /team/tests/test_team_api.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from rest_framework.test import APIRequestFactory 3 | from rest_framework.test import force_authenticate 4 | from team.views import TeammateList 5 | from team.models import Teammate 6 | from team.factories import TeammateFactory 7 | from team.factories import UserFactory 8 | from django.contrib.auth.models import Permission, Group 9 | from django.contrib.contenttypes.models import ContentType 10 | from rest_framework.authtoken.models import Token 11 | 12 | 13 | @pytest.mark.django_db 14 | def test_unauthenticated(): 15 | TeammateFactory.create_batch(10) 16 | view = TeammateList.as_view() 17 | factory = APIRequestFactory() 18 | 19 | request = factory.get('/team/api/team') 20 | response = view(request) 21 | 22 | assert len(response.data) == 10 23 | for t in response.data: 24 | with pytest.raises(KeyError): 25 | assert t['slack'] 26 | 27 | 28 | @pytest.mark.django_db 29 | def test_authenticated(): 30 | TeammateFactory.create_batch(10) 31 | # Create a user 32 | user = UserFactory.create() 33 | # Get required permission 34 | content_type = ContentType.objects.get_for_model(Teammate) 35 | permission = Permission.objects.get( 36 | codename='view_private', 37 | content_type=content_type, 38 | ) 39 | user.user_permissions.add(permission) 40 | # Make authenticated request 41 | view = TeammateList.as_view() 42 | factory = APIRequestFactory() 43 | request = factory.get('/team/api/team') 44 | force_authenticate(request, user=user) 45 | response = view(request) 46 | 47 | assert len(response.data) == 10 48 | for t in response.data: 49 | assert t['slack'] 50 | 51 | 52 | @pytest.mark.django_db 53 | def test_no_token_if_new(): 54 | user = UserFactory.create() 55 | try: 56 | Token.objects.get(user=user) 57 | except: 58 | assert True 59 | return 60 | assert False 61 | -------------------------------------------------------------------------------- /web/templates/web/base.html: -------------------------------------------------------------------------------- 1 | {% load static from staticfiles %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {% block title %}TTS Office of Acquisitions{% endblock %} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | {% block resources %}{% endblock %} 29 | 30 | 31 | Skip to main content 32 | {% include "web/includes/header.html" %} 33 |
34 |
35 | 36 | {% block content %} 37 | 38 | {% endblock %} 39 | 40 |
41 | {% block modals %}{% endblock modals %} 42 | {% include "web/includes/footer.html" %} 43 | 44 | 45 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/alerts/info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 18 | 19 | -------------------------------------------------------------------------------- /projects/tests/test_buys_api.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from rest_framework.test import APIRequestFactory 3 | from rest_framework.test import force_authenticate 4 | from projects.views import BuyList 5 | from projects.models import Buy, Project 6 | from projects.factories import BuyFactory 7 | from projects.factories import UserFactory 8 | from django.contrib.auth.models import Permission 9 | from django.contrib.contenttypes.models import ContentType 10 | from rest_framework.authtoken.models import Token 11 | 12 | 13 | @pytest.mark.django_db 14 | def test_unauthenticated(): 15 | BuyFactory.create_batch(10, public=True) 16 | BuyFactory.create_batch(10, public=False) 17 | view = BuyList.as_view() 18 | factory = APIRequestFactory() 19 | 20 | request = factory.get('/projects/api/buys') 21 | response = view(request) 22 | 23 | assert len(response.data) == 10 24 | for b in response.data: 25 | assert b['public'] is True 26 | 27 | 28 | @pytest.mark.django_db 29 | def test_authenticated(): 30 | BuyFactory.create_batch(10, public=True) 31 | BuyFactory.create_batch(10, public=False) 32 | # Create a user 33 | user = UserFactory.create() 34 | # Get required permission 35 | content_type = ContentType.objects.get_for_model(Project) 36 | permission = Permission.objects.get( 37 | codename='view_project', 38 | content_type=content_type, 39 | ) 40 | user.user_permissions.add(permission) 41 | # Make authenticated request 42 | view = BuyList.as_view() 43 | factory = APIRequestFactory() 44 | request = factory.get('/projects/api/buys') 45 | force_authenticate(request, user=user) 46 | response = view(request) 47 | 48 | assert len(response.data) == 20 49 | 50 | 51 | @pytest.mark.django_db 52 | def test_no_token_if_new(): 53 | user = UserFactory.create() 54 | try: 55 | Token.objects.get(user=user) 56 | except: 57 | assert True 58 | return 59 | assert False 60 | -------------------------------------------------------------------------------- /fake_uaa_provider/templates/fake_uaa_provider/fake_uaa_provider.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% load static from staticfiles %} 4 | 60 | Fake cloud.gov Login 61 | 62 | 63 |

Welcome to your fake UAA provider!

64 |

65 | Just enter an email address below and we'll log you in. 66 |

67 |
68 | 69 | 70 | {% for key, value in query.items %} 71 | 72 | {% endfor %} 73 |
74 | 75 |
76 |
77 |
78 | Note that a user account with the corresponding email address needs 79 | to exist in the database for the login to successfully complete. 80 | For more details, see the 81 | README. 82 |
83 | 84 | -------------------------------------------------------------------------------- /team/migrations/0001_squashed_0011_auto_20161105_2006.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-12-08 15:04 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | replaces = [('team', '0001_initial'), ('team', '0002_teammate_bio'), ('team', '0003_auto_20161029_1649'), ('team', '0004_auto_20161029_1650'), ('team', '0005_teammate_read_only'), ('team', '0006_auto_20161031_0210'), ('team', '0007_teammate_photo'), ('team', '0008_auto_20161031_2304'), ('team', '0009_auto_20161031_2306'), ('team', '0010_remove_teammate_read_only'), ('team', '0011_auto_20161105_2006')] 13 | 14 | initial = True 15 | 16 | dependencies = [ 17 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 18 | ] 19 | 20 | operations = [ 21 | migrations.CreateModel( 22 | name='Role', 23 | fields=[ 24 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 25 | ('name', models.CharField(max_length=100)), 26 | ], 27 | ), 28 | migrations.CreateModel( 29 | name='Teammate', 30 | fields=[ 31 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 32 | ('name', models.CharField(max_length=100)), 33 | ('github', models.CharField(blank=True, max_length=100, null=True)), 34 | ('slack', models.CharField(blank=True, max_length=100, null=True)), 35 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 36 | ('bio', models.TextField(blank=True, max_length=1000, null=True)), 37 | ('role', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='team.Role')), 38 | ('photo', models.ImageField(default='/team/photos/default.png', upload_to='/team/photos')), 39 | ], 40 | ), 41 | migrations.AlterModelOptions( 42 | name='teammate', 43 | options={'permissions': (('view_private', 'Can view private team info'),)}, 44 | ), 45 | ] 46 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - '3.5' 4 | addons: 5 | postgresql: '9.4' 6 | install: 7 | - pip install -r requirements.txt 8 | - pip install -r requirements-dev.txt 9 | cache: 10 | directories: 11 | - "$HOME/.cache/pip" 12 | script: 13 | - "./manage.py collectstatic --noinput -v 0" 14 | - py.test --cov=acquisitions --cov=projects --cov=team --cov=web --cov=nda 15 | - codeclimate-test-reporter 16 | - bandit -r . 17 | after_script: 18 | - npm install -g pa11y-crawl 19 | - pa11y-crawl --run "./manage.py runserver" --ci http://localhost:8000 20 | before_deploy: 21 | - export PATH=$HOME:$PATH 22 | - travis_retry curl -L -o $HOME/cf.tgz "https://cli.run.pivotal.io/stable?release=linux64-binary&version=6.15.0" 23 | - tar xzvf $HOME/cf.tgz -C $HOME 24 | - cf install-plugin autopilot -f -r CF-Community 25 | deploy: 26 | - provider: script 27 | script: "./bin/deploy staging" 28 | skip_cleanup: true 29 | on: 30 | branch: develop 31 | env: 32 | global: 33 | - CF_USERNAME=c9a300d8-2610-424b-94a0-14e321420176 34 | - secure: Nf375s8h8cSMgKdSR3wpCl26pwaYAhbxHiJ9tf4rWtJNZKv+WeX/hgsv+EG+oztyMz8QYOaSsONz3BszMG/zi3JOov/mZIRm6kQhGexzTSXh3sTZU+/3ZGuX2SQORKIl0NMLnV2KIvsGrKskCSkc4jR6jvMmNQscU6zp6PcmfPQrfZtnHv8Iz9okCjvZMD+iWTYeV0Y9wtNk15beNbk/B7HKyR6UyQ1ELDbyK99yp2GlBJkqqM0n+lPcYq3Y6VhEetFvuw6wwR0CasVFhP+1MCooRkoC96oF7/gh2UBqQFsHazCvK1wAx2Qv7kfZy0oASIkOvqT2VJ0+YPj5eR2WVbl6jkrV6CVMhZZNulR5K3engKGYCgJN1ZawkyDNeI5Soxc11kA7nB+khshTYgFUXBiPFBW1TLvDd8h5aTlvsQHhyHcw6PJi8ioREdRZ4+E8jzF7xCOM+JGw5M7l1VMliIevBB4FmJbSwrInYYokFJRIo3zWtkDWIlZOUjdkSiWLV560I9tBEiFwTPXmQlgLPwWo5FKMJZia6d1s9UpxXxIgSgxUL0vcqt+vrAu3zEnKvMGtlNWzNocjgR65YHEeWGgxiBDfOYmdYhQCJTHh1REY9T3URluQ5FlezHiTqzyqsU0aqmP+3Wysptk3p2dIGZUmCIeGkgwMQcu0FZvP7og= 35 | - secure: W+LzIxX8OtGsunesEKMo6rJHqS9n827c+a7o2lDbv84xn3ucb7dk526QOesv5+5hs9uKmhkIgIdh4lQhxqrl4mGo5T3dTfQhPClH3CWeOi47qqSTRKOw2XZrc1Ef/FW7NBIknovxtFvOusKGK/Y70Yhgx2wazJLj2xpIW1E8ZNnsY6Lt9NLFLp/+AACHT70ceWxn20OK5hyjAOeBoaeT08mogvAl7np97hY+3oK5BR6ZOIn2+6ToUle6vBFUyTuc/rK409bvwKLbN/PPu4BaH8glHZmuDmyS0LqzOpatfaLGbEvrLlaZv/wiR2geMOJaG0elp8zi8AcRJ6I0cqnWd0+WSKUfBMlGoEhp24YZq4f1+10vOYI4Pv0BwKmAMlxHw7gjmeWTdlPGALrwXrvUZ6+UEgjLzd35Xwxbu89VWmdYuBlrhQKj1kk06Rwp5pdl6FZTHJm3YKp5pJfZxSCgQxmw0IWKxjg0nBV9EvWofdXDBXxQUxeYWd3Zv22OA7Np69vc5VNDWknGBKyUTapd+0OLru+R1GMNelVAq7oFpD89IYtxjBpESFrybFBoRMhz6MAkGA+yyG7d4QCAMeaUJWTKyTxGNznQXDMWNwTQ0k0+/vA0xbL/zcX59V2ZBqhb5HP55CKBucF+yHgZnzYyzNQK03oMWjM1mo3iyWgQ7ik= 36 | -------------------------------------------------------------------------------- /system-security-plan.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: acquisitions.18f.gov 3 | uniqueID: 4 | version: 0.1 5 | # descriptions: 6 | # https://18f.gsa.gov/dashboard/ 7 | phase: alpha 8 | # `D26 Civilian Operations` is most common for 18F projects. 9 | # http://csrc.nist.gov/publications/nistpubs/800-60-rev1/SP800-60_Vol1-Rev1.pdf#page=23 10 | information-types: 11 | - D26 Civilian Operations 12 | 13 | # https://pages.18f.gov/before-you-ship/ato/levels/ 14 | confidentiality: low 15 | integrity: low 16 | availability: low 17 | security-baseline: low 18 | 19 | system-type: minor 20 | level-of-identity-assurance: https://compliance.cloud.gov/ 21 | staff: 22 | authorizing-official: 23 | name: Noah Kunin 24 | title: TTS Infrastructure Director 25 | org: General Services Administration 26 | unit: TTS 27 | email: devops@gsa.gov 28 | system-owner: 29 | name: Noah Kunin 30 | title: TTS Infrastructure Director 31 | org: General Services Administration 32 | unit: TTS 33 | email: devops@gsa.gov 34 | system-management: 35 | name: Noah Kunin 36 | title: TTS Infrastructure Director 37 | org: General Services Administration 38 | unit: TTS 39 | email: devops@gsa.gov 40 | system-security-officer: 41 | name: Noah Kunin 42 | title: TTS Infrastructure Director 43 | org: General Services Administration 44 | unit: TTS 45 | email: devops@gsa.gov 46 | technical-lead: 47 | name: Steven Reilly 48 | title: Technical Lead 49 | org: General Services Administration 50 | unit: 18F 51 | email: steven.reilly@gsa.gov 52 | leveraged-authorizations: 53 | - https://www.fedramp.gov/marketplace/compliant-systems/amazon-web-services-aws-eastwest-us-public-cloud/ 54 | purpose: https://github.com/18f/acquisitions.18f.gov 55 | components: 56 | - https://github.com/18f/acquisitions.18f.gov 57 | 58 | # these will be the same unless your architecture is especially complex 59 | system-diagram: https://docs.google.com/drawings/d/1k46ab0xqvIIqICkHdqSShaXugrwjSM_e4yHs0PTjGTo/edit 60 | network-diagram: https://docs.google.com/drawings/d/1k46ab0xqvIIqICkHdqSShaXugrwjSM_e4yHs0PTjGTo/edit 61 | 62 | environments: 63 | - Cloud Foundry 64 | - Amazon Web Services GovCloud 65 | user-types: 66 | developer: 67 | functions: 68 | - deployment 69 | - engineering 70 | controls: 71 | - https://github.com/18f/acquisitions.18f.gov/blob/develop/compliance/component.yaml 72 | -------------------------------------------------------------------------------- /projects/templates/projects/edit_project.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

{% if project %}Edit: {{ project.name }}{% else %}Create Project{% endif %}

7 |
8 | {% csrf_token %} 9 | {{ form.non_field_errors }} 10 |
11 | {{ form.name.errors }} 12 | {{ form.name.label_tag }} 13 | {{ form.name }} 14 |
15 |
16 | {{ form.description.errors }} 17 | {{ form.description.label_tag }} 18 | {{ form.description }} 19 |
20 |
21 | {{ form.project_type.errors }} 22 | {{ form.project_type.label_tag }} 23 | {{ form.project_type }} 24 |
25 |
26 | {{ form.iaa.errors }} 27 | {{ form.iaa.label_tag }} 28 | {{ form.iaa }} 29 |
30 |
31 | IAA budget available: {{ project.iaa.budget_remaining }} 32 |
33 |
34 | {{ form.cogs_amount.errors }} 35 | {{ form.cogs_amount.label_tag }} 36 | {{ form.cogs_amount }} 37 |
38 |
39 | {{ form.non_cogs_amount.errors }} 40 | {{ form.non_cogs_amount.label_tag }} 41 | {{ form.non_cogs_amount }} 42 |
43 |
44 | {{ form.team_members.errors }} 45 | {{ form.team_members.label_tag }} 46 | {{ form.team_members }} 47 |
48 |
49 | {{ form.public.errors }} 50 | {{ form.public }} 51 | 52 |
53 | 54 |
55 |
56 |
57 | {% endblock %} 58 | -------------------------------------------------------------------------------- /third-party/a11y-dialog/js/a11y-dialog.min.js: -------------------------------------------------------------------------------- 1 | !function(e){"use strict";function t(e,t,n){function i(e,t){t=t||{bubbles:!1,cancelable:!1,detail:void 0};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,t.bubbles,t.cancelable,t.detail),n}i.prototype=window.Event.prototype;var o;o=window.CustomEvent&&"function"==typeof window.CustomEvent?new window.CustomEvent(t,{detail:n}):new i(t,{bubbles:!1,cancelable:!1,detail:n}),o&&e.dispatchEvent(o)}function n(e){var t=["a[href]","area[href]","input:not([disabled])","select:not([disabled])","textarea:not([disabled])","button:not([disabled])","iframe","object","embed","[contenteditable]",'[tabindex]:not([tabindex^="-"])'];return i(t.join(","),e).filter(function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)})}function i(e,t){return Array.prototype.slice.call((t||document).querySelectorAll(e))}function o(e,t){var i=n(e),o=i.indexOf(document.activeElement);t.shiftKey&&0===o?(i[i.length-1].focus(),t.preventDefault()):t.shiftKey||o!==i.length-1||(i[0].focus(),t.preventDefault())}function d(e){var t=n(e);t.length&&t[0].focus()}var a,r=function(e,n){function r(t){l.shown&&27===t.which&&(t.preventDefault(),s()),l.shown&&9===t.which&&o(e,t)}function c(t){l.shown&&!e.contains(t.target)&&d(e)}function u(){l.shown||(l.shown=!0,e.removeAttribute("aria-hidden"),n.setAttribute("aria-hidden","true"),a=document.activeElement,d(e),document.body.addEventListener("focus",c,!0),document.addEventListener("keydown",r),t(e,"dialog:show",this))}function s(){l.shown&&(l.shown=!1,e.setAttribute("aria-hidden","true"),n.removeAttribute("aria-hidden"),a&&a.focus(),document.body.removeEventListener("focus",c,!0),document.removeEventListener("keydown",r),t(e,"dialog:hide",this))}function f(){s(),h.forEach(function(e){e.removeEventListener("click",u)}),v.forEach(function(e){e.removeEventListener("click",s)})}n=n||document.querySelector("#main");var l=this,h=i('[data-a11y-dialog-show="'+e.id+'"]'),v=i("[data-a11y-dialog-hide]",e).concat(i('[data-a11y-dialog-hide="'+e.id+'"]'));e.hasAttribute("aria-hidden")&&(this.shown=!JSON.parse(e.getAttribute("aria-hidden"))),this.show=u,this.hide=s,this.destroy=f,h.forEach(function(e){e.addEventListener("click",u)}),v.forEach(function(e){e.addEventListener("click",s)})};"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=r:"function"==typeof define&&define.amd?define("A11yDialog",[],function(){return r}):"object"==typeof e&&(e.A11yDialog=r)}(this); -------------------------------------------------------------------------------- /uaa_client/views.py: -------------------------------------------------------------------------------- 1 | from urllib.parse import urlencode 2 | import django.contrib.auth 3 | from django.conf import settings 4 | from django.http import HttpResponseRedirect 5 | from django.shortcuts import resolve_url, render, reverse 6 | from django.utils.crypto import get_random_string 7 | from django.utils.http import is_safe_url 8 | 9 | from .authentication import get_auth_url 10 | 11 | 12 | def login_error(request, error_code): 13 | return render(request, 'uaa_client/oauth2_error.html', { 14 | 'error_code': error_code 15 | }) 16 | 17 | 18 | def logout(request): 19 | django.contrib.auth.logout(request) 20 | return render(request, 'uaa_client/logged_out.html') 21 | 22 | 23 | def login(request): 24 | request.session['oauth2_next_url'] = request.GET.get('next', '') 25 | request.session['oauth2_state'] = get_random_string(length=32) 26 | redirect_uri = request.build_absolute_uri(reverse('uaa_client:callback')) 27 | url = get_auth_url(request) + '?' + urlencode({ 28 | 'client_id': settings.UAA_CLIENT_ID, 29 | 'response_type': 'code', 30 | 'state': request.session['oauth2_state'], 31 | 'redirect_uri': redirect_uri 32 | }) 33 | 34 | return HttpResponseRedirect(url) 35 | 36 | 37 | def oauth2_callback(request): 38 | code = request.GET.get('code') 39 | expected_state = request.session.get('oauth2_state') 40 | state = request.GET.get('state') 41 | if state is None: 42 | return login_error(request, 'missing_state') 43 | 44 | if expected_state is None: 45 | return login_error(request, 'missing_session_state') 46 | 47 | if state != expected_state: 48 | return login_error(request, 'invalid_state') 49 | 50 | if code is None: 51 | return login_error(request, 'missing_code') 52 | 53 | user = django.contrib.auth.authenticate(uaa_oauth2_code=code, 54 | request=request) 55 | 56 | if user is None: 57 | return login_error(request, 'invalid_code_or_nonexistent_user') 58 | 59 | del request.session['oauth2_state'] 60 | 61 | django.contrib.auth.login(request, user) 62 | 63 | next_url = request.session['oauth2_next_url'] 64 | 65 | del request.session['oauth2_next_url'] 66 | 67 | if not is_safe_url(url=next_url, host=request.get_host()): 68 | next_url = resolve_url(settings.LOGIN_REDIRECT_URL) 69 | 70 | return HttpResponseRedirect(next_url) 71 | -------------------------------------------------------------------------------- /projects/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import include, url 2 | from projects import views 3 | from rest_framework.urlpatterns import format_suffix_patterns 4 | 5 | 6 | api_patterns = [ 7 | url(r'^projects/$', views.ProjectList.as_view(), name='project-list'), 8 | url(r'^projects/(?P[0-9]+)$', 9 | views.ProjectDetail.as_view(), 10 | name='project-detail'), 11 | url(r'^buys/$', views.BuyList.as_view(), name='buy-list'), 12 | url(r'^buys/abpa/$', views.BuyList.as_view(), name='abpa-list'), 13 | url(r'^buys/abpa/(?P[0-9]+)$', 14 | views.BuyDetail.as_view(), 15 | name='abpa-detail'), 16 | url(r'^iaas/$', views.IAAList.as_view(), name='iaa-list'), 17 | url(r'^iaas/(?P[0-9]+)$', 18 | views.IAADetail.as_view(), 19 | name='iaa-detail'), 20 | url(r'^clients/$', views.ClientList.as_view(), name='client-list'), 21 | url(r'^clients/(?P[0-9]+)$', 22 | views.ClientDetail.as_view(), 23 | name='client-detail'), 24 | ] 25 | 26 | iaa_patterns = [ 27 | url(r'^$', views.iaas, name='iaas'), 28 | url(r'^create/$', views.edit_iaa, name='edit_iaa'), 29 | url(r'(?P\w+)/$', views.iaa, name='iaa'), 30 | url(r'(?P\w+)/edit/$', views.edit_iaa, name='edit_iaa'), 31 | ] 32 | 33 | project_patterns = [ 34 | url(r'^$', views.projects, name='projects'), 35 | url(r'^create/$', views.create_project, name='create_project'), 36 | url(r'(?P\d+)/$', views.project, name='project'), 37 | url(r'(?P\d+)/edit/$', views.edit_project, name='edit_project'), 38 | ] 39 | 40 | buy_patterns = [ 41 | url(r'^$', views.buys, name='buys'), 42 | url(r'^create/$', views.create_buy, name='create_buy'), 43 | url(r'(?P\d+)/$', views.buy, name='buy'), 44 | url(r'(?P\d+)/edit/$', views.edit_buy, name='edit_buy'), 45 | url(r'(?P\d+)/nda/$', views.buy_nda, name='buy_nda'), 46 | url(r'(?P\d+)/(?P\w+)/$', views.document, name='document'), 47 | url( 48 | r'(?P\d+)/(?P\w+)/download/(?P\w+)?$', 49 | views.download, 50 | name='download' 51 | ), 52 | ] 53 | 54 | client_patterns = [ 55 | url(r'^$', views.clients, name='clients'), 56 | url(r'^create/$', views.edit_client, name='edit_client'), 57 | url(r'^(?P\w+)/$', views.client, name='client'), 58 | url(r'(?P\d+)/edit/$', views.edit_client, name='edit_client'), 59 | ] 60 | 61 | api_patterns = format_suffix_patterns(api_patterns) 62 | -------------------------------------------------------------------------------- /nda/tests/test_blanket_nda.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from django.contrib.auth.models import User, Group 3 | from django.test import TestCase, Client 4 | from nda.views import sign_nda 5 | from web.views import profile 6 | 7 | 8 | class TestNDA: 9 | @pytest.mark.django_db 10 | def test_add_to_group(self, rf, django_user_model): 11 | group = Group.objects.create(name='NDA Signed') 12 | user = django_user_model.objects.create() 13 | # POST form data using request factory 14 | request = rf.post('/profile/sign_nda', {'agree': True}) 15 | request.user = user 16 | response = sign_nda(request) 17 | # check group 18 | assert group == user.groups.get(id=group.id) 19 | 20 | @pytest.mark.django_db 21 | def test_did_not_agree(self, rf, django_user_model): 22 | group = Group.objects.create(name='NDA Signed') 23 | user = django_user_model.objects.create() 24 | # POST form data using request factory 25 | request = rf.post('/profile/sign_nda', {'agree': False}) 26 | request.user = user 27 | response = sign_nda(request) 28 | # check group 29 | try: 30 | user.groups.get(id=group.id) 31 | except: 32 | assert True 33 | return 34 | assert False 35 | 36 | @pytest.mark.django_db 37 | def test_skip_if_unnecessary(self, rf, django_user_model): 38 | # create user 39 | user = django_user_model.objects.create() 40 | # add to group 41 | group = Group.objects.create(name='NDA Signed') 42 | user.groups.add(group) 43 | # go to view 44 | request = rf.get('/profile/sign_nda') 45 | request.user = user 46 | response = sign_nda(request) 47 | assert "previously signed the NDA" in str(response.content) 48 | 49 | 50 | class TestViews(TestCase): 51 | def setUp(self): 52 | self.group = Group.objects.create(name='NDA Signed') 53 | self.client = Client() 54 | self.user = User.objects.create_user( 55 | username='test', email='test@wow.biz', password='top_secret') 56 | 57 | def test_need_nda(self): 58 | self.client.force_login(self.user) 59 | response = self.client.get('/profile/sign_nda/') 60 | self.assertTemplateUsed(response, 'nda/nda.html') 61 | response = self.client.post('/profile/sign_nda/', {'agree': True}) 62 | self.assertTemplateUsed(response, 'nda/success.html') 63 | response = self.client.get('/profile/sign_nda/') 64 | self.assertTemplateUsed(response, 'nda/already-signed.html') 65 | -------------------------------------------------------------------------------- /third-party/uswds-0.13.1/img/social-icons/svg/youtube15.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /uaa_client/authentication.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import requests 3 | import jwt 4 | from django.core.urlresolvers import reverse 5 | from django.contrib.auth.models import User 6 | from django.contrib.auth.backends import ModelBackend 7 | from django.conf import settings 8 | 9 | logger = logging.getLogger('uaa_client') 10 | 11 | 12 | def get_auth_url(request): 13 | if settings.DEBUG and settings.UAA_AUTH_URL == 'fake:': 14 | return request.build_absolute_uri(reverse('fake_uaa_provider:auth')) 15 | return settings.UAA_AUTH_URL 16 | 17 | 18 | def get_token_url(request): 19 | if settings.DEBUG and settings.UAA_TOKEN_URL == 'fake:': 20 | return request.build_absolute_uri(reverse('fake_uaa_provider:token')) 21 | return settings.UAA_TOKEN_URL 22 | 23 | 24 | def exchange_code_for_access_token(request, code): 25 | redirect_uri = request.build_absolute_uri(reverse('uaa_client:callback')) 26 | payload = { 27 | 'grant_type': 'authorization_code', 28 | 'code': code, 29 | 'response_type': 'token', 30 | 'redirect_uri': redirect_uri, 31 | 'client_id': settings.UAA_CLIENT_ID, 32 | 'client_secret': settings.UAA_CLIENT_SECRET 33 | } 34 | 35 | token_url = get_token_url(request) 36 | token_req = requests.post(token_url, data=payload) 37 | if token_req.status_code != 200: 38 | logger.warn('POST %s returned %s ' 39 | 'w/ content %s' % ( 40 | token_url, 41 | token_req.status_code, 42 | repr(token_req.content) 43 | )) 44 | return None 45 | 46 | response = token_req.json() 47 | request.session.set_expiry(response['expires_in']) 48 | 49 | return response['access_token'] 50 | 51 | 52 | def get_user_by_email(email): 53 | try: 54 | return User.objects.get(email=email) 55 | except User.DoesNotExist: 56 | return None 57 | 58 | 59 | class UaaBackend(ModelBackend): 60 | ''' 61 | Custom auth backend for Cloud Foundry / cloud.gov User Account and 62 | Authentication (UAA) servers. 63 | 64 | This inherits from ModelBackend so that the superclass can provide 65 | all authorization methods (e.g. `has_perm()`). 66 | ''' 67 | 68 | def authenticate(self, uaa_oauth2_code=None, request=None, **kwargs): 69 | if uaa_oauth2_code is None or request is None: 70 | return None 71 | 72 | access_token = exchange_code_for_access_token(request, uaa_oauth2_code) 73 | if access_token is None: 74 | return None 75 | 76 | user_info = jwt.decode(access_token, verify=False) 77 | 78 | return get_user_by_email(user_info['email']) 79 | -------------------------------------------------------------------------------- /team/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.shortcuts import get_object_or_404 3 | from django.shortcuts import redirect 4 | from django.http import Http404 5 | from rest_framework import viewsets 6 | from rest_framework import status 7 | from rest_framework import mixins 8 | from rest_framework import generics 9 | from rest_framework.views import APIView 10 | from team.models import Teammate, Role 11 | from team.serializers import TeammateSerializer, \ 12 | TeammatePlusSerializer, RoleSerializer 13 | 14 | 15 | # Create your views here. 16 | def home(request): 17 | return render(request, "team/index.html") 18 | 19 | 20 | def teammate(request, teammate): 21 | # Since we only want to show a page if the person exists, this can't 22 | # quite be an API-only thing. But most of the page is built via API. 23 | teammate = get_object_or_404(Teammate, user__username=teammate) 24 | return render(request, "team/teammate.html", {"teammate": teammate}) 25 | 26 | 27 | class TeammateList(mixins.ListModelMixin, 28 | generics.GenericAPIView): 29 | """ 30 | List all teammates 31 | """ 32 | queryset = Teammate.objects.all() 33 | 34 | def get_serializer_class(self): 35 | if self.request.user.has_perm('team.view_private'): 36 | return TeammatePlusSerializer 37 | else: 38 | return TeammateSerializer 39 | 40 | def get(self, request, *args, **kwargs): 41 | return self.list(request, *args, **kwargs) 42 | 43 | 44 | class TeammateDetail(mixins.RetrieveModelMixin, 45 | generics.GenericAPIView): 46 | """ 47 | Retrieve details for one teammate 48 | """ 49 | queryset = Teammate.objects.all() 50 | 51 | def get_serializer_class(self): 52 | if self.request.user.has_perm('team.view_private'): 53 | return TeammatePlusSerializer 54 | else: 55 | return TeammateSerializer 56 | 57 | def get(self, request, *args, **kwargs): 58 | return self.retrieve(request, *args, **kwargs) 59 | 60 | 61 | class RoleList(mixins.ListModelMixin, 62 | generics.GenericAPIView): 63 | """ 64 | List all roles 65 | """ 66 | queryset = Role.objects.all() 67 | serializer_class = RoleSerializer 68 | 69 | def get(self, request, *args, **kwargs): 70 | return self.list(request, *args, **kwargs) 71 | 72 | 73 | class RoleDetail(mixins.RetrieveModelMixin, 74 | generics.GenericAPIView): 75 | """ 76 | Retrive details for a role 77 | """ 78 | queryset = Role.objects.all() 79 | serializer_class = RoleSerializer 80 | 81 | def get(self, request, *args, **kwargs): 82 | return self.retrieve(request, *args, **kwargs) 83 | -------------------------------------------------------------------------------- /acquisitions/urls.py: -------------------------------------------------------------------------------- 1 | """acquisitions URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.8/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Add an import: from blog import urls as blog_urls 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls)) 15 | """ 16 | from django.conf.urls import include, url 17 | from django.contrib import admin 18 | from web import views as web_views 19 | from nda import views as nda_views 20 | from team import urls as team_urls 21 | from projects import urls as projects_urls 22 | from projects import views as project_views 23 | from news import urls as news_urls 24 | from django.conf import settings 25 | from django.conf.urls.static import static 26 | from rest_framework_docs.views import DRFDocsView 27 | 28 | 29 | api_patterns = projects_urls.api_patterns + team_urls.api_patterns 30 | 31 | 32 | urlpatterns = [ 33 | url(r'^$', web_views.index), 34 | url(r'^guides$', web_views.guides), 35 | url(r'^api/$', DRFDocsView.as_view(), name='api_docs'), 36 | url(r'^api/', include(api_patterns, namespace='api')), 37 | url(r'^financials$', project_views.financials, name='financials'), 38 | url(r'^admin/', include(admin.site.urls)), 39 | url(r'^team/', include(team_urls.urlpatterns, namespace='team')), 40 | url( 41 | r'^projects/', 42 | include(projects_urls.project_patterns, namespace='projects') 43 | ), 44 | url( 45 | r'^buys/', 46 | include(projects_urls.buy_patterns, namespace='buys') 47 | ), 48 | url( 49 | r'^iaas/', 50 | include(projects_urls.iaa_patterns, namespace='iaas') 51 | ), 52 | url( 53 | r'^clients/', 54 | include(projects_urls.client_patterns, namespace='clients') 55 | ), 56 | url( 57 | r'^news/', 58 | include(news_urls.urlpatterns, namespace='news') 59 | ), 60 | url(r'^profile/$', web_views.profile), 61 | url(r'^profile/refresh_token/$', web_views.refresh_token), 62 | url(r'^profile/sign_nda/$', nda_views.sign_nda), 63 | url(r'^auth/', include('uaa_client.urls', namespace='uaa_client')), 64 | ] 65 | 66 | if settings.DEBUG: 67 | urlpatterns += [ 68 | url(r'^', include('fake_uaa_provider.urls', 69 | namespace='fake_uaa_provider')) 70 | ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 71 | -------------------------------------------------------------------------------- /projects/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.contrib.auth.models import User 3 | from django.contrib.postgres.forms import SimpleArrayField 4 | from projects.models import Buy, Project, IAA, AgencyOffice 5 | from projects.widgets import DurationMultiWidget 6 | from form_utils.forms import BetterModelForm 7 | from form_utils.widgets import AutoResizeTextarea 8 | 9 | 10 | class ClientForm(forms.ModelForm): 11 | class Meta: 12 | model = AgencyOffice 13 | fields = '__all__' 14 | 15 | 16 | class IAAForm(forms.ModelForm): 17 | class Meta: 18 | model = IAA 19 | fields = '__all__' 20 | 21 | 22 | class ProjectForm(forms.ModelForm): 23 | class Meta: 24 | model = Project 25 | fields = '__all__' 26 | 27 | 28 | class CreateBuyForm(forms.ModelForm): 29 | class Meta: 30 | model = Buy 31 | fields = [ 32 | 'name', 33 | 'description', 34 | 'project', 35 | 'budget', 36 | 'procurement_method' 37 | ] 38 | 39 | 40 | class EditBuyForm(forms.ModelForm): 41 | requirements = SimpleArrayField( 42 | forms.CharField(), 43 | delimiter='\n', 44 | help_text='Multiple requirements are allowed. Enter each one on its ' 45 | 'own line. Additional formatting, like bullet points, will ' 46 | 'be added later, so leave that out.', 47 | required=False, 48 | widget=forms.Textarea, 49 | ) 50 | skills_needed = SimpleArrayField( 51 | forms.CharField(), 52 | delimiter='\n', 53 | help_text='Multiple skills are allowed. Enter each one on its ' 54 | 'own line. Additional formatting, like bullet points, will ' 55 | 'be added later, so leave that out.', 56 | required=False, 57 | widget=forms.Textarea, 58 | ) 59 | 60 | def __init__(self, *args, **kwargs): 61 | super(EditBuyForm, self).__init__(*args, **kwargs) 62 | 63 | buy = kwargs['instance'] 64 | team_members = User.objects.filter(project=buy.project.id) 65 | self.fields['technical_evaluation_panel'].queryset = team_members 66 | self.fields['product_owner'].queryset = team_members 67 | self.fields['product_lead'].queryset = team_members 68 | self.fields['acquisition_lead'].queryset = team_members 69 | self.fields['technical_lead'].queryset = team_members 70 | 71 | class Meta: 72 | model = Buy 73 | fields = '__all__' 74 | widgets = { 75 | # 'description': AutoResizeTextarea(), 76 | 'base_period_length': DurationMultiWidget(), 77 | 'option_period_length': DurationMultiWidget(), 78 | # 'technical_evaluation_panel': forms.CheckboxSelectMultiple() 79 | } 80 | -------------------------------------------------------------------------------- /projects/templates/projects/buys.html: -------------------------------------------------------------------------------- 1 | {% extends "web/base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

Buys

7 | {% if perms.projects.view_project %}
Showing: public and non-public buys
{% endif %} 8 | {% if request.user.is_staff %}{% endif %} 9 |

Planning

10 |
11 | 12 |
13 |

Out for Bid

14 |
15 | 16 |
17 |

Awarded

18 |
19 | 20 |
21 |

Delivered

22 |
23 | 24 |
25 |
26 |
27 | 76 | {% endblock %} 77 | --------------------------------------------------------------------------------