[0-9]+)/delete$', views.ClipDeleteView.as_view(),
10 | name='clips-delete', robots_allow=False),
11 | ]
12 |
--------------------------------------------------------------------------------
/email_csv/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/email_csv/__init__.py
--------------------------------------------------------------------------------
/email_csv/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/email_csv/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class EmailCsvConfig(AppConfig):
5 | name = 'email_csv'
6 |
--------------------------------------------------------------------------------
/email_csv/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/email_csv/migrations/__init__.py
--------------------------------------------------------------------------------
/email_csv/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
--------------------------------------------------------------------------------
/email_csv/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/email_csv/urls.py:
--------------------------------------------------------------------------------
1 | from django2_url_robots.utils import url
2 | from . import views
3 |
4 | urlpatterns = [
5 | url(r'^$', views.email_csv,
6 | name='email-csv', robots_allow=False),
7 |
8 | ]
9 |
--------------------------------------------------------------------------------
/favicons/static/favicons/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/android-icon-144x144.png
--------------------------------------------------------------------------------
/favicons/static/favicons/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/android-icon-192x192.png
--------------------------------------------------------------------------------
/favicons/static/favicons/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/android-icon-36x36.png
--------------------------------------------------------------------------------
/favicons/static/favicons/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/android-icon-48x48.png
--------------------------------------------------------------------------------
/favicons/static/favicons/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/android-icon-72x72.png
--------------------------------------------------------------------------------
/favicons/static/favicons/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/android-icon-96x96.png
--------------------------------------------------------------------------------
/favicons/static/favicons/apple-touch-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/apple-touch-icon-114x114.png
--------------------------------------------------------------------------------
/favicons/static/favicons/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/favicons/static/favicons/apple-touch-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/apple-touch-icon-144x144.png
--------------------------------------------------------------------------------
/favicons/static/favicons/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/favicons/static/favicons/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/favicons/static/favicons/apple-touch-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/apple-touch-icon-57x57.png
--------------------------------------------------------------------------------
/favicons/static/favicons/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/favicons/static/favicons/apple-touch-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/apple-touch-icon-72x72.png
--------------------------------------------------------------------------------
/favicons/static/favicons/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/favicons/static/favicons/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
--------------------------------------------------------------------------------
/favicons/static/favicons/icon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/icon-16x16.png
--------------------------------------------------------------------------------
/favicons/static/favicons/icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/icon-192x192.png
--------------------------------------------------------------------------------
/favicons/static/favicons/icon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/icon-32x32.png
--------------------------------------------------------------------------------
/favicons/static/favicons/icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/icon-96x96.png
--------------------------------------------------------------------------------
/favicons/static/favicons/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/ms-icon-144x144.png
--------------------------------------------------------------------------------
/favicons/static/favicons/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/ms-icon-150x150.png
--------------------------------------------------------------------------------
/favicons/static/favicons/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/ms-icon-310x310.png
--------------------------------------------------------------------------------
/favicons/static/favicons/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/favicons/static/favicons/ms-icon-70x70.png
--------------------------------------------------------------------------------
/features/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/features/__init__.py
--------------------------------------------------------------------------------
/features/contact_partnerships.feature:
--------------------------------------------------------------------------------
1 | Feature: Visitor can submit a partnerships interest form
2 | Scenario: Visitor submits a minimal partnerships interest form
3 | Given that "/partnerships/get-in-touch" loads
4 | When the "name" text input is set to "Ziggy Stardust"
5 | And the "email" email input is set to "ziggy@mars.space"
6 | And the "organization_name" text input is set to "Spiders from Mars"
7 | And submit button in form "partnerships-contact-form" is clicked
8 | Then it should load "/partnerships/"
9 | And it should have the element ".flash.success" which says "Thanks for reaching out! Your message has been sent"
--------------------------------------------------------------------------------
/features/easy_audit.feature:
--------------------------------------------------------------------------------
1 | Feature: CRUD events are audited
2 | Background:
3 | Given a superuser
4 | And an org user at "ebclc"
5 |
6 | Scenario: Admin actions create CRUD events
7 | Given I log in as a superuser
8 | When I go to the admin edit page for "ebclc" user
9 | And I check "is_staff"
10 | And I select the "followup_staff" option in "groups_old"
11 | And I click "a#id_groups_add_link"
12 | And I click "input[name='_save']"
13 | Then the latest "auth.User" "update" event should have "superuser" as the user
14 | And the latest "auth.User" "update" event should have "True" for "is_staff"
15 | And the latest "auth.User" "m2m_change" event should have "2" ids in "groups"
16 |
--------------------------------------------------------------------------------
/features/search_applications.feature:
--------------------------------------------------------------------------------
1 | Feature: An org user can search for an application and navigate to its detail page
2 | As on org user, I want to quickly search for an application
3 | in order to check the case status
4 |
5 | Background:
6 | Given an org user at "ebclc"
7 | And "100" applications to "ebclc"
8 | And a "ebclc" application to search for
9 |
10 | Scenario: Org user can search for application and find details
11 | Given I log in as an org user at "ebclc"
12 | And that "/applications/" loads
13 | When I search for the applicant's name
14 | Then I should see the applicant's name in search results
15 | When I click on the applicant's search result
16 | Then it should load the applicant's detail page
17 |
--------------------------------------------------------------------------------
/features/search_followups.feature:
--------------------------------------------------------------------------------
1 | Feature: A staff user can search for and modify submissions
2 | As CfA staff, I want to quickly search for an applicant
3 | in order to add a note and provide case support for applicants.
4 |
5 | Background:
6 | Given an applicant support user
7 | And "100" applications
8 | And an applicant to search for
9 |
10 | Scenario: CfA user can find applicant and add a note
11 | Given I log in as an applicant support user
12 | And that "/applications/" loads
13 | When I search for the applicant's name
14 | Then I should see the applicant's followup row
15 | And the create note form should be visible
16 | When I add a note about the applicant's case
17 | Then the note should be visible
18 |
--------------------------------------------------------------------------------
/features/stats.feature:
--------------------------------------------------------------------------------
1 | Feature: StatsPage Loads
2 | Scenario: Has static assets
3 | Given that "/stats/" loads
4 | And it loads css
5 |
--------------------------------------------------------------------------------
/features/steps/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/features/steps/__init__.py
--------------------------------------------------------------------------------
/features/steps/debugging_hacks.py:
--------------------------------------------------------------------------------
1 | from behave import then
2 |
3 |
4 | @then('I need to debug')
5 | def test_debugging(context):
6 | print("\n---------------------------------")
7 | print("HTML in the browser")
8 | print(context.browser.page_source)
9 | print("\n---------------------------------")
10 | assert False
11 |
--------------------------------------------------------------------------------
/features/steps/language_hacks.py:
--------------------------------------------------------------------------------
1 | """A utility module turning English into machine-readable data."""
2 |
3 |
4 | def oxford_comma_text_to_list(phrase):
5 | """Examples:
6 | - 'Eeeny, Meeny, Miney, and Moe' --> ['Eeeny', 'Meeny', 'Miney', 'Moe']
7 | - 'Black and White' --> ['Black', 'White']
8 | - 'San Francisco and Saint Francis' -->
9 | ['San Francisco', 'Saint Francisco']
10 | """
11 | items = []
12 | for subphrase in phrase.split(', '):
13 | items.extend(
14 | [item.strip() for item in subphrase.split(' and ')])
15 | return items
16 |
--------------------------------------------------------------------------------
/formation/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/formation/__init__.py
--------------------------------------------------------------------------------
/formation/exceptions.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class RawDataMustBeDictError(Exception):
4 | """Raise this if the input raw data for
5 | forms or form fields is not a dict or dict descendant
6 | (MultiValueDict, QueryDict)
7 | """
8 | pass
9 |
10 |
11 | class NoChoicesGivenError(Exception):
12 | """Raise this when a field that operates on a set of
13 | choices is instantiated without any choices.
14 | """
15 | pass
16 |
17 |
18 | class MultiValueFieldSubfieldError(NotImplementedError):
19 | """Raise this when someone tries to instantiate a
20 | MultiValueField without a defined `subfields` attribute
21 | """
22 | pass
23 |
24 |
25 | class InvalidPhoneNumberException(Exception):
26 | """Raise this when an invalid phone number is found
27 | """
28 | pass
29 |
--------------------------------------------------------------------------------
/formation/templates/formation/address_display.jinja:
--------------------------------------------------------------------------------
1 |
2 |
{{ field.get_display_label() }}
3 | {%- if not field.is_empty() %}
4 |
5 |
{{ field.get_display_value() }}
6 | {%- else %}
7 |
8 | {%- endif %}
9 |
--------------------------------------------------------------------------------
/formation/templates/formation/counties_display.jinja:
--------------------------------------------------------------------------------
1 |
2 |
{{ field.get_display_label() }}
3 | {%- if not field.is_empty() %}
4 |
5 | {{ field.get_display_value(unlisted_counties=unlisted_counties) }}
6 |
7 | {%- else %}
8 |
9 | {%- endif %}
10 |
--------------------------------------------------------------------------------
/formation/templates/formation/default_form_display.jinja:
--------------------------------------------------------------------------------
1 | {%- for field in form.get_usable_fields() %}
2 | {{ field.display() }}
3 | {%- endfor %}
--------------------------------------------------------------------------------
/formation/templates/formation/default_input_display.jinja:
--------------------------------------------------------------------------------
1 |
2 |
{{ field.get_display_label() }}
3 | {%- if not field.is_empty() %}
4 |
{{ field.get_display_value() }}
5 | {%- else %}
6 |
7 | {%- endif %}
8 |
--------------------------------------------------------------------------------
/formation/templates/formation/email_display.jinja:
--------------------------------------------------------------------------------
1 |
2 |
{{ field.get_display_label() }}
3 | {%- if not field.is_empty() %}
4 |
9 | {%- else %}
10 |
11 | {%- endif %}
12 |
--------------------------------------------------------------------------------
/formation/templates/formation/example.html:
--------------------------------------------------------------------------------
1 | {{ message }}
--------------------------------------------------------------------------------
/formation/templates/formation/generic_form.jinja:
--------------------------------------------------------------------------------
1 |
2 | {% for field in form.iter_fields() %}
3 | {{ field.render()|indent(4)|safe }}
4 | {% endfor %}
5 |
--------------------------------------------------------------------------------
/formation/templates/formation/messages_list.jinja:
--------------------------------------------------------------------------------
1 | {%- if field.errors -%}
2 |
3 | {%- for error in field.get_errors_list() -%}
4 |
5 | {{ error }}
6 |
7 | {%- endfor -%}
8 |
9 | {%- endif -%}
10 |
11 | {%- if field.warnings -%}
12 |
13 | {%- for warning in field.get_warnings_list() -%}
14 |
15 | {{ warning }}
16 |
17 | {%- endfor -%}
18 |
19 | {%- endif -%}
--------------------------------------------------------------------------------
/formation/templates/formation/option_set_display.jinja:
--------------------------------------------------------------------------------
1 |
2 |
{{ field.get_display_label() }}
3 | {%- if not field.is_empty() %}
4 |
5 | {%- for option, option_display in field.get_display_choices() %}
6 |
10 | {{ field.get_display_for_choice(option) }}
11 |
12 | {%- endfor %}
13 |
14 | {%- else %}
15 |
16 | {%- endif %}
17 |
--------------------------------------------------------------------------------
/formation/templates/formation/phone_display.jinja:
--------------------------------------------------------------------------------
1 |
2 |
{{ field.get_display_label() }}
3 | {%- set display_value = field.get_display_value() %}
4 | {%- if display_value %}
5 |
6 | {%- if field.get_current_value_parsed() %}
7 |
8 | {{- display_value -}}
9 |
10 | {%- else %}
11 |
{{- display_value -}}
12 | {%- endif %}
13 |
14 | {%- else %}
15 |
16 | {%- endif %}
17 |
--------------------------------------------------------------------------------
/formation/templates/formation/textarea_field.jinja:
--------------------------------------------------------------------------------
1 | {% extends "formation/text_input.jinja" -%}
2 | {%- block input_widget %}
3 |
8 | {%- endblock input_widget %}
--------------------------------------------------------------------------------
/formation/templates/formation/url_display.jinja:
--------------------------------------------------------------------------------
1 |
2 |
{{ field.get_display_label() }}
3 | {%- if not field.is_empty() %}
4 |
9 | {%- else %}
10 |
11 | {%- endif %}
12 |
--------------------------------------------------------------------------------
/formation/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/formation/tests/__init__.py
--------------------------------------------------------------------------------
/formation/tests/utils.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import sys
3 |
4 |
5 | class PatchTranslationTestCase(unittest.TestCase):
6 |
7 | def setUp(self):
8 | self.add_apps_mock = unittest.mock.patch(
9 | 'django.utils.translation.trans_real.'
10 | 'DjangoTranslation._add_installed_apps_translations')
11 | self.add_apps_mock.start()
12 |
13 | def tearDown(self):
14 | self.add_apps_mock.stop()
15 |
16 |
17 | django_only = unittest.skipUnless(
18 | any('manage.py' in arg for arg in sys.argv),
19 | 'For Django test runner only')
20 |
--------------------------------------------------------------------------------
/health_check/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/health_check/__init__.py
--------------------------------------------------------------------------------
/health_check/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/health_check/tests/__init__.py
--------------------------------------------------------------------------------
/health_check/tests/test_urls.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 | from django.urls import reverse
3 | from user_accounts.tests.mock import fake_superuser, fake_password
4 |
5 |
6 | class TestURLPatterns(TestCase):
7 |
8 | def test_ok(self):
9 | response = self.client.get(reverse('health_check-ok'))
10 | self.assertEqual(response.status_code, 200)
11 | self.assertContains(response, "Everything seems fine")
12 |
13 | def test_error(self):
14 | su = fake_superuser()
15 | self.client.login(username=su.username, password=fake_password)
16 | with self.assertRaises(Exception) as context:
17 | response = self.client.get(reverse('health_check-error'))
18 | self.assertTrue('This is a Test' in context.exception)
19 |
--------------------------------------------------------------------------------
/health_check/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 | from django.contrib.auth.decorators import user_passes_test
3 | from django.http import HttpResponse
4 |
5 |
6 | def ok(request, *args, **kwargs):
7 | return HttpResponse("Everything seems fine", status=200)
8 |
9 |
10 | @user_passes_test(lambda u: u.is_superuser)
11 | def error(request, *args, **kwargs):
12 | raise Exception("This is a Test")
13 |
14 |
15 | urlpatterns = [
16 | url(r'^$', ok, name='health_check-ok'),
17 | url(r'^error$', error, name='health_check-error'),
18 | ]
19 |
--------------------------------------------------------------------------------
/helper_commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/helper_commands/__init__.py
--------------------------------------------------------------------------------
/helper_commands/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class HelperCommandsConfig(AppConfig):
5 | name = 'helper_commands'
6 |
--------------------------------------------------------------------------------
/helper_commands/management/commands/run_debug_task.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 | from intake.tasks import debug_task
3 |
4 |
5 | class Command(BaseCommand):
6 | help = str(
7 | "[THIS IS NOT FOR USE ON PERSONAL MACHINES]"
8 | "Downloads from s3 and loads data.")
9 |
10 | def handle(self, *args, **kwargs):
11 | debug_task('test single arguement')
12 |
--------------------------------------------------------------------------------
/intake/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | default_app_config = 'intake.apps.IntakeConfig'
3 |
--------------------------------------------------------------------------------
/intake/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from intake import models
3 |
4 |
5 | @admin.register(models.FillablePDF)
6 | class FillablePDFAdmin(admin.ModelAdmin):
7 | pass
8 |
9 |
10 | @admin.register(models.County)
11 | class CountyAdmin(admin.ModelAdmin):
12 | pass
13 |
14 |
15 | @admin.register(models.StatusType)
16 | class StatusTypeAdmin(admin.ModelAdmin):
17 | pass
18 |
19 |
20 | @admin.register(models.NextStep)
21 | class NextStepAdmin(admin.ModelAdmin):
22 | pass
23 |
24 |
25 | @admin.register(models.StatusUpdate)
26 | class StatusUpdateAdmin(admin.ModelAdmin):
27 | pass
28 |
29 |
30 | @admin.register(models.StatusNotification)
31 | class StatusNotificationAdmin(admin.ModelAdmin):
32 | pass
33 |
--------------------------------------------------------------------------------
/intake/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class IntakeConfig(AppConfig):
5 | name = 'intake'
6 |
--------------------------------------------------------------------------------
/intake/fixtures/0015_add_default_counties_data.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "model": "intake.county",
4 | "pk": 1,
5 | "fields": {
6 | "slug": "sanfrancisco",
7 | "name": "San Francisco",
8 | "description": "San Francisco"
9 | }
10 | },
11 | {
12 | "model": "intake.county",
13 | "pk": 2,
14 | "fields": {
15 | "slug": "contracosta",
16 | "name": "Contra Costa",
17 | "description": "Conta Costa County (near Richmond, Concord, Walnut Creek, San Ramon, Antioch, or Brentwood)"
18 | }
19 | },
20 | {
21 | "model": "intake.county",
22 | "pk": 3,
23 | "fields": {
24 | "slug": "alameda",
25 | "name": "Alameda",
26 | "description": "Alameda County (near Oakland, Berkeley, San Leandro, Hayward, Union City, Pleasanton, or Livermore)"
27 | }
28 | }
29 | ]
30 |
--------------------------------------------------------------------------------
/intake/forms/__init__.py:
--------------------------------------------------------------------------------
1 | from .status_update_forms import (
2 | StatusUpdateForm, StatusNotificationForm,
3 | NotificationContactInfoDisplayForm)
4 | from .application_transfer_form import ApplicationTransferForm
5 |
6 | __all__ = [
7 | StatusUpdateForm,
8 | StatusNotificationForm,
9 | NotificationContactInfoDisplayForm,
10 | ApplicationTransferForm
11 | ]
12 |
--------------------------------------------------------------------------------
/intake/groups.py:
--------------------------------------------------------------------------------
1 | FOLLOWUP_STAFF = 'followup_staff'
2 | APPLICATION_REVIEWERS = 'application_reviewers'
3 | PERFORMANCE_MONITORS = 'performance_monitors'
4 |
--------------------------------------------------------------------------------
/intake/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/management/__init__.py
--------------------------------------------------------------------------------
/intake/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/management/commands/__init__.py
--------------------------------------------------------------------------------
/intake/management/commands/heroku_release.py:
--------------------------------------------------------------------------------
1 | from django.core import management
2 | from django.core.management.base import BaseCommand
3 |
4 |
5 | class Command(BaseCommand):
6 | help = str(
7 | "Migrates and loads essential data from fixtures")
8 |
9 | def handle(self, *args, **kwargs):
10 | management.call_command('migrate')
11 | management.call_command('load_essential_data')
12 |
--------------------------------------------------------------------------------
/intake/management/commands/load_2000_mock_submissions.py:
--------------------------------------------------------------------------------
1 | from django.core.management import BaseCommand
2 |
3 | from intake.tests.mock import build_2000_mock_submissions
4 |
5 |
6 | class Command(BaseCommand):
7 | help = 'Generates new json sample fixtures'
8 |
9 | def handle(self, *args, **options):
10 | build_2000_mock_submissions()
11 | self.stdout.write(
12 | self.style.SUCCESS(
13 | "Created fake submissions, bundles, and transfers "
14 | "and saved them to fixture files"))
15 |
--------------------------------------------------------------------------------
/intake/management/commands/load_essential_data.py:
--------------------------------------------------------------------------------
1 | from django.core import management
2 | from django.core.management.base import BaseCommand
3 | from project.fixtures_index import ESSENTIAL_DATA_FIXTURES
4 |
5 |
6 | class Command(BaseCommand):
7 | help = str(
8 | "Loads 'essential' data from fixture files")
9 |
10 | def handle(self, *args, **kwargs):
11 | management.call_command('loaddata', *ESSENTIAL_DATA_FIXTURES)
12 |
--------------------------------------------------------------------------------
/intake/management/commands/load_mock_data.py:
--------------------------------------------------------------------------------
1 | from django.core import management
2 | from django.core.management.base import BaseCommand
3 | from intake.models import pdfs
4 | from intake.tests import mock
5 | from project.fixtures_index import ALL_MOCK_DATA_FIXTURES
6 |
7 |
8 | class Command(BaseCommand):
9 | help = str(
10 | "Loads mock data from fixture files")
11 |
12 | def handle(self, *args, **kwargs):
13 | management.call_command(
14 | 'loaddata', *ALL_MOCK_DATA_FIXTURES)
15 | if pdfs.FillablePDF.objects.count() == 0:
16 | mock.fillable_pdf()
17 |
--------------------------------------------------------------------------------
/intake/management/commands/prepare_review_env.py:
--------------------------------------------------------------------------------
1 | from django.core import management
2 | from django.core.management.base import BaseCommand
3 |
4 |
5 | class Command(BaseCommand):
6 | help = str(
7 | "Run commands required to set up a review application environment")
8 |
9 | def handle(self, *args, **kwargs):
10 | management.call_command('migrate', 'easyaudit')
11 | management.call_command('new_fixtures')
12 |
--------------------------------------------------------------------------------
/intake/management/commands/send_followups.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 | import intake.services.followups as FollowupsService
3 | from intake.utils import is_the_weekend
4 |
5 |
6 | class Command(BaseCommand):
7 | help = 'Sends an email about unopened applications'
8 |
9 | def handle(self, *args, **options):
10 | if not is_the_weekend():
11 | FollowupsService.send_all_followups_that_are_due(after_id=465)
12 | self.stdout.write(
13 | self.style.SUCCESS("Successfully sent followups")
14 | )
15 |
--------------------------------------------------------------------------------
/intake/management/commands/send_unopened_apps_notification.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | import intake.services.bundles as BundlesService
4 |
5 |
6 | class Command(BaseCommand):
7 | help = 'Sends an email about unopened applications'
8 |
9 | def handle(self, *args, **options):
10 | BundlesService.count_unreads_and_send_notifications_to_orgs()
11 | self.stdout.write(
12 | self.style.SUCCESS("Successfully referred any unopened apps")
13 | )
14 |
--------------------------------------------------------------------------------
/intake/management/commands/test_fillpdf.py:
--------------------------------------------------------------------------------
1 | from django.core import management
2 | from django.core.management.base import BaseCommand
3 |
4 | from intake.models import pdfs
5 | from intake.models import form_submission
6 |
7 |
8 | class Command(BaseCommand):
9 | help = str(
10 | "Sets up seeds based on what environment it runs in.")
11 |
12 | def handle(self, *args, **kwargs):
13 | fillable = pdfs.FillablePDF.objects.first()
14 | sub = form_submission.FormSubmission.objects.first()
15 | filled = fillable.fill_for_submission(sub)
16 | print(filled)
17 |
--------------------------------------------------------------------------------
/intake/migrations/0002_fillablepdf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9 on 2016-05-09 00:00
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 | ('intake', '0001_initial'),
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name='FillablePDF',
17 | fields=[
18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19 | ('pdf', models.FileField(upload_to='pdfs/')),
20 | ('translator', models.TextField()),
21 | ],
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/intake/migrations/0003_fillablepdf_name.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9 on 2016-05-09 00: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 | ('intake', '0002_fillablepdf'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='fillablepdf',
17 | name='name',
18 | field=models.CharField(default='Sample pdf', max_length=50),
19 | preserve_default=False,
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/intake/migrations/0009_auto_20160615_2323.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.7 on 2016-06-15 23:23
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('intake', '0008_auto_20160615_2307'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterModelOptions(
16 | name='formsubmission',
17 | options={'ordering': ['-date_received']},
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/intake/migrations/0011_confirmationsentlogentry_message_sent.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.7 on 2016-07-06 20:09
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 | ('intake', '0010_auto_20160706_2000'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='confirmationsentlogentry',
17 | name='message_sent',
18 | field=models.TextField(blank=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/intake/migrations/0012_auto_20160706_2010.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.7 on 2016-07-06 20:10
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('intake', '0011_confirmationsentlogentry_message_sent'),
12 | ]
13 |
14 | operations = [
15 | migrations.RenameModel(
16 | old_name='ConfirmationSentLogEntry',
17 | new_name='ApplicantContactedLogEntry',
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/intake/migrations/0014_county_name.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.9 on 2016-08-16 18: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 | ('intake', '0013_add_county_model'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='county',
17 | name='name',
18 | field=models.TextField(default='San Francisco'),
19 | preserve_default=False,
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/intake/migrations/0016_applicationlogentry_organization.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.9 on 2016-08-12 22:46
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 | ('user_accounts', '0008_add_profiles_related_name_to_organization'),
13 | ('intake', '0015_add_default_counties'),
14 | ]
15 |
16 | operations = [
17 | migrations.AddField(
18 | model_name='applicationlogentry',
19 | name='organization',
20 | field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='logs', to='user_accounts.Organization'),
21 | ),
22 | ]
23 |
--------------------------------------------------------------------------------
/intake/migrations/0017_fillablepdf_organization.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.9 on 2016-08-12 23:02
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 | ('user_accounts', '0008_add_profiles_related_name_to_organization'),
13 | ('intake', '0016_applicationlogentry_organization'),
14 | ]
15 |
16 | operations = [
17 | migrations.AddField(
18 | model_name='fillablepdf',
19 | name='organization',
20 | field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='pdfs', to='user_accounts.Organization'),
21 | ),
22 | ]
23 |
--------------------------------------------------------------------------------
/intake/migrations/0020_formsubmission_organizations.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.9 on 2016-08-18 18: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 | ('user_accounts', '0010_add_slugs_to_orgs'),
12 | ('intake', '0019_update_contact_preferences_answer_data'),
13 | ]
14 |
15 | operations = [
16 | migrations.AddField(
17 | model_name='formsubmission',
18 | name='organizations',
19 | field=models.ManyToManyField(related_name='submissions', to='user_accounts.Organization'),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/intake/migrations/0024_app_bundle_pdf_not_required.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.9 on 2016-08-30 23:23
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 | ('intake', '0023_applicationbundle'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='applicationbundle',
17 | name='bundled_pdf',
18 | field=models.FileField(blank=True, null=True, upload_to='pdf_bundles/'),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/intake/migrations/0025_remove_formsubmission_counties.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.9 on 2016-09-02 20:53
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('intake', '0024_app_bundle_pdf_not_required'),
12 | ]
13 |
14 | operations = [
15 | migrations.RemoveField(
16 | model_name='formsubmission',
17 | name='counties',
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/intake/migrations/0026_applicationlogentry_add_transfer_type.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.9 on 2016-09-20 01:30
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 | ('intake', '0025_remove_formsubmission_counties'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='applicationlogentry',
17 | name='event_type',
18 | field=models.PositiveSmallIntegerField(choices=[(1, 'opened'), (2, 'referred'), (3, 'processed'), (4, 'deleted'), (5, 'sent confirmation'), (6, 'referred to another org')]),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/intake/migrations/0028_formsubmission_applicant.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.9 on 2016-09-20 22:05
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 | ('intake', '0027_applicant_applicationevent'),
13 | ]
14 |
15 | operations = [
16 | migrations.AddField(
17 | model_name='formsubmission',
18 | name='applicant',
19 | field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='form_submissions', to='intake.Applicant'),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/intake/migrations/0029_applicationevent_order_by_time.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.1 on 2016-10-07 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 | ('intake', '0028_formsubmission_applicant'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterModelOptions(
16 | name='applicationevent',
17 | options={'ordering': ['-time']},
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/intake/migrations/0031_add_view_app_stats_permission.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.1 on 2016-12-04 00:00
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('intake', '0030_add_visitor_model'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterModelOptions(
16 | name='applicant',
17 | options={'permissions': (('view_app_stats', 'Can see detailed aggregate information about apps'),)},
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/intake/migrations/0032_add_view_app_details_permission.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.1 on 2016-12-04 00:54
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('intake', '0031_add_view_app_stats_permission'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterModelOptions(
16 | name='applicant',
17 | options={'permissions': (('view_app_stats', 'Can see detailed aggregate information about apps'), ('view_app_details', 'Can see detail information about individual apps'))},
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/intake/migrations/0033_visitor_ip_address.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.1 on 2016-12-07 04: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 | ('intake', '0032_add_view_app_details_permission'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='visitor',
17 | name='ip_address',
18 | field=models.TextField(null=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/intake/migrations/0036_add_view_app_notes_permission.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.1 on 2016-12-27 23:04
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('intake', '0035_applicationnote'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterModelOptions(
16 | name='applicationnote',
17 | options={'ordering': ['-created'], 'permissions': (('intake.view_application_note', 'Can read the contents of notes from followups'),)},
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/intake/migrations/0041_enforce_unique_slugs.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.5 on 2017-01-24 18:58
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 | ('intake', '0040_create_status_notification'),
13 | ]
14 |
15 | operations = [
16 | migrations.AlterField(
17 | model_name='nextstep',
18 | name='slug',
19 | field=models.SlugField(unique=True),
20 | ),
21 | migrations.AlterField(
22 | model_name='statustype',
23 | name='slug',
24 | field=models.SlugField(unique=True),
25 | ),
26 | ]
27 |
--------------------------------------------------------------------------------
/intake/migrations/0043_status_update_related_name.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.1 on 2017-01-25 18:04
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 | ('intake', '0042_fix_permissions_and_non_db_model_updates'),
13 | ]
14 |
15 | operations = [
16 | migrations.AlterField(
17 | model_name='statusupdate',
18 | name='application',
19 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='status_updates', to='intake.Application'),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/intake/migrations/0044_one_to_one_mapping_between_status_update_and_notification.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.5 on 2017-01-26 00:16
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 | ('intake', '0043_status_update_related_name'),
13 | ]
14 |
15 | operations = [
16 | migrations.AlterField(
17 | model_name='statusnotification',
18 | name='status_update',
19 | field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='notification', to='intake.StatusUpdate'),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/intake/migrations/0045_add_is_active_to_template_options.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.5 on 2017-01-27 18:31
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 | ('intake', '0044_one_to_one_mapping_between_status_update_and_notification'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='nextstep',
17 | name='is_active',
18 | field=models.BooleanField(default=True),
19 | ),
20 | migrations.AddField(
21 | model_name='statustype',
22 | name='is_active',
23 | field=models.BooleanField(default=True),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/intake/migrations/0049_template_option_is_a_status_update_choice.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.1 on 2017-03-10 00:24
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 | ('intake', '0048_template_field_validators'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='nextstep',
17 | name='is_a_status_update_choice',
18 | field=models.BooleanField(default=True),
19 | ),
20 | migrations.AddField(
21 | model_name='statustype',
22 | name='is_a_status_update_choice',
23 | field=models.BooleanField(default=True),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/intake/migrations/0050_application_created_updated.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.1 on 2017-03-24 18: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 | ('intake', '0049_template_option_is_a_status_update_choice'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='application',
17 | name='created',
18 | field=models.DateTimeField(null=True),
19 | ),
20 | migrations.AddField(
21 | model_name='application',
22 | name='updated',
23 | field=models.DateTimeField(null=True),
24 | )
25 | ]
26 |
--------------------------------------------------------------------------------
/intake/migrations/0055_visitor_uuid.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10 on 2017-04-25 23:02
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 | import uuid
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('intake', '0054_graduate_additional_fields'),
13 | ]
14 |
15 | operations = [
16 | migrations.AddField(
17 | model_name='visitor',
18 | name='uuid',
19 | field=models.UUIDField(default=uuid.uuid4, editable=False),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/intake/migrations/0057_applicant_visitor_onetoone.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10 on 2017-04-26 01:05
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 | ('intake', '0056_backfill_visitors_for_applicants'),
13 | ]
14 |
15 | operations = [
16 | migrations.AlterField(
17 | model_name='applicant',
18 | name='visitor',
19 | field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='intake.Visitor'),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/intake/migrations/0060_visitor_locale_user_agent.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.7 on 2017-07-18 22:25
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 | ('intake', '0059_prebuiltpdfbundle'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='visitor',
17 | name='locale',
18 | field=models.TextField(default=''),
19 | ),
20 | migrations.AddField(
21 | model_name='visitor',
22 | name='user_agent',
23 | field=models.TextField(default=''),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/intake/migrations/0071_add_display_order_to_template_option.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.8 on 2017-10-03 20: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 | ('intake', '0070_formsubmission_unlisted_counties'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='nextstep',
17 | name='display_order',
18 | field=models.IntegerField(default=0),
19 | ),
20 | migrations.AddField(
21 | model_name='statustype',
22 | name='display_order',
23 | field=models.IntegerField(default=0),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/intake/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/migrations/__init__.py
--------------------------------------------------------------------------------
/intake/models/abstract_base_models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class BaseModel(models.Model):
5 | """An abstract base model that includes default fields for any table
6 | """
7 | # these must be null = True because they will be added to preexisting
8 | # models
9 | created = models.DateTimeField(auto_now_add=True, null=True)
10 | updated = models.DateTimeField(auto_now=True, null=True)
11 |
12 | class Meta:
13 | abstract = True
14 |
--------------------------------------------------------------------------------
/intake/models/application_transfer.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from .abstract_base_models import BaseModel
3 |
4 |
5 | class ApplicationTransfer(BaseModel):
6 | """A record that links a 'Transferred' status update to the new application
7 | created from the transfer.
8 | """
9 | status_update = models.OneToOneField(
10 | 'intake.StatusUpdate',
11 | models.CASCADE,
12 | related_name='transfer')
13 | new_application = models.ForeignKey(
14 | 'intake.Application',
15 | models.PROTECT,
16 | related_name='incoming_transfers')
17 | reason = models.TextField(blank=True)
18 |
19 | def __str__(self):
20 | return '{} because "{}"'.format(
21 | self.status_update.__str__(),
22 | self.reason)
23 |
--------------------------------------------------------------------------------
/intake/models/fields.py:
--------------------------------------------------------------------------------
1 | from django.contrib.postgres.fields import JSONField
2 | from intake import validators
3 |
4 |
5 | class ContactInfoJSONField(JSONField):
6 | """
7 | A field for storing contact information that validates
8 | data against expected keys and structure
9 | """
10 |
11 | def validate(self, value, model_instance):
12 | validators.contact_info_json(value)
13 | super().validate(value, model_instance)
14 |
--------------------------------------------------------------------------------
/intake/models/next_step.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from .template_option import TemplateOption, TemplateOptionManager
3 |
4 |
5 | class PurgedNextStep(models.Model):
6 | """Placeholder for custom VIEW see intake migration 0067
7 | """
8 | class Meta:
9 | db_table = 'purged\".\"intake_nextstep'
10 | managed = False
11 |
12 |
13 | class NextStep(TemplateOption):
14 | objects = TemplateOptionManager()
15 |
--------------------------------------------------------------------------------
/intake/models/status_type.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from .template_option import TemplateOption, TemplateOptionManager
3 |
4 |
5 | class PurgedStatusType(models.Model):
6 | """Placeholder for custom VIEW see intake migration 0067
7 | """
8 | class Meta:
9 | db_table = 'purged\".\"intake_statustype'
10 | managed = False
11 |
12 |
13 | class StatusType(TemplateOption):
14 | objects = TemplateOptionManager()
15 |
--------------------------------------------------------------------------------
/intake/pdfparser.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/pdfparser.jar
--------------------------------------------------------------------------------
/intake/permissions.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.models import Permission
2 |
3 | # apps
4 | CAN_SEE_APP_STATS = 'view_app_stats'
5 | CAN_SEE_APP_DETAILS = 'view_app_details'
6 |
7 | # notes
8 | CAN_SEE_FOLLOWUP_NOTES = 'view_application_note'
9 |
10 |
11 | def get_all_followup_permissions():
12 | return Permission.objects.filter(
13 | codename__in=[
14 | CAN_SEE_FOLLOWUP_NOTES,
15 | 'add_applicationnote',
16 | 'delete_applicationnote'])
17 |
--------------------------------------------------------------------------------
/intake/serializers/applicant_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 | from intake.serializers.fields import ChainableAttributeField
3 |
4 |
5 | class ApplicantMixpanelSerializer(serializers.Serializer):
6 | """This serializes user information from an applicant instance
7 | """
8 | applicant_source = ChainableAttributeField('visitor.source')
9 | applicant_referrer = ChainableAttributeField('visitor.referrer')
10 |
--------------------------------------------------------------------------------
/intake/serializers/organization_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 | from user_accounts.models import Organization
3 |
4 |
5 | class OrganizationFollowupSerializer(serializers.ModelSerializer):
6 | county = serializers.SlugRelatedField(read_only=True, slug_field='name')
7 |
8 | class Meta:
9 | model = Organization
10 | fields = [
11 | 'slug', 'name', 'county',
12 | 'short_followup_message',
13 | 'long_followup_message']
14 |
15 |
16 | class OrganizationSerializer(serializers.ModelSerializer):
17 |
18 | class Meta:
19 | model = Organization
20 | fields = ['slug', 'name', 'is_live']
21 |
--------------------------------------------------------------------------------
/intake/serializers/shortcuts.py:
--------------------------------------------------------------------------------
1 | from .applicant_serializer import ApplicantMixpanelSerializer
2 | from .request_serializer import RequestSerializer
3 | from .view_serializer import ViewMixpanelSerializer
4 |
5 |
6 | def mixpanel_applicant_data(applicant):
7 | return ApplicantMixpanelSerializer(applicant).data
8 |
9 |
10 | def mixpanel_request_data(request):
11 | return RequestSerializer(request).data
12 |
13 |
14 | def mixpanel_view_data(view):
15 | return ViewMixpanelSerializer(view).data
16 |
--------------------------------------------------------------------------------
/intake/serializers/tag_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 | from taggit.models import Tag
3 |
4 |
5 | class TagSerializer(serializers.ModelSerializer):
6 |
7 | class Meta:
8 | model = Tag
9 | fields = ['id', 'name']
10 |
--------------------------------------------------------------------------------
/intake/serializers/view_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 | from .fields import ChainableAttributeField
3 | from intake.constants import LANGUAGES_LOOKUP
4 |
5 |
6 | class ViewMixpanelSerializer(serializers.Serializer):
7 | view_name = ChainableAttributeField('__class__.__name__')
8 |
--------------------------------------------------------------------------------
/intake/service_objects/__init__.py:
--------------------------------------------------------------------------------
1 | from .applicant_notifications import (
2 | FollowupNotification,
3 | ConfirmationNotification
4 | )
5 |
6 | __all__ = [
7 | FollowupNotification,
8 | ConfirmationNotification
9 | ]
10 |
--------------------------------------------------------------------------------
/intake/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/services/__init__.py
--------------------------------------------------------------------------------
/intake/services/messages_service.py:
--------------------------------------------------------------------------------
1 | from django.contrib import messages
2 |
3 |
4 | def flash_errors(request, *errors):
5 | for error in errors:
6 | messages.error(request, error)
7 |
8 |
9 | def flash_success(request, *success_messages):
10 | for success in success_messages:
11 | messages.success(request, success)
12 |
13 |
14 | def flash_warnings(request, *warning_messages):
15 | for warning in warning_messages:
16 | messages.warning(request, warning)
17 |
--------------------------------------------------------------------------------
/intake/services/pagination.py:
--------------------------------------------------------------------------------
1 | from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
2 |
3 |
4 | def get_page(qset, page_index, max_count_per_page=25, min_count_per_page=5):
5 | paginator = Paginator(
6 | qset, max_count_per_page, orphans=min_count_per_page)
7 | try:
8 | return paginator.page(page_index)
9 | except PageNotAnInteger:
10 | return paginator.page(1)
11 | except EmptyPage:
12 | if int(page_index) <= 0:
13 | return paginator.page(1)
14 | else:
15 | return paginator.page(paginator.num_pages)
16 |
17 |
18 | def get_serialized_page(qset, serializer, page_index, **kwargs):
19 | page = get_page(qset, page_index, **kwargs)
20 | page.object_list = serializer(page.object_list, many=True).data
21 | return page
22 |
--------------------------------------------------------------------------------
/intake/static/intake/fonts:
--------------------------------------------------------------------------------
1 | ../../../node_modules/bootstrap/fonts/
--------------------------------------------------------------------------------
/intake/static/intake/icomoon/icomoon.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/icomoon/icomoon.eot
--------------------------------------------------------------------------------
/intake/static/intake/icomoon/icomoon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/icomoon/icomoon.ttf
--------------------------------------------------------------------------------
/intake/static/intake/icomoon/icomoon.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/icomoon/icomoon.woff
--------------------------------------------------------------------------------
/intake/static/intake/img/10_minutes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/10_minutes.png
--------------------------------------------------------------------------------
/intake/static/intake/img/10_minutes@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/10_minutes@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/CMR-hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/CMR-hero.png
--------------------------------------------------------------------------------
/intake/static/intake/img/CMR_share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/CMR_share.png
--------------------------------------------------------------------------------
/intake/static/intake/img/CMR_social_thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/CMR_social_thumbnail.png
--------------------------------------------------------------------------------
/intake/static/intake/img/alameda_seal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/alameda_seal.png
--------------------------------------------------------------------------------
/intake/static/intake/img/alameda_seal@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/alameda_seal@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/ben-golder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/ben-golder.jpg
--------------------------------------------------------------------------------
/intake/static/intake/img/bundle-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/bundle-icon.png
--------------------------------------------------------------------------------
/intake/static/intake/img/bundle-icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/bundle-icon@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/ca.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/ca.png
--------------------------------------------------------------------------------
/intake/static/intake/img/ca@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/ca@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/cfa-logo-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/cfa-logo-black.png
--------------------------------------------------------------------------------
/intake/static/intake/img/cfa-logo-black@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/cfa-logo-black@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/cfa_logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/cfa_logo@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/cfa_logo_color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/cfa_logo_color.png
--------------------------------------------------------------------------------
/intake/static/intake/img/cfa_logo_color@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/cfa_logo_color@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/cfa_logo_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/cfa_logo_white.png
--------------------------------------------------------------------------------
/intake/static/intake/img/cmr_logo_black_cropped.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/cmr_logo_black_cropped.png
--------------------------------------------------------------------------------
/intake/static/intake/img/cmr_logo_black_cropped@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/cmr_logo_black_cropped@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/contra_costa_seal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/contra_costa_seal.png
--------------------------------------------------------------------------------
/intake/static/intake/img/contra_costa_seal@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/contra_costa_seal@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/eligibility-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/eligibility-icon.png
--------------------------------------------------------------------------------
/intake/static/intake/img/eligibility-icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/eligibility-icon@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/fresno_seal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/fresno_seal.png
--------------------------------------------------------------------------------
/intake/static/intake/img/fresno_seal@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/fresno_seal@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/geometry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/geometry.png
--------------------------------------------------------------------------------
/intake/static/intake/img/jazmyn-latimer.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/jazmyn-latimer.jpg
--------------------------------------------------------------------------------
/intake/static/intake/img/job_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/job_search.png
--------------------------------------------------------------------------------
/intake/static/intake/img/job_search@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/job_search@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/ladders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/ladders.png
--------------------------------------------------------------------------------
/intake/static/intake/img/ladders@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/ladders@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/notification-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/notification-icon.png
--------------------------------------------------------------------------------
/intake/static/intake/img/notification-icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/notification-icon@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/official_doc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/official_doc.png
--------------------------------------------------------------------------------
/intake/static/intake/img/official_doc@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/official_doc@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/ok_hand.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/ok_hand.png
--------------------------------------------------------------------------------
/intake/static/intake/img/ok_hand@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/ok_hand@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/partner-interface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/partner-interface.png
--------------------------------------------------------------------------------
/intake/static/intake/img/partner-interface@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/partner-interface@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/pencil.png
--------------------------------------------------------------------------------
/intake/static/intake/img/pencil@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/pencil@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/san_diego_seal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/san_diego_seal.png
--------------------------------------------------------------------------------
/intake/static/intake/img/san_diego_seal@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/san_diego_seal@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/san_francisco_seal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/san_francisco_seal.png
--------------------------------------------------------------------------------
/intake/static/intake/img/san_francisco_seal@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/san_francisco_seal@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/santa_barbara_seal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/santa_barbara_seal.png
--------------------------------------------------------------------------------
/intake/static/intake/img/santa_barbara_seal@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/santa_barbara_seal@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/santa_clara_seal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/santa_clara_seal.png
--------------------------------------------------------------------------------
/intake/static/intake/img/santa_clara_seal@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/santa_clara_seal@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/santa_cruz_seal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/santa_cruz_seal.png
--------------------------------------------------------------------------------
/intake/static/intake/img/santa_cruz_seal@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/santa_cruz_seal@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/solano_seal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/solano_seal.png
--------------------------------------------------------------------------------
/intake/static/intake/img/solano_seal@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/solano_seal@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/speech_bubbles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/speech_bubbles.png
--------------------------------------------------------------------------------
/intake/static/intake/img/speech_bubbles@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/speech_bubbles@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/img/tiffany-andrews.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/tiffany-andrews.jpg
--------------------------------------------------------------------------------
/intake/static/intake/img/ventura_seal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/ventura_seal.png
--------------------------------------------------------------------------------
/intake/static/intake/img/ventura_seal@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/intake/img/ventura_seal@2x.png
--------------------------------------------------------------------------------
/intake/static/intake/js/ajax.js:
--------------------------------------------------------------------------------
1 | var $ = require('jquery');
2 |
3 | function handleAjaxFormSubmission(form, successCallback){
4 | var actionUrl = form.attr('action');
5 | var rawData = form.serializeArray();
6 | var data = {};
7 | rawData.forEach(function (field){ data[field.name] = field.value; });
8 | $.post(actionUrl, data, successCallback);
9 | }
10 |
11 | module.exports = {
12 | handleForm: handleAjaxFormSubmission,
13 | }
--------------------------------------------------------------------------------
/intake/static/intake/js/csrf.js:
--------------------------------------------------------------------------------
1 |
2 | function csrfSafeMethod(method) {
3 | // these HTTP methods do not require CSRF protection
4 | return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
5 | }
6 |
7 | function setupAjaxCsrf(jQueryObject, csrftoken) {
8 | jQueryObject.ajaxSetup({
9 | beforeSend: function(xhr, settings) {
10 | if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
11 | xhr.setRequestHeader("X-CSRFToken", csrftoken);
12 | }
13 | }
14 | });
15 |
16 | }
17 |
18 | module.exports = {
19 | setupAjaxCsrf: setupAjaxCsrf
20 | };
21 |
--------------------------------------------------------------------------------
/intake/static/intake/js/d3.js:
--------------------------------------------------------------------------------
1 | var utils = require('./utils');
2 | var d3 = require('d3-selection');
3 | utils.combineObjs(d3, require('d3-array'));
4 | utils.combineObjs(d3, require('d3-collection'));
5 | utils.combineObjs(d3, require('d3-format'));
6 | utils.combineObjs(d3, require('d3-axis'));
7 | utils.combineObjs(d3, require('d3-scale'));
8 | utils.combineObjs(d3, require('d3-shape'));
9 | utils.combineObjs(d3, require('d3-time'));
10 | utils.combineObjs(d3, require('d3-time-format'));
11 |
12 | module.exports = d3;
--------------------------------------------------------------------------------
/intake/static/intake/less/charts.less:
--------------------------------------------------------------------------------
1 | .stats-single_figure {
2 | display: inline-block;
3 | width: 15em;
4 | }
5 | .minutes span.stats-total-number, .minutes span.stats-total-annot {
6 | display: block;
7 | }
8 |
9 | .stats-total-number {
10 | font-size: 2em;
11 | font-weight: 500;
12 | }
13 | span.perc-sign {
14 | font-size: 0.8em;
15 | }
16 |
17 | svg g.axis text {
18 | font-family: @font-family-sans-serif;
19 | }
20 |
21 | .axis.y path { stroke-width: 0; }
22 | .axis.y line { stroke: #dfdfdf; }
23 |
24 | rect.day-bar {
25 | stroke: #fff;
26 | stroke-width: 0.5px;
27 | fill: @brand-primary;
28 | }
29 |
30 | path.day-line {
31 | stroke: @brand-primary;
32 | stroke-width: 2px;
33 | fill: none;
34 | }
35 |
--------------------------------------------------------------------------------
/intake/static/intake/less/clear.less:
--------------------------------------------------------------------------------
1 | ul {
2 | list-style-type: none;
3 | }
--------------------------------------------------------------------------------
/intake/static/intake/less/flash_messages.less:
--------------------------------------------------------------------------------
1 |
2 | .flash_message {
3 | padding: .25em 0;
4 | }
5 | .flash_message:first-child {
6 | padding-top: 1em;
7 | }
8 | .flash_message:last-child {
9 | padding-bottom: 1em;
10 | }
11 | .flash_message .row {
12 | position: relative;
13 | }
14 | .flash_message .row > div:before {
15 | .glyphicon;
16 | width: 2em;
17 | position: absolute;
18 | }
19 | .flash_message-body {
20 | display: block;
21 | }
22 |
23 | .flash_message.error {
24 | background-color: @brand-danger-background;
25 | color: @brand-danger-text;
26 | }
27 |
28 | .flash_message.success {
29 | background-color: @brand-success;
30 | color: white;
31 | }
32 |
33 | .flash_message.warning {
34 | background-color: @brand-warning;
35 | color: white;
36 | }
37 |
--------------------------------------------------------------------------------
/intake/static/intake/less/mixins.less:
--------------------------------------------------------------------------------
1 | // Function borrowed from getbootstrap.com/css/#mixins
2 | // Generate the medium columns
3 | .make-md-column(@columns, @gutter: @grid-gutter-width) {
4 | position: relative;
5 | // Prevent columns from collapsing when empty
6 | min-height: 1px;
7 | // Inner gutter via padding
8 | padding-left: (@gutter / 2);
9 | padding-right: (@gutter / 2);
10 |
11 | // Calculate width based on number of columns available
12 | @media (min-width: @screen-md-min) {
13 | float: left;
14 | width: percentage((@columns / @grid-columns));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/intake/static/intake/less/sunset-notice.less:
--------------------------------------------------------------------------------
1 | .sunset-notice {
2 | h3 {
3 | font-weight: bold;
4 | margin-bottom: 22px;
5 | }
6 | h4 {
7 | font-size: 18px;
8 | }
9 | ul.list--bulleted {
10 | list-style-type: disc;
11 | }
12 | hr {
13 | margin: 40px 0;
14 | }
15 | }
--------------------------------------------------------------------------------
/intake/static/intake/scss/_ie-hacks.scss:
--------------------------------------------------------------------------------
1 | .lt-ie10 {
2 | .select {
3 | &:before {
4 | display: none;
5 | }
6 | }
7 | .select__element {
8 | padding-right: .7em;
9 | }
10 | }
--------------------------------------------------------------------------------
/intake/static/intake/scss/_shame.scss:
--------------------------------------------------------------------------------
1 | /* this is a file for shameful hacks, so they can act as temporary solutions
2 | If you put something here, fix it and take it out later :)
3 | */
--------------------------------------------------------------------------------
/intake/static/intake/scss/atoms/_base.scss:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 |
6 | html {
7 | position: relative;
8 | background-color: $color-background;
9 | font-size: $em-base;
10 | -webkit-font-smoothing: antialiased;
11 | min-height: 100%;
12 | }
13 |
14 | body {
15 | font-size: $font-size-normal;
16 | font-family: $font-system;
17 | line-height: $line-height-normal;
18 | margin: 0;
19 | }
20 |
21 | .page-wrapper {
22 | overflow: hidden;
23 | padding-left: $site-margins/2;
24 | padding-right: $site-margins/2;
25 | @include media($tablet-up) {
26 | padding-left: $site-margins;
27 | padding-right: $site-margins;
28 | }
29 | }
--------------------------------------------------------------------------------
/intake/static/intake/scss/atoms/_emoji.scss:
--------------------------------------------------------------------------------
1 | .emoji {
2 | display: inline-block;
3 | text-indent: -9999px;
4 | height: 1em;
5 | width: 1em;
6 | content: '';
7 | background-size: 100% auto;
8 | position: relative;
9 | }
10 |
11 | .emoji--big {
12 | width: 3em;
13 | height: 3em;
14 | }
15 |
16 | .emoji--med {
17 | width: 2.4em;
18 | height: 2.4em;
19 | }
20 |
21 | .emoji--small {
22 | width: 1.8em;
23 | height: 1.8em;
24 | }
25 |
26 | // .emoji--grinning-face {
27 | // background-image: image-url('emojis/1f600.png');
28 | // }
29 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/atoms/_form-widths.scss:
--------------------------------------------------------------------------------
1 | .form-width--short {
2 | max-width: $width-form-short;
3 | }
4 |
5 | .form-width--med {
6 | max-width: $width-form-med;
7 | }
8 |
9 | .form-width--long {
10 | max-width: $width-form-long;
11 | }
12 |
13 | .form-width--casenumber {
14 | max-width: $width-form-casenumber;
15 | }
16 |
17 | .form-width--name {
18 | max-width: $width-form-name;
19 | }
20 |
21 | .form-width--phone {
22 | max-width: $width-form-phone;
23 | }
24 |
25 | .form-width--ssn {
26 | max-width: $width-form-ssn;
27 | }
28 |
29 | .form-width--zip {
30 | max-width: $width-form-zip;
31 | }
32 |
33 | .form-width--searchbar {
34 | max-width: $width-form-searchbar;
35 | }
36 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/atoms/_images.scss:
--------------------------------------------------------------------------------
1 | img {
2 | max-width: 100%;
3 | height: auto;
4 | width: auto;
5 | }
6 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/atoms/_labels.scss:
--------------------------------------------------------------------------------
1 | .label {
2 | display: inline-block;
3 | font-size: $font-size-smallest;
4 | background-color: $color-dark-grey;
5 | color: #fff;
6 | font-weight: 500;
7 | border-radius: $border-radius;
8 | text-transform: uppercase;
9 | padding: 0 .5em;
10 | line-height: 1.4em;
11 | position: relative;
12 | top: -.1em;
13 | margin-left: .2em;
14 | }
15 |
16 | .label--magenta {
17 | background-color: $color-magenta;
18 | }
19 |
20 | .label--teal {
21 | background-color: $color-teal;
22 | }
23 |
24 | .label--green {
25 | background-color: $color-green;
26 | }
27 |
28 | .label--orange {
29 | background-color: $color-orange;
30 | }
31 |
32 | .label--red {
33 | background-color: $color-red;
34 | }
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/helpers/_buttons-list.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// A list of all HTML button elements.
4 | ///
5 | /// @type list
6 | ///
7 | /// @access private
8 |
9 | $_buttons-list: (
10 | "button",
11 | "[type='button']",
12 | "[type='reset']",
13 | "[type='submit']",
14 | );
15 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/helpers/_scales.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | ////
4 | /// Pre-defined scales for use with the `modular-scale` function.
5 | ///
6 | /// @type number (unitless)
7 | ///
8 | /// @see {function} modular-scale
9 | ////
10 |
11 | $minor-second: 1.067;
12 | $major-second: 1.125;
13 | $minor-third: 1.2;
14 | $major-third: 1.25;
15 | $perfect-fourth: 1.333;
16 | $augmented-fourth: 1.414;
17 | $perfect-fifth: 1.5;
18 | $minor-sixth: 1.6;
19 | $golden: 1.618;
20 | $major-sixth: 1.667;
21 | $minor-seventh: 1.778;
22 | $major-seventh: 1.875;
23 | $octave: 2;
24 | $major-tenth: 2.5;
25 | $major-eleventh: 2.667;
26 | $major-twelfth: 3;
27 | $double-octave: 4;
28 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/helpers/_text-inputs-list.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// A list of all _text-based_ HTML inputs.
4 | ///
5 | /// @type list
6 | ///
7 | /// @access private
8 |
9 | $_text-inputs-list: (
10 | "[type='color']",
11 | "[type='date']",
12 | "[type='datetime']",
13 | "[type='datetime-local']",
14 | "[type='email']",
15 | "[type='month']",
16 | "[type='number']",
17 | "[type='password']",
18 | "[type='search']",
19 | "[type='tel']",
20 | "[type='text']",
21 | "[type='time']",
22 | "[type='url']",
23 | "[type='week']",
24 | "input:not([type])",
25 | "textarea",
26 | );
27 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/library/_border-style.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Provides a concise, one-line method for setting `border-style` on specific
4 | /// edges of a box. Use a `null` value to “skip” edges of the box with standard
5 | /// CSS shorthand.
6 | ///
7 | /// @argument {list} $values
8 | /// List of border styles; accepts CSS shorthand.
9 | ///
10 | /// @example scss
11 | /// .element {
12 | /// @include border-style(dashed null solid);
13 | /// }
14 | ///
15 | /// // CSS Output
16 | /// .element {
17 | /// border-bottom-style: solid;
18 | /// border-top-style: dashed;
19 | /// }
20 | ///
21 | /// @require {mixin} _directional-property
22 |
23 | @mixin border-style($values) {
24 | @include _directional-property(border, style, $values);
25 | }
26 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/library/_border-width.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Provides a concise, one-line method for setting `border-width` on specific
4 | /// edges of a box. Use a `null` value to “skip” edges of the box with standard
5 | /// CSS shorthand.
6 | ///
7 | /// @argument {list} $values
8 | /// List of border widths; accepts CSS shorthand.
9 | ///
10 | /// @example scss
11 | /// .element {
12 | /// @include border-width(1em null 20px);
13 | /// }
14 | ///
15 | /// // CSS Output
16 | /// .element {
17 | /// border-bottom-width: 20px;
18 | /// border-top-width: 1em;
19 | /// }
20 | ///
21 | /// @require {mixin} _directional-property
22 |
23 | @mixin border-width($values) {
24 | @include _directional-property(border, width, $values);
25 | }
26 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/library/_clearfix.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Provides an easy way to include a clearfix for containing floats.
4 | ///
5 | /// @link https://goo.gl/yP5hiZ
6 | ///
7 | /// @example scss
8 | /// .element {
9 | /// @include clearfix;
10 | /// }
11 | ///
12 | /// // CSS Output
13 | /// .element::after {
14 | /// clear: both;
15 | /// content: "";
16 | /// display: block;
17 | /// }
18 |
19 | @mixin clearfix {
20 | &::after {
21 | clear: both;
22 | content: "";
23 | display: block;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/library/_hide-text.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Hides the text in an element, commonly used to show an image instead. Some
4 | /// elements will need block-level styles applied.
5 | ///
6 | /// @link https://goo.gl/EvLRIu
7 | ///
8 | /// @example scss
9 | /// .element {
10 | /// @include hide-text;
11 | /// }
12 | ///
13 | /// // CSS Output
14 | /// .element {
15 | /// overflow: hidden;
16 | /// text-indent: 101%;
17 | /// white-space: nowrap;
18 | /// }
19 |
20 | @mixin hide-text {
21 | overflow: hidden;
22 | text-indent: 101%;
23 | white-space: nowrap;
24 | }
25 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/library/_shade.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Mixes a color with black.
4 | ///
5 | /// @argument {color} $color
6 | ///
7 | /// @argument {number (percentage)} $percent
8 | /// The amount of black to be mixed in.
9 | ///
10 | /// @return {color}
11 | ///
12 | /// @example scss
13 | /// .element {
14 | /// background-color: shade(#ffbb52, 60%);
15 | /// }
16 | ///
17 | /// // CSS Output
18 | /// .element {
19 | /// background-color: #664a20;
20 | /// }
21 |
22 | @function shade(
23 | $color,
24 | $percent
25 | ) {
26 | @if not _is-color($color) {
27 | @error "`#{$color}` is not a valid color for the `$color` argument in " +
28 | "the `shade` mixin.";
29 | } @else {
30 | @return mix(#000, $color, $percent);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/library/_strip-unit.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Strips the unit from a number.
4 | ///
5 | /// @argument {number} $value
6 | ///
7 | /// @return {number (unitless)}
8 | ///
9 | /// @example scss
10 | /// $dimension: strip-unit(10em);
11 | ///
12 | /// // Output
13 | /// $dimension: 10;
14 |
15 | @function strip-unit($value) {
16 | @return ($value / ($value * 0 + 1));
17 | }
18 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/library/_tint.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Mixes a color with white.
4 | ///
5 | /// @argument {color} $color
6 | ///
7 | /// @argument {number (percentage)} $percent
8 | /// The amount of white to be mixed in.
9 | ///
10 | /// @return {color}
11 | ///
12 | /// @example scss
13 | /// .element {
14 | /// background-color: tint(#6ecaa6, 40%);
15 | /// }
16 | ///
17 | /// // CSS Output
18 | /// .element {
19 | /// background-color: #a8dfc9;
20 | /// }
21 |
22 | @function tint(
23 | $color,
24 | $percent
25 | ) {
26 | @if not _is-color($color) {
27 | @error "`#{$color}` is not a valid color for the `$color` argument in " +
28 | "the `tint` mixin.";
29 | } @else {
30 | @return mix(#fff, $color, $percent);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/utilities/_assign-inputs.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Append pseudo-classes to a selector(s).
4 | ///
5 | /// @argument {list | string} $inputs
6 | /// A selector, or list of selectors, to apply the pseudo-class to.
7 | ///
8 | /// @argument {pseudo-class} $pseudo [null]
9 | /// The pseudo-class to be appended.
10 | ///
11 | /// @return {list}
12 | ///
13 | /// @access private
14 |
15 | @function _assign-inputs(
16 | $inputs,
17 | $pseudo: null
18 | ) {
19 | $list: ();
20 |
21 | @each $input in $inputs {
22 | $input: unquote($input);
23 | $input: if($pseudo, $input + ":" + $pseudo, $input);
24 | $list: append($list, $input, comma);
25 | }
26 |
27 | @return $list;
28 | }
29 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/utilities/_fetch-bourbon-setting.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Return a Bourbon setting.
4 | ///
5 | /// @argument {string} $setting
6 | ///
7 | /// @return {boolean | color | list | number | string}
8 | ///
9 | /// @example scss
10 | /// _fetch-bourbon-setting(rails-asset-pipeline)
11 | ///
12 | /// @access private
13 |
14 | @function _fetch-bourbon-setting($setting) {
15 | @return map-get(map-merge($_bourbon-defaults, $bourbon), $setting);
16 | }
17 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/utilities/_gamma.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Performs gamma correction on a single color channel.
4 | ///
5 | /// Note that the calculation is approximate if a `pow()` is not available.
6 | ///
7 | /// @argument {number (0-1)} $channel
8 | ///
9 | /// @return {number (0-1)}
10 | ///
11 | /// @access private
12 |
13 | @function _gamma($channel) {
14 | @if $channel < 0.03928 {
15 | @return $channel / 12.92;
16 | } @else {
17 | $c: ($channel + 0.055) / 1.055;
18 | @if function-exists("pow") {
19 | @return pow($c, 2.4);
20 | } @else {
21 | @return 0.56 * $c * $c * $c + 0.44 * $c * $c;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/utilities/_lightness.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Programatically determines the lightness of a color.
4 | ///
5 | /// @argument {color (hex)} $hex-color
6 | ///
7 | /// @return {number (0-1)}
8 | ///
9 | /// @example scss
10 | /// _lightness($color)
11 | ///
12 | /// @access private
13 |
14 | @function _lightness($hex-color) {
15 | $-local-red-raw: red(rgba($hex-color, 1));
16 | $-local-green-raw: green(rgba($hex-color, 1));
17 | $-local-blue-raw: blue(rgba($hex-color, 1));
18 |
19 | $-local-red: _gamma($-local-red-raw / 255);
20 | $-local-green: _gamma($-local-green-raw / 255);
21 | $-local-blue: _gamma($-local-blue-raw / 255);
22 |
23 | @return $-local-red * 0.2126 + $-local-green * 0.7152 + $-local-blue * 0.0722;
24 | }
25 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/validators/_contains-falsy.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Checks if a list does not contain any values.
4 | ///
5 | /// @argument {list} $list
6 | /// The list to check against.
7 | ///
8 | /// @return {boolean}
9 | ///
10 | /// @access private
11 |
12 | @function _contains-falsy($list) {
13 | @each $item in $list {
14 | @if not $item {
15 | @return true;
16 | }
17 | }
18 |
19 | @return false;
20 | }
21 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/validators/_contains.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Checks if a list contains a value(s).
4 | ///
5 | /// @argument {list} $list
6 | /// The list to check against.
7 | ///
8 | /// @argument {list} $values
9 | /// A single value or list of values to check for.
10 | ///
11 | /// @return {boolean}
12 | ///
13 | /// @access private
14 |
15 | @function _contains(
16 | $list,
17 | $values...
18 | ) {
19 | @each $value in $values {
20 | @if type-of(index($list, $value)) != "number" {
21 | @return false;
22 | }
23 | }
24 |
25 | @return true;
26 | }
27 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/validators/_is-color.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Checks for a valid CSS color.
4 | ///
5 | /// @argument {string} $color
6 | ///
7 | /// @return {boolean}
8 | ///
9 | /// @access private
10 |
11 | @function _is-color($color) {
12 | @return (type-of($color) == color) or ($color == "currentColor");
13 | }
14 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/validators/_is-length.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Checks for a valid CSS length.
4 | ///
5 | /// @argument {string} $value
6 | ///
7 | /// @return {boolean}
8 | ///
9 | /// @access private
10 |
11 | @function _is-length($value) {
12 | @return type-of($value) != "null" and (str-slice($value + "", 1, 4) == "calc"
13 | or index(auto inherit initial 0, $value)
14 | or (type-of($value) == "number" and not(unitless($value))));
15 | }
16 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/validators/_is-number.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Checks for a valid number.
4 | ///
5 | /// @argument {number} $value
6 | ///
7 | /// @require {function} _contains
8 | ///
9 | /// @return {boolean}
10 | ///
11 | /// @access private
12 |
13 | @function _is-number($value) {
14 | @return _contains("0" "1" "2" "3" "4" "5" "6" "7" "8" "9" 0 1 2 3 4 5 6 7 8 9, $value);
15 | }
16 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/bourbon/bourbon/validators/_is-size.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Checks for a valid CSS size.
4 | ///
5 | /// @argument {string} $value
6 | ///
7 | /// @return {boolean}
8 | ///
9 | /// @require {function} _contains
10 | ///
11 | /// @require {function} _is-length
12 | ///
13 | /// @access private
14 |
15 | @function _is-size($value) {
16 | @return _is-length($value)
17 | or _contains("fill" "fit-content" "min-content" "max-content", $value);
18 | }
19 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/molecules/_flashes.scss:
--------------------------------------------------------------------------------
1 | .flash {
2 | @include full-bleed();
3 | position: relative;
4 | padding: {
5 | top: 1em;
6 | bottom: 1em;
7 | }
8 | background-color: #fff;
9 | font-weight: 500;
10 | &:last-child {
11 | box-shadow: 10px 0 10px rgba(0,0,0,.25);
12 | }
13 | p:last-child {
14 | margin-bottom: 0;
15 | }
16 | a {
17 | color: inherit;
18 | }
19 | }
20 |
21 | .flash.error {
22 | background-color: tint($color-red, 80%);
23 | }
24 |
25 | .flash.success {
26 | color: #fff;
27 | background-color: shade($color-green, 8%);
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/molecules/_progress-indicator.scss:
--------------------------------------------------------------------------------
1 | .progress-indicator {
2 | width: 10em;
3 | margin: 2em auto;
4 | text-align: center;
5 | position: relative;
6 | &:before {
7 | content: '';
8 | display: block;
9 | position: absolute;
10 | top: 0;
11 | height: 6px;
12 | left: 0;
13 | right: 0;
14 | border-radius: 3px;
15 | background-color: $color-light-grey;
16 | z-index: -1;
17 | border: 1px solid $color-tan;
18 | }
19 | }
20 |
21 | .progress-indicator__bar {
22 | height: 6px;
23 | min-width: 6px;
24 | border-radius: 3px;
25 | background-color: $color-teal;
26 | }
27 |
28 | .progress-indicator__percentage {
29 | margin-top: .5em;
30 | font-size: $font-size-small;
31 | }
--------------------------------------------------------------------------------
/intake/static/intake/scss/molecules/_scroller.scss:
--------------------------------------------------------------------------------
1 | @keyframes scroller {
2 | 0% {
3 | opacity: 0;
4 | }
5 |
6 | 100% {
7 | opacity: 1;
8 | }
9 |
10 | }
11 |
12 | .scroller {
13 | animation: scroller 2s 1;
14 | position: absolute;
15 | left: 50%;
16 | bottom: 1em;
17 | margin-left: -1em;
18 | display: block;
19 | width: 2em;
20 | height: 2em;
21 | color: $color-darkest-grey;
22 | text-decoration: none;
23 | &:before {
24 | font-family: $font-icon;
25 | font-size: $font-size-h2;
26 | display: block;
27 | content: '\e313';
28 | text-align: center;
29 | line-height: 1.5em;
30 | }
31 | }
32 |
33 | .scroller--light {
34 | color: #FFFFFF;
35 | &:hover {
36 | color: $color-magenta;
37 | }
38 | }
--------------------------------------------------------------------------------
/intake/static/intake/scss/molecules/_summary-table.scss:
--------------------------------------------------------------------------------
1 | .summary-table {
2 | text-align: center;
3 | .grid__item {
4 | margin-bottom: 1em;
5 | }
6 | }
7 |
8 | .summary-table--left {
9 | text-align: left;
10 | }
11 |
12 | .summary-table__label {
13 | @extend .text--help;
14 | margin-bottom: 0;
15 | }
16 |
17 | .summary-table__value {
18 | @extend .text--pullquote;
19 | }
--------------------------------------------------------------------------------
/intake/static/intake/scss/molecules/_toolbar.scss:
--------------------------------------------------------------------------------
1 | .toolbar {
2 | @include clearfix();
3 | max-width: $site-max-width;
4 | margin: {
5 | left: auto;
6 | right: auto;
7 | }
8 | }
9 |
10 | .toolbar__item {
11 | float: left;
12 | margin-right: 1em;
13 | }
14 |
15 | .toolbar__left {
16 | float: left;
17 | margin-right: .5em;
18 | }
19 |
20 | .toolbar__right {
21 | float: right;
22 | margin-left: .5em;
23 | .toolbar__item {
24 | margin-right: 0;
25 | margin-left: 1em;
26 | display: inline-block;
27 | float: left;
28 | }
29 | }
--------------------------------------------------------------------------------
/intake/static/intake/scss/neat/_neat-helpers.scss:
--------------------------------------------------------------------------------
1 | // Mixins
2 | @import "mixins/clearfix";
3 |
4 | // Functions
5 | @import "functions/private";
6 | @import "functions/new-breakpoint";
7 |
8 | // Settings
9 | @import "settings/grid";
10 | @import "settings/visual-grid";
11 | @import "settings/disable-warnings";
12 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/neat/_neat.scss:
--------------------------------------------------------------------------------
1 | // Neat 1.8.0
2 | // http://neat.bourbon.io
3 | // Copyright 2012-2015 thoughtbot, inc.
4 | // MIT License
5 |
6 | // Helpers
7 | @import "neat-helpers";
8 |
9 | // Grid
10 | @import "grid/private";
11 | @import "grid/box-sizing";
12 | @import "grid/omega";
13 | @import "grid/outer-container";
14 | @import "grid/span-columns";
15 | @import "grid/row";
16 | @import "grid/shift";
17 | @import "grid/pad";
18 | @import "grid/fill-parent";
19 | @import "grid/media";
20 | @import "grid/to-deprecate";
21 | @import "grid/visual-grid";
22 | @import "grid/display-context";
23 | @import "grid/direction-context";
24 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/neat/grid/_box-sizing.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | @if $border-box-sizing == true {
4 | html { // http://bit.ly/1qk2tVR
5 | box-sizing: border-box;
6 | }
7 |
8 | * {
9 | &,
10 | &::after,
11 | &::before {
12 | box-sizing: inherit;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/neat/grid/_fill-parent.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Forces the element to fill its parent container.
4 | ///
5 | /// @example scss - Usage
6 | /// .element {
7 | /// @include fill-parent;
8 | /// }
9 | ///
10 | /// @example css - CSS Output
11 | /// .element {
12 | /// width: 100%;
13 | /// box-sizing: border-box;
14 | /// }
15 |
16 | @mixin fill-parent() {
17 | width: 100%;
18 |
19 | @if $border-box-sizing == false {
20 | box-sizing: border-box;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/neat/grid/_pad.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Adds padding to the element.
4 | ///
5 | /// @param {List} $padding [flex-gutter()]
6 | /// A list of padding value(s) to use. Passing `default` in the list will result in using the gutter width as a padding value.
7 | ///
8 | /// @example scss - Usage
9 | /// .element {
10 | /// @include pad(30px -20px 10px default);
11 | /// }
12 | ///
13 | /// @example css - CSS Output
14 | /// .element {
15 | /// padding: 30px -20px 10px 2.35765%;
16 | /// }
17 |
18 | @mixin pad($padding: flex-gutter()) {
19 | $padding-list: null;
20 | @each $value in $padding {
21 | $value: if($value == 'default', flex-gutter(), $value);
22 | $padding-list: join($padding-list, $value);
23 | }
24 | padding: $padding-list;
25 | }
26 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/neat/mixins/_clearfix.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Provides an easy way to include a clearfix for containing floats.
4 | ///
5 | /// @link http://goo.gl/yP5hiZ
6 | ///
7 | /// @example scss
8 | /// .element {
9 | /// @include clearfix;
10 | /// }
11 | ///
12 | /// @example css
13 | /// .element::after {
14 | /// clear: both;
15 | /// content: "";
16 | /// display: block;
17 | /// }
18 |
19 | @mixin clearfix {
20 | &::after {
21 | clear: both;
22 | content: "";
23 | display: block;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/neat/settings/_disable-warnings.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /// Disable all deprecation warnings. Defaults to `false`. Set with a `!global` flag.
4 | ///
5 | /// @type Bool
6 |
7 | $disable-warnings: false !default;
8 |
9 | @mixin -neat-warn($message) {
10 | @if $disable-warnings == false {
11 | @warn "#{$message}";
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/organisms/_county-seal-list.scss:
--------------------------------------------------------------------------------
1 | .county-seal-list {
2 | text-align: center;
3 | max-width: 35em;
4 | margin: 0 auto;
5 | }
6 | .county-seal-list + p {
7 | text-align: center;
8 | }
9 |
10 | .county-seal {
11 | margin: 0 0.4em 0.4em 0.4em;
12 | display: inline-block;
13 | text-align: center;
14 | outline: 10px red !important;
15 | }
--------------------------------------------------------------------------------
/intake/static/intake/scss/organisms/_demo-banner.scss:
--------------------------------------------------------------------------------
1 | .demo-banner {
2 | @include full-bleed();
3 | position: relative;
4 | z-index: 2;
5 | background-color: $color-red;
6 | padding: .5em;
7 | text-align: center;
8 | font-size: $font-size-small;
9 | color: #FFFFFF;
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/organisms/_legal.scss:
--------------------------------------------------------------------------------
1 | .legal {
2 | margin-top: -1em;
3 | margin-bottom: 2em;
4 | max-width: 30em;
5 | margin-left: auto;
6 | margin-right: auto;
7 | }
--------------------------------------------------------------------------------
/intake/static/intake/scss/organisms/_pagination.scss:
--------------------------------------------------------------------------------
1 | .pagination {
2 | @include clearfix;
3 | padding: 2em 0;
4 |
5 | .text--help {
6 | margin-top: .3em;
7 | }
8 |
9 | .button {
10 | min-width: 2.5em;
11 | text-align: center;
12 | }
13 |
14 | .pagination__selected {
15 | @extend .button--primary;
16 | }
17 |
18 | .pagination__ellipsis {
19 | display: inline-block;
20 | width: 2em;
21 | text-align: center;
22 | }
23 |
24 | @include media($tablet-up) {
25 |
26 | .pagination__info {
27 | float: left;
28 | }
29 |
30 | .pagination__buttons {
31 | float: right;
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/intake/static/intake/scss/organisms/_statistic-card.scss:
--------------------------------------------------------------------------------
1 | .statistic-card {
2 | @extend .card;
3 | }
4 |
5 | .statistic-card__label {
6 | @extend .text--help;
7 | margin-bottom: .5em;
8 | }
9 |
10 | .statistic-card__number {
11 | @extend .h1;
12 | margin-top: 0;
13 | }
14 |
--------------------------------------------------------------------------------
/intake/static/intake/scss/organisms/_sunset-notice-alert.scss:
--------------------------------------------------------------------------------
1 | .sunset-notice-alert {
2 | background-color: #E5F2FD;
3 | padding: 15px 10px;
4 | &__icon {
5 | position: absolute;
6 | color: #1380D0;
7 | font-size: 32px;
8 | display: none;
9 | @include media($tablet-up) {
10 | display: block;
11 | }
12 | }
13 |
14 | &__details {
15 | margin-bottom: 0;
16 | margin-left: 0;
17 |
18 | @include media($tablet-up) {
19 | margin-left: 45px;
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/intake/static/intake/scss/templates/_banner.scss:
--------------------------------------------------------------------------------
1 | .banner {
2 | background-color: #E5F2FD;
3 | color: #423A3E;
4 | text-align: center;
5 | padding: 10px;
6 | margin-top: 2em;
7 | margin-left: inherit;
8 | margin-right: inherit;
9 | margin-bottom: 0;
10 | }
--------------------------------------------------------------------------------
/intake/static/intake/scss/templates/_partnerships-contact.scss:
--------------------------------------------------------------------------------
1 | .partnerships-contact {
2 | .slab {
3 | border-top: 1px solid $color-tan;
4 | }
5 | }
--------------------------------------------------------------------------------
/intake/static/voicemail/CMR_voicemail_greeting.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/static/voicemail/CMR_voicemail_greeting.mp3
--------------------------------------------------------------------------------
/intake/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/tests/__init__.py
--------------------------------------------------------------------------------
/intake/tests/factories/applicant_factory.py:
--------------------------------------------------------------------------------
1 | import factory
2 | from intake import models
3 | from .visitor_factory import VisitorFactory
4 |
5 |
6 | class ApplicantFactory(factory.DjangoModelFactory):
7 | visitor = factory.SubFactory(VisitorFactory)
8 |
9 | class Meta:
10 | model = models.Applicant
11 |
--------------------------------------------------------------------------------
/intake/tests/factories/county_factory.py:
--------------------------------------------------------------------------------
1 | import factory
2 | from intake import models
3 |
4 |
5 | class CountyFactory(factory.DjangoModelFactory):
6 | slug = factory.Sequence(lambda n: 'county-{}'.format(n))
7 | name = factory.Sequence(lambda n: 'Fake County {}'.format(n))
8 | description = factory.Sequence(
9 | lambda n: (
10 | 'Fake County {} (near Tlön, Uqbar, or Orbis Tertius)'.format(
11 | n)))
12 |
13 | class Meta:
14 | model = models.County
15 |
--------------------------------------------------------------------------------
/intake/tests/factories/prebuilt_pdf_bundle_factory.py:
--------------------------------------------------------------------------------
1 | import factory
2 | from intake import models
3 | from user_accounts.models import Organization
4 |
5 |
6 | def get_sf_pubdef(*args, **kwargs):
7 | return Organization.objects.get(slug="sf_pubdef")
8 |
9 |
10 | class PrebuiltPDFBundleFactory(factory.DjangoModelFactory):
11 | organization = factory.LazyFunction(get_sf_pubdef)
12 |
13 | class Meta:
14 | model = models.PrebuiltPDFBundle
15 |
--------------------------------------------------------------------------------
/intake/tests/factories/status_notification_factory.py:
--------------------------------------------------------------------------------
1 | import factory
2 | from intake import models
3 |
4 |
5 | class StatusNotificationFactory(factory.DjangoModelFactory):
6 | status_update = factory.Iterator(models.StatusUpdate.objects.all())
7 | contact_info = {"email": "cmrtestuser+notification@gmail.com"}
8 | base_message = "Resistance is futile"
9 | sent_message = "Live long and prosper"
10 |
11 | class Meta:
12 | model = models.StatusNotification
13 |
--------------------------------------------------------------------------------
/intake/tests/factories/status_type.py:
--------------------------------------------------------------------------------
1 | import factory
2 | from intake import models
3 |
4 |
5 | class StatusTypeFactory(factory.DjangoModelFactory):
6 | label = 'Everything is Awesome'
7 | display_name = 'Awesome'
8 | template = 'Dear {{first_name}}, your case is just fantastic!'
9 | help_text = 'Client has nothing to worry about'
10 | slug = 'everything-is-awesome'
11 |
12 | class Meta:
13 | model = models.StatusType
14 |
--------------------------------------------------------------------------------
/intake/tests/factories/submission_tag_link_factory.py:
--------------------------------------------------------------------------------
1 | import factory
2 | from intake import models
3 | from user_accounts.tests.factories import UserFactory
4 | from .tag_factory import TagFactory
5 | from .form_submission_factory import FormSubmissionFactory
6 |
7 |
8 | class SubmissionTagLinkFactory(factory.DjangoModelFactory):
9 | content_object = factory.SubFactory(FormSubmissionFactory)
10 | tag = factory.SubFactory(TagFactory)
11 | user = factory.SubFactory(UserFactory)
12 |
13 | class Meta:
14 | model = models.SubmissionTagLink
15 |
--------------------------------------------------------------------------------
/intake/tests/factories/tag_factory.py:
--------------------------------------------------------------------------------
1 | import factory
2 | from taggit import models
3 |
4 |
5 | class TagFactory(factory.DjangoModelFactory):
6 | name = factory.Sequence(lambda n: 'tag-{}'.format(n))
7 |
8 | class Meta:
9 | model = models.Tag
10 |
--------------------------------------------------------------------------------
/intake/tests/factories/utils.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/tests/factories/utils.py
--------------------------------------------------------------------------------
/intake/tests/factories/visitor_factory.py:
--------------------------------------------------------------------------------
1 | import factory
2 | from intake import models
3 |
4 |
5 | class VisitorFactory(factory.DjangoModelFactory):
6 | source = 'share'
7 | referrer = 'http://bajoradefender.org/services/clean-slate/'
8 | ip_address = '48.104.186.127'
9 |
10 | class Meta:
11 | model = models.Visitor
12 |
--------------------------------------------------------------------------------
/intake/tests/forms/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/tests/forms/__init__.py
--------------------------------------------------------------------------------
/intake/tests/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/tests/management/__init__.py
--------------------------------------------------------------------------------
/intake/tests/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/tests/management/commands/__init__.py
--------------------------------------------------------------------------------
/intake/tests/mock_referrers.py:
--------------------------------------------------------------------------------
1 | choices = [
2 | None,
3 | 'https://t.co/8syieoGr9k',
4 | 'https://checkrapplicant.zendesk.com/hc/en-us',
5 | 'http://sfpublicdefender.org/',
6 | 'http://sfpublicdefender.org/services/clean-slate/',
7 | 'http://www.safeandjust.org/county-map',
8 | 'https://www.facebook.com/',
9 | 'https://m.facebook.com/',
10 | 'https://www.google.com/',
11 | 'https://www.codeforamerica.org/products/clear-my-record'
12 | ]
13 |
--------------------------------------------------------------------------------
/intake/tests/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/tests/models/__init__.py
--------------------------------------------------------------------------------
/intake/tests/models/test_application_event.py:
--------------------------------------------------------------------------------
1 | # from unittest.mock import patch
2 | from django.test import TestCase
3 |
4 | # from intake import models
5 | # from intake.tests import factories
6 |
7 |
8 | class TestApplicationEvent(TestCase):
9 |
10 | def test_nothing(self):
11 | pass
12 |
--------------------------------------------------------------------------------
/intake/tests/models/test_status_notification.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 | from intake import models
3 |
4 |
5 | class TestStatusNotification(TestCase):
6 | pass
7 |
--------------------------------------------------------------------------------
/intake/tests/models/test_status_update.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 |
4 | class TestStatusUpdate(TestCase):
5 | pass
6 |
--------------------------------------------------------------------------------
/intake/tests/models/test_visitor.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | from intake.models import Visitor
4 |
5 |
6 | class TestVisitor(TestCase):
7 |
8 | def test_init_visitor_with_no_info(self):
9 | visitor = Visitor()
10 | visitor.save()
11 | self.assertTrue(visitor.id)
12 | self.assertTrue(visitor.first_visit)
13 |
14 | def test_save_with_source_and_referrer(self):
15 | visitor = Visitor(
16 | source='prop47fair',
17 | referrer='www.google.com')
18 | visitor.save()
19 | self.assertTrue(visitor.id)
20 | self.assertTrue(visitor.first_visit)
21 |
--------------------------------------------------------------------------------
/intake/tests/serializers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/tests/serializers/__init__.py
--------------------------------------------------------------------------------
/intake/tests/service_objects/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/tests/service_objects/__init__.py
--------------------------------------------------------------------------------
/intake/tests/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/tests/services/__init__.py
--------------------------------------------------------------------------------
/intake/tests/test_commands.py:
--------------------------------------------------------------------------------
1 | from unittest.mock import Mock, patch
2 | from django.test import TestCase
3 | from intake.management import commands
4 |
5 |
6 | class TestCommands(TestCase):
7 |
8 | @patch(
9 | 'intake.management.commands.send_unopened_apps_notification'
10 | '.BundlesService')
11 | def test_send_unopened_apps_notification(self, BundlesService):
12 | command = Mock()
13 | commands.send_unopened_apps_notification.Command.handle(command)
14 | BundlesService.count_unreads_and_send_notifications_to_orgs\
15 | .assert_called_once_with()
16 | command.style.SUCCESS.assert_called_once_with(
17 | "Successfully referred any unopened apps")
18 |
--------------------------------------------------------------------------------
/intake/tests/test_fields.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 | from formation import fields
3 |
4 |
5 | class TestHouseholdSizeField(TestCase):
6 |
7 | def test_display_value_is_larger_than_input(self):
8 | data = {'household_size': 2}
9 | field = fields.HouseholdSize(data)
10 | self.assertTrue(field.is_valid())
11 | self.assertEqual(field.get_current_value(), 2)
12 | self.assertEqual(field.get_display_value(), 3)
13 |
--------------------------------------------------------------------------------
/intake/tests/test_groups.py:
--------------------------------------------------------------------------------
1 | from intake.tests.base_testcases import IntakeDataTestCase
2 | from django.contrib.auth.models import Group
3 | from intake import groups
4 |
5 |
6 | class TestGroups(IntakeDataTestCase):
7 |
8 | fixtures = [
9 | 'counties', 'organizations', 'groups', 'mock_profiles'
10 | ]
11 |
12 | def test_followup_staff_group(self):
13 | user = self.be_cfa_user()
14 | group = Group.objects.get(name=groups.FOLLOWUP_STAFF)
15 | self.assertIn(group, user.groups.all())
16 |
17 | def test_application_reviewers_group(self):
18 | user = self.be_cfa_user()
19 | group = Group.objects.get(name=groups.APPLICATION_REVIEWERS)
20 | self.assertIn(group, user.groups.all())
21 |
--------------------------------------------------------------------------------
/intake/tests/unit/__init__.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 | from unittest.mock import Mock, patch, MagicMock
3 |
4 |
5 | class TestContextProcessors(TestCase):
6 |
7 | def test_oxford_comma(self):
8 | from project.jinja2 import oxford_comma
9 | items = ["apples", "oranges", "bananas"]
10 | expected_phrases = [
11 | "apples, oranges, and bananas",
12 | "apples and oranges",
13 | "apples",
14 | ]
15 | for phrase in expected_phrases:
16 | self.assertEqual(
17 | phrase, oxford_comma(items))
18 | items.pop()
19 |
--------------------------------------------------------------------------------
/intake/tests/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/tests/views/__init__.py
--------------------------------------------------------------------------------
/intake/tests/views/test_newapps_pdf_view.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/tests/views/test_newapps_pdf_view.py
--------------------------------------------------------------------------------
/intake/translators/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/translators/__init__.py
--------------------------------------------------------------------------------
/intake/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/intake/views/__init__.py
--------------------------------------------------------------------------------
/intake/views/stats_views.py:
--------------------------------------------------------------------------------
1 | from django.views.generic.base import TemplateView
2 | from intake.services import statistics
3 |
4 |
5 | class Stats(TemplateView):
6 | """A view that shows a public summary of service performance.
7 | """
8 | template_name = "stats.jinja"
9 |
10 | def get_context_data(self, **kwargs):
11 | context = super().get_context_data(**kwargs)
12 | context['stats'] = {'org_stats': statistics.get_org_data_dict()}
13 | return context
14 |
15 |
16 | stats = Stats.as_view()
17 |
--------------------------------------------------------------------------------
/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", "local_settings") # Only used in dev
7 | from django.core.management import execute_from_command_line
8 | execute_from_command_line(sys.argv)
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "dependencies": {
4 | "bootstrap": "^3.4.1",
5 | "browserify": "^16.5.2",
6 | "c3": "^0.4.23",
7 | "cached-path-relative": ">=1.0.2",
8 | "jquery": "^3.5.0",
9 | "less": "^3.11.0",
10 | "moment": "~> 2.19.3",
11 | "vinyl-buffer": "^1.0.1",
12 | "vinyl-source-stream": "^1.1.2",
13 | "bl": "^1.2.3",
14 | "elliptic": ">=6.5.4",
15 | "path-parse": ">=1.0.7"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/partnerships/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/partnerships/__init__.py
--------------------------------------------------------------------------------
/partnerships/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/partnerships/migrations/__init__.py
--------------------------------------------------------------------------------
/partnerships/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/partnerships/tests/__init__.py
--------------------------------------------------------------------------------
/partnerships/tests/factories.py:
--------------------------------------------------------------------------------
1 | import factory
2 | from partnerships import models
3 | from intake.tests.factories import VisitorFactory
4 |
5 |
6 | class PartnershipLeadFactory(factory.DjangoModelFactory):
7 | visitor = factory.SubFactory(VisitorFactory)
8 | name = 'Ziggy Stardust'
9 | email = 'ziggy@mars.space'
10 | organization_name = 'Spiders from Mars'
11 | message = 'Jamming good with Weird and Gilly'
12 |
13 | class Meta:
14 | model = models.PartnershipLead
15 |
--------------------------------------------------------------------------------
/partnerships/urls.py:
--------------------------------------------------------------------------------
1 | from django2_url_robots.utils import url
2 | from .views import contact, home
3 |
4 |
5 | urlpatterns = [
6 | url(r'^$', home, name='partnerships-home', robots_allow=True),
7 | url(r'^get-in-touch$',
8 | contact, name='partnerships-contact', robots_allow=True),
9 | ]
10 |
--------------------------------------------------------------------------------
/phone/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/phone/__init__.py
--------------------------------------------------------------------------------
/phone/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class PhoneConfig(AppConfig):
5 | name = 'phone'
6 |
--------------------------------------------------------------------------------
/phone/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/phone/tests/__init__.py
--------------------------------------------------------------------------------
/phone/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 | from phone.views import record, handle_new_message
3 |
4 | urlpatterns = [
5 | # voicemail views
6 | # these views are public, csrf exempt, and answer to POST data
7 | url(r'^handle-incoming-call$', record, name='phone-handle_incoming_call'),
8 | url(r'^handle-new-message$',
9 | handle_new_message, name='phone-handle_new_message'),
10 | ]
11 |
--------------------------------------------------------------------------------
/phone/validators.py:
--------------------------------------------------------------------------------
1 | from twilio.request_validator import RequestValidator
2 | from django.conf import settings
3 |
4 |
5 | def is_valid_twilio_request(request):
6 | twilio_request_validator = RequestValidator(settings.TWILIO_AUTH_TOKEN)
7 | request_path = request.build_absolute_uri(
8 | request.get_full_path()).replace('http:', 'https:')
9 | # trailing slashes should be removed
10 | if request_path[-1] == '/':
11 | request_path = request_path[:-1]
12 | twilio_signature = request.META.get('HTTP_X_TWILIO_SIGNATURE', '')
13 | return twilio_request_validator.validate(
14 | request_path, request.POST, twilio_signature)
15 |
--------------------------------------------------------------------------------
/printing/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/printing/__init__.py
--------------------------------------------------------------------------------
/project/__init__.py:
--------------------------------------------------------------------------------
1 | from .celery import app as celery_app
2 |
3 | __all__ = ['celery_app']
4 |
--------------------------------------------------------------------------------
/project/alerts.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 | from intake import tasks
3 |
4 |
5 | def send_email_to_admins(subject, message):
6 | """Asynchronously sends an email alert to all ADMINs in settings
7 | """
8 | tasks.send_email.delay(
9 | subject=subject, message=message,
10 | from_email=settings.MAIL_DEFAULT_SENDER,
11 | recipient_list=[email for name, email in settings.ADMINS])
12 |
--------------------------------------------------------------------------------
/project/celery.py:
--------------------------------------------------------------------------------
1 | import os
2 | from celery import Celery
3 |
4 | # set the default Django settings module for the 'celery' program.
5 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'local_settings')
6 |
7 | app = Celery('intake')
8 |
9 | # Using a string here means the worker don't have to serialize
10 | # the configuration object to child processes.
11 | # - namespace='CELERY' means all celery-related configuration keys
12 | # should have a `CELERY_` prefix.
13 | app.config_from_object('django.conf:settings', namespace='CELERY')
14 |
15 | # Load task modules from all registered Django app configs.
16 | app.autodiscover_tasks()
17 |
18 |
19 | @app.task(bind=True)
20 | def debug_task(self):
21 | print('Request: {0!r}'.format(self.request))
22 |
--------------------------------------------------------------------------------
/project/decorators.py:
--------------------------------------------------------------------------------
1 | import logging
2 | from functools import wraps
3 | from django.conf import settings
4 |
5 |
6 | # Get an instance of a logger
7 | logger = logging.getLogger(__name__)
8 |
9 |
10 | def run_if_setting_true(setting_name, alternate_return_value):
11 | def true_decorator(func):
12 | @wraps(func)
13 | def wrapped(*args, **kwargs):
14 | if not getattr(settings, setting_name, False):
15 | logger.info(
16 | "{} caused skipped function call {}".
17 | format(setting_name, func.__name__))
18 | return alternate_return_value
19 | return func(*args, **kwargs)
20 | return wrapped
21 | return true_decorator
22 |
--------------------------------------------------------------------------------
/project/exceptions.py:
--------------------------------------------------------------------------------
1 |
2 | class InvalidQueryParamsError(Exception):
3 | pass
4 |
--------------------------------------------------------------------------------
/project/heroku_wsgi.py:
--------------------------------------------------------------------------------
1 | import os
2 | from django.core.wsgi import get_wsgi_application
3 |
4 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings.prod")
5 |
6 | application = get_wsgi_application()
7 |
--------------------------------------------------------------------------------
/project/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/project/services/__init__.py
--------------------------------------------------------------------------------
/project/services/mixpanel_service.py:
--------------------------------------------------------------------------------
1 | from mixpanel import Mixpanel
2 | from . import logging_service
3 | from django.conf import settings
4 |
5 |
6 | _mixpanel_client = None
7 |
8 |
9 | def get_mixpanel_client():
10 | # Why this? seems like there must be a simpler way
11 | global _mixpanel_client
12 | if _mixpanel_client is None:
13 | mixpanel_key = getattr(settings, 'MIXPANEL_KEY', None)
14 | if mixpanel_key:
15 | _mixpanel_client = Mixpanel(mixpanel_key)
16 | return _mixpanel_client
17 |
--------------------------------------------------------------------------------
/project/services/query_params.py:
--------------------------------------------------------------------------------
1 | from django.urls import reverse
2 | from ..exceptions import InvalidQueryParamsError
3 |
4 |
5 | def get_ids_from_query_params(request, key='ids', sep=','):
6 | string_value = request.GET.get(key, '')
7 | str_ids = string_value.split(sep)
8 | try:
9 | ids = [int(str_id) for str_id in str_ids]
10 | except ValueError as err:
11 | raise InvalidQueryParamsError(
12 | "Received invalid query params: {url}".format(
13 | url=request.get_full_path()))
14 | return ids
15 |
16 |
17 | def get_url_for_ids(view_name, ids, key='ids'):
18 | url = reverse(view_name)
19 | params = '?' + key + '=' + ','.join(sorted([str(i) for i in ids]))
20 | return url + params
21 |
--------------------------------------------------------------------------------
/project/settings/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/project/settings/__init__.py
--------------------------------------------------------------------------------
/project/settings/development.py:
--------------------------------------------------------------------------------
1 | # This file intentionally left blank.
2 | # Developers maintain their own uncommitted `local_settings.py` files in the project root
3 | # For an example of a `local_settings.py` file, see `local_settings.py.example`
4 |
--------------------------------------------------------------------------------
/project/settings/review.py:
--------------------------------------------------------------------------------
1 | import dj_database_url
2 | from project.settings.deployed import *
3 |
4 | # looks for 'DATABASE_URL' environmental variable
5 | DATABASES = {
6 | 'default': dj_database_url.config(ssl_require=True),
7 | 'purged': dj_database_url.config(ssl_require=True),
8 | }
9 |
10 | # Settings for file uploads
11 | AWS_ACCESS_KEY_ID = os.environ.get('BUCKETEER_AWS_ACCESS_KEY_ID')
12 | AWS_SECRET_ACCESS_KEY = os.environ.get('BUCKETEER_AWS_SECRET_ACCESS_KEY')
13 | AWS_STORAGE_BUCKET_NAME = os.environ.get('BUCKETEER_BUCKET_NAME')
14 |
--------------------------------------------------------------------------------
/project/settings/test.py:
--------------------------------------------------------------------------------
1 | DIVERT_REMOTE_CONNECTIONS = True
2 | ALLOW_REQUESTS_TO_MAILGUN = False
3 | VOICEMAIL_NOTIFICATION_EMAIL = "test@example.com"
4 |
--------------------------------------------------------------------------------
/project/templates/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow: /* # disallow all
3 | {{ rules|safe }}
4 |
--------------------------------------------------------------------------------
/project/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/project/tests/__init__.py
--------------------------------------------------------------------------------
/project/tests/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/project/tests/services/__init__.py
--------------------------------------------------------------------------------
/project/tests/test_decorators.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | from project.decorators import run_if_setting_true
4 |
5 |
6 | class TestRunIfSettingTrue(TestCase):
7 |
8 | @run_if_setting_true("MY_SETTING", "foo")
9 | def sample_function(self):
10 | return "bar"
11 |
12 | def test_with_setting_undefined(self):
13 | self.assertEqual(self.sample_function(), "foo")
14 |
15 | def test_with_setting_true(self):
16 | with self.settings(MY_SETTING=True):
17 | self.assertEqual(self.sample_function(), "bar")
18 |
19 | def test_with_setting_false(self):
20 | with self.settings(MY_SETTING=False):
21 | self.assertEqual(self.sample_function(), "foo")
22 |
--------------------------------------------------------------------------------
/project/tests/utils.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 |
3 |
4 | def login(client, profile):
5 | client.login(
6 | username=profile.user.username,
7 | password=settings.TEST_USER_PASSWORD)
8 |
--------------------------------------------------------------------------------
/project/wsgi.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from django.core.wsgi import get_wsgi_application
4 | application = get_wsgi_application()
5 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # Included because many PaaS require a requirements.txt file
2 | # in the project root.
3 |
4 | -r requirements/prod.txt
5 |
--------------------------------------------------------------------------------
/requirements/ci.txt:
--------------------------------------------------------------------------------
1 | # Dependencies for automated testing via CircleCI
2 | -r prod.txt
3 | -r dev.txt
--------------------------------------------------------------------------------
/requirements/dev.txt:
--------------------------------------------------------------------------------
1 | # Requirements for development and testing
2 | -r app.txt
3 |
4 | xlrd==1.2.0
5 | autopep8~=1.5
6 | pep8~=1.7
7 | coverage~=5.0.3
8 | codeclimate-test-reporter~=0.2
9 | beautifulsoup4==4.8.2
10 | selenium~=3.141.0
11 | behave-django~=1.3
12 |
--------------------------------------------------------------------------------
/requirements/prod.txt:
--------------------------------------------------------------------------------
1 | # Requirements for production
2 | -r app.txt
3 |
4 | sentry-sdk==0.14.3
5 | gunicorn==20.0.4
6 | dj-database-url==0.5.0
7 | django-celery-beat==2.0.0
8 | boto==2.49.0
9 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.6.10
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [pycodestyle]
2 | exclude = migrations,lib,bin,node_modules,mock_serialized_apps.py,mock_user_agents.py,local_settings.py,src,notes,venv36
3 | max-line-length = 120
4 | ignore = W606,E123,E121,E126,W504
5 |
--------------------------------------------------------------------------------
/system.properties:
--------------------------------------------------------------------------------
1 | java.runtime.version=1.8 # Default
2 |
--------------------------------------------------------------------------------
/templates/admin_base_single_column.jinja:
--------------------------------------------------------------------------------
1 | {% extends "cmr_base.jinja" %}
2 |
3 | {%- block head_title -%}
4 | Clear My Record
5 | {%- endblock head_title -%}
6 |
7 | {% block content %}
8 |
9 |
10 |
11 |
12 |
13 | {%- block header_title -%}
14 | {%- endblock header_title -%}
15 |
16 | {% block column_content %}
17 | {% endblock column_content %}
18 |
19 |
20 |
21 |
22 | {% endblock content %}
23 |
--------------------------------------------------------------------------------
/templates/admin_form_base.jinja:
--------------------------------------------------------------------------------
1 | {% extends "admin_base_single_column.jinja" %}
2 | {%- block section_class %}form{% endblock section_class -%}
3 | {% block column_content %}
4 | {% block form %}
5 | {% endblock form %}
6 | {% endblock column_content %}
--------------------------------------------------------------------------------
/templates/app_bundle_action_bar.jinja:
--------------------------------------------------------------------------------
1 | {#-
2 | This displays the set of actions relating to an application bundle
3 | that are available to a user.
4 |
5 | In the future, the set of actions should be determined through more detailed
6 | permissions. But for now the actions will be hardcoded
7 |
8 | context:
9 | bundle - an ApplicationBundle
10 |
11 | #}
12 |
13 |
14 | Get a printout of these cases
15 |
16 |
--------------------------------------------------------------------------------
/templates/app_history.jinja:
--------------------------------------------------------------------------------
1 | {% extends "app_detail.jinja" %}
2 |
3 | {%- block page_heading -%}
4 | Application History
5 | {%- endblock page_heading -%}
6 |
7 |
8 |
9 | {%- block app_detail_contents -%}
10 |
19 | {%- endblock app_detail_contents -%}
20 |
21 |
--------------------------------------------------------------------------------
/templates/app_reviewer_list.jinja:
--------------------------------------------------------------------------------
1 | {%- if no_results %}
2 | {{ no_results }}
3 | {%- else %}
4 |
5 |
6 | Date
7 | Last Name
8 | First Name
9 | {%- if show_pdf %}
10 | Intake PDF
11 | {%- endif %}
12 | Status
13 | Latest Status Update
14 | Actions
15 |
16 |
17 | {%- for app in results %}
18 | {%- if app.was_transferred_out %}
19 | {%- include "includes/org_user_transferred_app_listing.jinja" %}
20 | {%- else %}
21 | {%- include "includes/org_user_app_index_listing.jinja" %}
22 | {%- endif %}
23 | {%- endfor %}
24 |
25 | {%- endif %}
--------------------------------------------------------------------------------
/templates/cmr_base.jinja:
--------------------------------------------------------------------------------
1 | {% extends "base.jinja" %}
2 |
3 | {% block css %}
4 | {% compress 'css' %}
5 |
6 | {% endcompress %}
7 | {% endblock css %}
8 |
9 | {% block body %}
10 | {% include "includes/header.jinja" %}
11 | {% block main %}
12 | {% block content %}
13 | {% endblock content %}
14 | {% endblock main %}
15 | {% endblock body %}
16 |
--------------------------------------------------------------------------------
/templates/create_status_update.jinja:
--------------------------------------------------------------------------------
1 | {% extends "admin_form_base.jinja" %}
2 | {% import 'macros.jinja' as macros %}
3 |
4 | {%- block header_title -%}
5 | Update Application Status for {{ submission.get_full_name() }}
6 | {%- endblock header_title -%}
7 |
8 | {% block form %}
9 |
10 | {% include "includes/minimal_latest_status_line.jinja" %}
11 |
12 |
19 | {% endblock form %}
--------------------------------------------------------------------------------
/templates/email/app_bundle_email.jinja:
--------------------------------------------------------------------------------
1 | As of {{ current_local_time('%-I:%M %p %Z on %A %b %-d') }}, {{ org_name }} has
2 | {%- if unread_count == 1 %} one unread application{% else %} {{ unread_count }} unread applications
3 | {%- endif %} to Clear My Record.
4 |
5 | You can review and print them at this link:
6 | {{ unread_redirect_link }}
7 |
8 | There are also {{ update_count }} applications awaiting a status update. You can review them at this link:
9 | {{ needs_update_redirect_link }}
10 |
11 | You may also review all {{ all_count }} applications at this link:
12 | {{ all_redirect_link }}
13 |
14 | If you have any questions or concerns, email us at clearmyrecord@codeforamerica.org and we will get back to you right away.
15 |
16 | Best,
17 |
18 | Clear My Record team
19 | clearmyrecord@codeforamerica.org
20 |
--------------------------------------------------------------------------------
/templates/email/applicant_edit_notification.jinja:
--------------------------------------------------------------------------------
1 | Hello,
2 |
3 | Your application has been updated by {{org_name}}.
4 | Here is the information that was changed:
5 |
6 | {%- for field in changed_fields %}
7 | - {{ field }}
8 | {%- endfor %}
9 |
10 | You are receiving this email because Clear My Record has an application on file with this email address.
11 | {%- if is_old_contact_info %}
12 | This is the last email you will get from us at this email address.
13 | {%- endif %}
14 |
15 | We value your privacy. If you did not approve this change or would like more information, reply to this email to contact {{ org_name }}.
16 |
--------------------------------------------------------------------------------
/templates/email/confirmation.jinja:
--------------------------------------------------------------------------------
1 | Hi {{ name|safe }},
2 |
3 | Thanks for applying online to Clear My Record.
4 | {%- if organizations %} Since you applied for help in {{ oxford_comma(county_names)|safe }}, we are sending your application to {{ oxford_comma(organizations)|safe }}.{% endif %}
5 | {{ next_steps|join(' ')|safe }}
6 | {% if unlisted_counties %}
7 | Next steps for {{ unlisted_counties|safe }}:
8 | We will contact you in the next week with information on how to clear your record in {{ unlisted_counties|safe }}
9 | {%- endif %}
10 |
11 | Take care,
12 | {{ staff_name|safe }} at Clear My Record
--------------------------------------------------------------------------------
/templates/email/followup.jinja:
--------------------------------------------------------------------------------
1 | Hello again {{ name|safe }},
2 |
3 | This is {{ staff_name|safe }} from Clear My Record. You applied online about one month ago for help in {{ counties_applied_to|safe }} and we sent your application to {{ oxford_comma(organization_names)|safe }}. I'm just checking to see how things are going.
4 |
5 | {% for followup_message in followup_messages -%}
6 | {{ followup_message|safe }}
7 | {% endfor %}
8 | Best,
9 |
10 | {{ staff_name|safe }} at Clear My Record
--------------------------------------------------------------------------------
/templates/email/org_edit_notification.jinja:
--------------------------------------------------------------------------------
1 | The information for applicant {{ applicant_name }} has been edited by {{ editor_email }} from {{ editor_org_name }}. You may want to update your organization's records.
2 |
3 |
4 | {%- for field, values in safe_data_diff.items() %}
5 |
6 | ------------
7 | Updated {{ field }}
8 |
9 | Before:
10 | {{ (values['before'] or "(Blank)") }}
11 |
12 | After:
13 | {{ (values['after'] or "(Blank)") }}
14 |
15 | {%- endfor %}
16 | {%- for field in unsafe_changed_keys %}
17 |
18 | ------------
19 | Updated {{ field }}
20 |
21 | {% endfor %}
22 |
23 | You can view {{ applicant_name }}'s full application here:
24 | {{ app_detail_url }}
25 |
26 |
27 | If you have any questions, please feel free to email us at:
28 | clearmyrecord@codeforamerica.org
29 |
--------------------------------------------------------------------------------
/templates/followup_list.jinja:
--------------------------------------------------------------------------------
1 |
2 |
3 | ID
4 | Received
5 | Name
6 | Contact
7 | Orgs & Statuses
8 | {%- if perms.intake.view_application_note %}
9 | Notes
10 | Tags
11 | {%- endif %}
12 |
13 | {% include "followup_list_rows.jinja" %}
14 |
--------------------------------------------------------------------------------
/templates/followup_list_rows.jinja:
--------------------------------------------------------------------------------
1 | {#
2 | expects a 'results' to be data from FormSubmissionFollowupListSerializer
3 | expects humanize, perms
4 | -#}
5 | {% for sub in results %}
6 | {%- include "includes/followup_list_row.jinja" %}
7 | {%- endfor %}
--------------------------------------------------------------------------------
/templates/forms/county_selection.jinja:
--------------------------------------------------------------------------------
1 | {% extends "forms/county_form.jinja" %}
2 |
3 | {% block county_scope %}
4 | {% endblock county_scope %}
5 |
6 | {% block form_content %}
7 |
8 | {{ form.render() }}
9 | {{ _("Apply") }}
10 | {% endblock form_content %}
--------------------------------------------------------------------------------
/templates/forms/declaration_letter_form.jinja:
--------------------------------------------------------------------------------
1 | {% extends "forms/county_form.jinja" %}
2 |
3 |
4 | {%- block header_title -%}
5 | Create Your Letter
6 | {%- endblock header_title -%}
7 |
8 |
9 | {%- block submit_button_label -%}
10 | Review your letter
11 | {%- endblock submit_button_label -%}
--------------------------------------------------------------------------------
/templates/gcf-style-flash-messages.jinja:
--------------------------------------------------------------------------------
1 | {#-
2 | this include is intended to appear before the header or any other content
3 | -#}
4 |
5 | {%- if messages -%}
6 | {%- for message in messages -%}
7 |
20 | {%- endfor %}
21 | {%- endif %}
22 |
23 |
--------------------------------------------------------------------------------
/templates/gcf-style-public-header.jinja:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/gcf_style_base.jinja:
--------------------------------------------------------------------------------
1 | {% extends "base.jinja" %}
2 |
3 | {% block css %}
4 | {% compress 'css' %}
5 |
6 | {% endcompress %}
7 | {% endblock css %}
8 |
9 |
10 | {% block body_class %}cfa-style{% endblock body_class %}
11 |
12 | {% block body %}
13 |
14 | {% include "gcf-style-flash-messages.jinja" %}
15 | {% include "gcf-style-public-header.jinja" %}
16 |
17 | {% block content %}
18 | {% endblock content %}
19 |
20 | {% include "gcf-style-footer.jinja" %}
21 |
22 | {% endblock body %}
--------------------------------------------------------------------------------
/templates/includes/application_next_steps.jinja:
--------------------------------------------------------------------------------
1 |
2 | {%- for organization in organizations %}
3 |
4 | {%- if organization.county.slug != 'not_listed' %}
5 | To help you with {{ organization.county.name }} County, we sent your application to the
6 | {{ organization.name }} .
7 | {{ linkify(organization.long_confirmation_message) }}
8 | {% endif %}
9 |
10 | {%- endfor %}
11 | {%- if unlisted_counties %}
12 |
13 | We will contact you in the next week with information on how to clear your record in {{ unlisted_counties }}.
14 |
15 | {% endif %}
16 |
--------------------------------------------------------------------------------
/templates/includes/auth_bar.jinja:
--------------------------------------------------------------------------------
1 | {% if request.user.is_authenticated %}
2 |
9 | {% endif %}
--------------------------------------------------------------------------------
/templates/includes/back_to_home_button.jinja:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/templates/includes/cmr_contact_info.jinja:
--------------------------------------------------------------------------------
1 |
2 | {{ _("If you have any questions or concerns, please email us at")}}
3 | {{ linkify(content.cmr_email) }}
4 | {{ _("or text us at")}}
5 | {{ linkify(content.cmr_phone_number) }}
6 |
--------------------------------------------------------------------------------
/templates/includes/county_list.jinja:
--------------------------------------------------------------------------------
1 | {%- if county_list %}
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{ _("You are applying for help in ") -}}
9 | {{- oxford_comma(county_list) }}. {{ _("Switch counties") }} .
10 |
11 |
12 |
13 |
14 |
15 |
16 | {%- endif %}
--------------------------------------------------------------------------------
/templates/includes/csrf_field.jinja:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/templates/includes/empty_status_summary.jinja:
--------------------------------------------------------------------------------
1 |
2 |
3 | Current Status:
4 |
5 | New
6 |
7 |
--------------------------------------------------------------------------------
/templates/includes/flash_messages.jinja:
--------------------------------------------------------------------------------
1 |
2 | {% block flash_messages %}
3 |
4 | {%- if messages -%}
5 | {%- for message in messages -%}
6 |
17 | {%- endfor %}
18 | {%- endif %}
19 |
20 | {% endblock %}
--------------------------------------------------------------------------------
/templates/includes/google_analytics.jinja:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/templates/includes/header.jinja:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/templates/includes/latest_status_summary_for_incoming_transfer.jinja:
--------------------------------------------------------------------------------
1 |
2 |
3 | Current Status:
4 |
5 | Transferred from {{
6 | transfer.status_update.application.organization.name
7 | }}
8 | by {{transfer.status_update.author.profile.name}}
9 |
10 |
11 | Reason:
12 |
13 | {{transfer.reason}}
14 |
15 |
--------------------------------------------------------------------------------
/templates/includes/latest_status_summary_for_outgoing_transfer.jinja:
--------------------------------------------------------------------------------
1 |
2 |
3 | Current Status:
4 |
5 | {{application.latest_status.status_type.display_name}} to {{
6 | application.latest_status.transfer.new_application.organization.name
7 | }} by {{application.latest_status.author.profile.name}}
8 |
9 |
10 | Reason:
11 |
12 | {{application.latest_status.transfer.reason}}
13 |
14 |
--------------------------------------------------------------------------------
/templates/includes/minimal_latest_status_line.jinja:
--------------------------------------------------------------------------------
1 | {#
2 | assumes 'application' is in the context
3 | -#}
4 |
5 | {%- if application.latest_status %}
6 | Current status:
7 |
10 | {{ application.latest_status.status_type.display_name }}
11 | ({{ humanize.naturaltime(application.latest_status.created) }}
12 | by {{ application.latest_status.author.profile.name }})
13 |
14 | {%- else %}
15 | New (no status updates yet)
16 | {%- endif %}
17 |
18 |
--------------------------------------------------------------------------------
/templates/includes/public_flash_messages.jinja:
--------------------------------------------------------------------------------
1 |
2 | {% block flash_messages %}
3 |
4 | {%- if messages -%}
5 | {%- for message in messages -%}
6 |
17 | {%- endfor %}
18 | {%- endif %}
19 |
20 | {% endblock %}
--------------------------------------------------------------------------------
/templates/includes/public_topbar.jinja:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/templates/includes/submission_display_actions.jinja:
--------------------------------------------------------------------------------
1 | {%- if form.submission and request %}
2 |
15 | {%- endif %}
--------------------------------------------------------------------------------
/templates/newapps_pdf_detail.jinja:
--------------------------------------------------------------------------------
1 | {% extends "cmr_base.jinja" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{ app_count }} applications to the {{ organization.name }}
12 |
13 |
14 |
15 |
16 |
23 |
24 |
25 | {% endblock content %}
--------------------------------------------------------------------------------
/templates/partner_list.jinja:
--------------------------------------------------------------------------------
1 | {% extends "public_base_single_column.jinja" %}
2 |
3 |
4 | {%- block header_title -%}
5 | {{ _("Our Partners") }}
6 | {%- endblock header_title -%}
7 |
8 | {%- block section_class %}partners{% endblock section_class -%}
9 |
10 | {% block column_content %}
11 | {%- for county in counties %}
12 | {{ county.name }} County
13 |
22 |
23 | {%- endfor %}
24 | {% endblock column_content %}
--------------------------------------------------------------------------------
/templates/public_base_single_column.jinja:
--------------------------------------------------------------------------------
1 | {% extends "public_base.jinja" %}
2 |
3 | {% block body_class -%}public{%- endblock body_class %}
4 |
5 | {% block content %}
6 |
7 |
8 |
9 |
10 | {% block column_content %}
11 | {% endblock column_content %}
12 |
13 |
14 |
15 |
16 | {% endblock content %}
17 |
--------------------------------------------------------------------------------
/templates/slack/app_bundle_sent.jinja:
--------------------------------------------------------------------------------
1 | {{ org_name }} has:
2 | {%- if unread_count > 0 %}
3 | {{ unread_count }} unread applications. (Emailed {{ oxford_comma(emails) }})
4 | {%- else %}
5 | no unread applications. (Did not email {{ oxford_comma(emails) }})
6 | {%- endif %}
7 | {{ update_count }} applications needing status updates out of {{ all_count }} total applications
--------------------------------------------------------------------------------
/templates/slack/bundle_action.jinja:
--------------------------------------------------------------------------------
1 | {{ user.email }} {{ action }}{% if submissions|length > 1 %} apps from <{{ bundle_url}}|{{
2 | oxford_comma(submissions) }}>{% else %} <{{bundle_url}}|{{ submissions[0] }}'s application>{% endif %}
--------------------------------------------------------------------------------
/templates/slack/bundle_viewed.jinja:
--------------------------------------------------------------------------------
1 | {{ user.email }} {{ action }}{% if len(submissions) > 1 %} apps from {{
2 | oxford_comma(submissions) }}{% else %} {{ submissions[0] }}'s app{% endif %}
--------------------------------------------------------------------------------
/templates/slack/new_submission.jinja:
--------------------------------------------------------------------------------
1 | New submission #{{submission_count}} to {{ oxford_comma(submission.get_nice_counties())}}!
2 | <{{ request.build_absolute_uri(
3 | url('intake-app_detail',
4 | submission_id=submission.id)
5 | ) }}|{{ submission.get_anonymous_display() }}>
6 | {% if submission.get_nice_contact_preferences() -%}
7 | They want to be contacted via {{ oxford_comma(submission.get_nice_contact_preferences())}}
8 | {% else -%}
9 | They didn't give a contact method
10 | {%- endif %}
--------------------------------------------------------------------------------
/templates/slack/notification_failed.jinja:
--------------------------------------------------------------------------------
1 | {{ notification_type }} by {{ oxford_comma(errors.keys()) }} for {{ submission.get_anonymous_display() }} failed with errors:
2 | ```{% for method, error in errors.items() %}
3 | {{ method }}:
4 | {{ error }}
5 | {% endfor %}```
--------------------------------------------------------------------------------
/templates/slack/notification_sent.jinja:
--------------------------------------------------------------------------------
1 | {% for method in methods %}
2 | {%- if method in ['email', 'sms'] -%}
3 | Successfully sent a {{ notification_type }} to {{ submission.anonymous_name }} via {{ method }}
4 | {%- else -%}
5 | Did not send a {{ notification_type }} to {{ submission.anonymous_name }} via {{ method }}
6 | {%- endif %}
7 | {% endfor %}
--------------------------------------------------------------------------------
/templates/slack/submission_action.jinja:
--------------------------------------------------------------------------------
1 | {{ user.email }} {{ action }} <{{ submission.get_external_url() }}|{{ submission }}'s application>
--------------------------------------------------------------------------------
/templates/slack/submission_deleted.jinja:
--------------------------------------------------------------------------------
1 | {{ user.email }} deleted {{ submission.get_anonymous_display() }}'s application
--------------------------------------------------------------------------------
/templates/slack/submission_viewed.jinja:
--------------------------------------------------------------------------------
1 | {{ user.email }} looked at {{ submission.get_anonymous_display() }}'s application
--------------------------------------------------------------------------------
/templates/text/applicant_edit_notification.jinja:
--------------------------------------------------------------------------------
1 | Clear My Record update by {{org_name}}
2 |
3 | Your application has been updated with new {{ oxford_comma(changed_fields) }}.
4 | {%- if is_old_contact_info %}
5 | This is the last text message you will get from us at this phone number.
6 | {%- endif %}
7 |
8 | If you did not request this change or would like more info, please {{ org_contact_info }}
9 | to contact {{ org_name }}.
--------------------------------------------------------------------------------
/templates/text/confirmation.jinja:
--------------------------------------------------------------------------------
1 | Hi {{ name|safe }}, thanks for applying to Clear My Record.{% for step in next_steps %} {{ step|safe }}{% endfor -%}{%- if unlisted_counties %} For {{ unlisted_counties|safe }} we'll contact you in the next week.{% endif %}
2 | - {{ staff_name }} at Clear My Record
--------------------------------------------------------------------------------
/templates/text/followup.jinja:
--------------------------------------------------------------------------------
1 | Hi again {{ name|safe }}, this is {{ staff_name|safe }} from Clear My Record. You applied about a month ago for help in {{ oxford_comma(county_names)|safe }}.
2 | {%- for followup_message in followup_messages %}
3 | {{ followup_message|safe }}
4 | {%- endfor %}
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/tests/__init__.py
--------------------------------------------------------------------------------
/tests/sample_pdfs/sample_form.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/tests/sample_pdfs/sample_form.pdf
--------------------------------------------------------------------------------
/tests/sample_pdfs/sample_form_filled.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/tests/sample_pdfs/sample_form_filled.pdf
--------------------------------------------------------------------------------
/tests/sample_translator.py:
--------------------------------------------------------------------------------
1 | from intake.translators.base import FormToPDFTranslator
2 |
3 |
4 | translate = FormToPDFTranslator({
5 | 'Given Name Text Box': lambda s: s.answers['first_name'].capitalize(),
6 | 'Family Name Text Box': 'last_name',
7 | 'Address 1 Text Box': 'address_street',
8 | 'Postcode Text Box': 'address_zip',
9 | 'City Text Box': 'address_city'
10 | }, att_object_extractor='answers')
11 |
--------------------------------------------------------------------------------
/user_accounts/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/user_accounts/__init__.py
--------------------------------------------------------------------------------
/user_accounts/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from . import models
3 |
4 |
5 | class AddressInline(admin.StackedInline):
6 | model = models.Address
7 | extra = 1
8 |
9 |
10 | @admin.register(models.Organization)
11 | class OrganizationAdmin(admin.ModelAdmin):
12 | inlines = [
13 | AddressInline
14 | ]
15 |
16 |
17 | @admin.register(models.UserProfile)
18 | class UserProfileAdmin(admin.ModelAdmin):
19 | def get_actions(self, request):
20 | actions = super(UserProfileAdmin, self).get_actions(request)
21 | if 'delete_selected' in actions:
22 | del actions['delete_selected']
23 | return actions
24 |
25 | def has_delete_permission(self, request, obj=None):
26 | return False
27 |
--------------------------------------------------------------------------------
/user_accounts/base_views.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.mixins import UserPassesTestMixin
2 |
3 |
4 | class StaffOnlyMixin(UserPassesTestMixin):
5 |
6 | def test_func(self):
7 | return self.request.user.is_staff
8 |
--------------------------------------------------------------------------------
/user_accounts/exceptions.py:
--------------------------------------------------------------------------------
1 | class MissingInvitationError(Exception):
2 | '''Can't find a matching invitation for a user during signup
3 | '''
4 | pass
5 |
6 |
7 | class UnacceptedInviteError(Exception):
8 | '''The user has not yet accepted this invite
9 | '''
10 | pass
11 |
12 |
13 | class UndefinedResourceAccessError(Exception):
14 | '''Someone should not have access to this resource
15 | '''
16 | pass
17 |
18 |
19 | class NoEmailsForOrgError(Exception):
20 | '''There is no email contact available for this organization
21 | '''
22 | pass
23 |
--------------------------------------------------------------------------------
/user_accounts/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/user_accounts/management/__init__.py
--------------------------------------------------------------------------------
/user_accounts/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/user_accounts/management/commands/__init__.py
--------------------------------------------------------------------------------
/user_accounts/management/commands/create_email_forwarding_for_users.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | from user_accounts.models import UserProfile
4 | from intake.services.mailgun_api_service import set_route_for_user_profile
5 |
6 |
7 | class Command(BaseCommand):
8 | help = 'Creates Mailgun routes for each user profile'
9 |
10 | def handle(self, *args, **options):
11 | self.stdout.write('Sending route creation commands to Mailgun')
12 | for profile in UserProfile.objects.order_by('organization__slug'):
13 | set_route_for_user_profile(profile)
14 | message = '\t{} --> {}'.format(
15 | profile.get_clearmyrecord_email(),
16 | profile.user.email
17 | )
18 | self.stdout.write(message)
19 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9 on 2016-05-24 00:40
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='Organization',
18 | fields=[
19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20 | ('name', models.CharField(max_length=50)),
21 | ('website', models.URLField()),
22 | ('blurb', models.TextField()),
23 | ],
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0004_userprofile_should_get_notifications.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.7 on 2016-06-23 18: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 | ('user_accounts', '0003_auto_20160525_1728'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='userprofile',
17 | name='should_get_notifications',
18 | field=models.BooleanField(default=False),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0005_organization_is_receiving_agency.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.7 on 2016-06-23 18:30
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 | ('user_accounts', '0004_userprofile_should_get_notifications'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='organization',
17 | name='is_receiving_agency',
18 | field=models.BooleanField(default=False),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0006_add_county_model.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.7 on 2016-07-16 22:26
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 | ('intake', '0013_add_county_model'),
13 | ('user_accounts', '0005_organization_is_receiving_agency'),
14 | ]
15 |
16 | operations = [
17 | migrations.AddField(
18 | model_name='organization',
19 | name='county',
20 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='organizations', to='intake.County'),
21 | ),
22 | ]
23 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0008_add_profiles_related_name_to_organization.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.9 on 2016-08-12 22:46
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 | ('user_accounts', '0007_add_default_orgs_for_counties'),
13 | ]
14 |
15 | operations = [
16 | migrations.AlterField(
17 | model_name='userprofile',
18 | name='organization',
19 | field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='profiles', to='user_accounts.Organization'),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0009_organization_slug.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.9 on 2016-08-18 17: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 | ('user_accounts', '0008_add_profiles_related_name_to_organization'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='organization',
17 | name='slug',
18 | field=models.SlugField(null=True, unique=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0012_organization_show_pdf_only.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.9 on 2016-09-07 04:17
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 | ('user_accounts', '0011_organization_confirmation_message_contact_info_etc'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='organization',
17 | name='show_pdf_only',
18 | field=models.BooleanField(default=False),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0014_long_and_short_confirmation_messages.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.9 on 2016-09-20 01:32
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 | ('user_accounts', '0013_address'),
12 | ]
13 |
14 | operations = [
15 | migrations.RenameField(
16 | model_name='organization',
17 | old_name='new_submission_confirmation_message',
18 | new_name='long_confirmation_message',
19 | ),
20 | migrations.AddField(
21 | model_name='organization',
22 | name='short_confirmation_message',
23 | field=models.TextField(blank=True),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0015_organization_notify_on_weekends.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.1 on 2016-10-07 19:53
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 | ('user_accounts', '0014_long_and_short_confirmation_messages'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='organization',
17 | name='notify_on_weekends',
18 | field=models.BooleanField(default=False),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0017_organization_followup_message_fields.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.1 on 2016-12-13 00:29
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 | ('user_accounts', '0016_add_more_invitation_options'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='organization',
17 | name='long_followup_message',
18 | field=models.TextField(blank=True),
19 | ),
20 | migrations.AddField(
21 | model_name='organization',
22 | name='short_followup_message',
23 | field=models.TextField(blank=True),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0019_order_orgs_by_name.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.1 on 2017-01-24 21:42
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('user_accounts', '0018_org_accepting_apps_checking_notifications'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterModelOptions(
16 | name='organization',
17 | options={'ordering': ['name']},
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0020_organization_is_live.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.1 on 2017-01-25 18:05
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 | ('user_accounts', '0019_order_orgs_by_name'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='organization',
17 | name='is_live',
18 | field=models.BooleanField(default=False),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0022_organization_needs_applicant_followups.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10 on 2017-04-11 21: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 | ('user_accounts', '0021_organization_transfer_partners'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='organization',
17 | name='needs_applicant_followups',
18 | field=models.BooleanField(default=False),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0023_organization_fax_number.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10 on 2017-05-11 21:32
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 | ('user_accounts', '0022_organization_needs_applicant_followups'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='organization',
17 | name='fax_number',
18 | field=models.TextField(blank=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0024_userprofile_uuid.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10 on 2017-06-16 18:05
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 | import uuid
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('user_accounts', '0023_organization_fax_number'),
13 | ]
14 |
15 | operations = [
16 | migrations.AddField(
17 | model_name='userprofile',
18 | name='uuid',
19 | field=models.UUIDField(default=uuid.uuid4, editable=False),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0026_remove_hayward_clean_slate_clinic_from_addresses.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.8 on 2017-10-12 21:18
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | def delete_hayward_clean_slate_clinic(apps, schema_editor):
9 | Address = apps.get_model('user_accounts', 'Address')
10 | Address.objects.filter(name='Hayward Clean Slate Walk-in Clinic').delete()
11 |
12 |
13 | class Migration(migrations.Migration):
14 |
15 | dependencies = [
16 | ('user_accounts', '0025_purgedorganization'),
17 | ]
18 |
19 | operations = [
20 | migrations.RunPython(delete_hayward_clean_slate_clinic)
21 | ]
22 |
--------------------------------------------------------------------------------
/user_accounts/migrations/0027_remove_oakland_clinic_from_addresses.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from django.db import migrations
4 |
5 |
6 | def delete_oakland_clean_slate_clinic(apps, schema_editor):
7 | Address = apps.get_model('user_accounts', 'Address')
8 | Address.objects.filter(name='Oakland Clean Slate Walk-in Clinic',
9 | organization__slug='a_pubdef').delete()
10 |
11 |
12 | class Migration(migrations.Migration):
13 |
14 | dependencies = [
15 | ('user_accounts', '0026_remove_hayward_clean_slate_clinic_from_addresses'),
16 | ]
17 |
18 | operations = [
19 | migrations.RunPython(delete_oakland_clean_slate_clinic)
20 | ]
21 |
--------------------------------------------------------------------------------
/user_accounts/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/user_accounts/migrations/__init__.py
--------------------------------------------------------------------------------
/user_accounts/models/__init__.py:
--------------------------------------------------------------------------------
1 | from .address import Address
2 | from .invitation import Invitation
3 | from .organization import Organization, OrganizationManager
4 | from .user_profile import UserProfile, get_user_display
5 |
6 | __all__ = [
7 | Address,
8 | Invitation,
9 | Organization, OrganizationManager,
10 | UserProfile, get_user_display,
11 | ]
12 |
--------------------------------------------------------------------------------
/user_accounts/models/address.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class Address(models.Model):
5 | organization = models.ForeignKey(
6 | 'user_accounts.Organization',
7 | on_delete=models.CASCADE,
8 | related_name='addresses')
9 | name = models.TextField()
10 | text = models.TextField()
11 | walk_in_hours = models.TextField(blank=True)
12 |
13 | class Meta:
14 | verbose_name_plural = "Addresses"
15 |
16 | def __str__(self):
17 | return self.text
18 |
--------------------------------------------------------------------------------
/user_accounts/serializers/__init__.py:
--------------------------------------------------------------------------------
1 | from .user_serializer import UserMixpanelSerializer
2 | from .shortcuts import mixpanel_user_data
3 |
4 | __all__ = [
5 | UserMixpanelSerializer,
6 | mixpanel_user_data
7 | ]
8 |
--------------------------------------------------------------------------------
/user_accounts/serializers/shortcuts.py:
--------------------------------------------------------------------------------
1 | from .user_serializer import UserMixpanelSerializer
2 |
3 |
4 | def mixpanel_user_data(user):
5 | return UserMixpanelSerializer(user).data
6 |
--------------------------------------------------------------------------------
/user_accounts/serializers/user_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 | from intake.serializers.fields import ChainableAttributeField
3 |
4 |
5 | class UserMixpanelSerializer(serializers.Serializer):
6 | """This serializes user information from a user instance
7 | """
8 | user_organization_name = ChainableAttributeField(
9 | 'profile.organization.name')
10 | user_username = ChainableAttributeField('username')
11 |
--------------------------------------------------------------------------------
/user_accounts/tasks.py:
--------------------------------------------------------------------------------
1 | from celery import shared_task
2 |
3 |
4 | @shared_task
5 | def create_mailgun_route(user_profile_id):
6 | from intake.services.mailgun_api_service import set_route_for_user_profile
7 | from user_accounts.models import UserProfile
8 | # TODO: Fix whatever is causing circular imports.
9 | profile = UserProfile.objects.get(pk=user_profile_id)
10 | set_route_for_user_profile(profile)
11 |
--------------------------------------------------------------------------------
/user_accounts/templates/account/email/password_reset_key_message.txt:
--------------------------------------------------------------------------------
1 | Hello,
2 |
3 | You're receiving this e-mail because you or someone else has requested a password for your account at Clear My Record.
4 |
5 | If you would like to reset your password, follow the link below:
6 |
7 | {{ password_reset_url }}
8 |
9 | If you did not request a password reset, you can safely ignore this email.
--------------------------------------------------------------------------------
/user_accounts/templates/account/email/password_reset_key_subject.txt:
--------------------------------------------------------------------------------
1 | Password Reset for Clear My Record
--------------------------------------------------------------------------------
/user_accounts/templates/invitations/email/email_invite_message.txt:
--------------------------------------------------------------------------------
1 | Hello,
2 |
3 | You've been invited to create an account on Clear My Record.
4 |
5 | If you'd like to join, please follow this link:
6 | {{ invite_url }}
--------------------------------------------------------------------------------
/user_accounts/templates/invitations/email/email_invite_subject.txt:
--------------------------------------------------------------------------------
1 | Invitation to create an account on Clear My Record
2 |
--------------------------------------------------------------------------------
/user_accounts/templates/user_accounts/invite_form.jinja:
--------------------------------------------------------------------------------
1 | {% extends "admin_form_base.jinja" %}
2 | {% import 'macros.jinja' as macros %}
3 |
4 | {%- block header_title -%}
5 | Invite a new user
6 | {%- endblock header_title -%}
7 | {% block form %}
8 |
16 | {% endblock form %}
--------------------------------------------------------------------------------
/user_accounts/templates/user_accounts/password_reset_sent.jinja:
--------------------------------------------------------------------------------
1 | {% extends "admin_base_single_column.jinja" %}
2 | {% block head_title %}Password Reset Sent{% endblock %}
3 | {%- block header_title -%}
4 | We've sent you an email.
5 | {%- endblock header_title -%}
6 | {% block column_content %}
7 | We've sent you an email with a link to reset your password. If you don't see it within a few minutes, let us know.
8 | {% endblock column_content %}
--------------------------------------------------------------------------------
/user_accounts/templates/user_accounts/request_password_reset.jinja:
--------------------------------------------------------------------------------
1 | {% extends "admin_form_base.jinja" %}
2 | {% import 'macros.jinja' as macros %}
3 | {% block head_title %}Reset password{% endblock %}
4 | {%- block header_title -%}
5 | Request a password reset
6 | {%- endblock header_title -%}
7 | {% block form %}
8 | Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it.
9 |
10 |
17 | {% endblock form %}
--------------------------------------------------------------------------------
/user_accounts/templates/user_accounts/signup.jinja:
--------------------------------------------------------------------------------
1 | {% extends "admin_form_base.jinja" %}
2 | {% import 'macros.jinja' as macros %}
3 | {% block head_title %}Sign up{% endblock %}
4 | {%- block header_title -%}
5 | Sign up
6 | {%- endblock header_title -%}
7 | {% block form %}
8 |
19 | {% endblock form %}
--------------------------------------------------------------------------------
/user_accounts/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/user_accounts/tests/__init__.py
--------------------------------------------------------------------------------
/user_accounts/tests/clients.py:
--------------------------------------------------------------------------------
1 | from django.test import Client
2 |
3 |
4 | class CsrfClient(Client):
5 |
6 | def __init__(self, **defaults):
7 | super().__init__(enforce_csrf_checks=True, **defaults)
8 |
9 | def get_csrf_token(self, response):
10 | return response.cookies['csrftoken'].value
11 |
12 | def fill_form(self, url, csrf_token=None, headers=None, **data):
13 | if not csrf_token:
14 | response = self.get(url)
15 | csrf_token = self.get_csrf_token(response)
16 | follow = data.pop('follow', False)
17 | data.update(csrfmiddlewaretoken=csrf_token)
18 | headers = headers or {}
19 | return self.post(url, data, follow=follow, **headers)
20 |
--------------------------------------------------------------------------------
/user_accounts/tests/factories/__init__.py:
--------------------------------------------------------------------------------
1 | from .user_factory import UserFactory
2 | from .user_profile_factory import (
3 | UserProfileFactory,
4 | fake_app_reviewer,
5 | profile_for_org_and_group_names,
6 | profile_for_slug_in_groups,
7 | app_reviewer,
8 | followup_user,
9 | monitor_user
10 | )
11 | from .organization_factory import (
12 | ExistingOrganizationFactory, FakeOrganizationFactory)
13 |
14 |
15 | __all__ = [
16 | UserFactory,
17 | UserProfileFactory,
18 | fake_app_reviewer,
19 | profile_for_org_and_group_names,
20 | profile_for_slug_in_groups,
21 | app_reviewer,
22 | followup_user,
23 | monitor_user,
24 | ExistingOrganizationFactory,
25 | FakeOrganizationFactory,
26 | ]
27 |
--------------------------------------------------------------------------------
/user_accounts/tests/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeforamerica/intake/8755e64c13e2b6f9bef9bbee47011253f20e7e0d/user_accounts/tests/models/__init__.py
--------------------------------------------------------------------------------