Created
July 20, 2016 21:30
-
-
Save bengolder/7efa8dda0de1f8d2e498afdd8bb8ae32 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from intake.forms.form_base import CombinableForm | |
from intake.constants import Counties | |
from intake.forms import fields | |
class OtherCountyForm(CombinableForm): | |
"""This is used by Code for America to send applicants | |
information on clean slate services in other counties or states. | |
""" | |
counties = {Counties.OTHER} | |
fields = { | |
fields.contact_preferences, | |
fields.first_name, | |
fields.phone_number, | |
fields.email, | |
fields.address, | |
fields.how_did_you_hea' | |
} | |
required_fields = { | |
fields.contact_preferences, | |
fields.first_name, | |
} | |
class SanFranciscoCountyForm(CombinableForm): | |
counties = {Counties.SAN_FRANCISCO} | |
fields = { | |
fields.contact_preferences, | |
fields.first_name, | |
fields.middle_name, | |
fields.last_name, | |
fields.phone_number, | |
fields.email, | |
fields.address, | |
fields.dob, | |
fields.ssn, | |
fields.us_citizen, | |
fields.serving_sentence, | |
fields.on_probation_parole, | |
fields.where_probation_parole, | |
fields.when_probation_parole, | |
fields.rap_outside_sf, | |
fields.when_where_outside_sf, | |
fields.financial_screening_note, | |
fields.currently_employed, | |
fields.monthly_income, | |
fields.monthly_expenses, | |
fields.how_did_you_hear, | |
} | |
required_fields = { | |
fields.first_name, | |
fields.last_name, | |
} | |
recommended_fields = { | |
fields.address, | |
fields.dob, | |
fields.ss' | |
} | |
class ContraCostaForm(CombinableForm): | |
"""Based on | |
https://ca-contracostacounty2.civicplus.com/FormCenter/Public-Defender-7/Prop-47-Contact-Form-144/ | |
""" | |
counties = {Counties.CONTRA_COSTA} | |
fields = { | |
fields.contact_preferences, | |
fields.first_name, | |
fields.middle_name, | |
fields.last_name, | |
fields.phone_number, | |
fields.email, | |
fields.address, | |
fields.dob, | |
fields.us_citizen, | |
fields.serving_sentence, | |
fields.on_probation_parole, | |
fields.financial_screening_note, | |
fields.currently_employed, | |
fields.monthly_income, | |
fields.income_source, | |
fields.monthly_expenses, | |
fields.case_number, | |
fields.how_did_you_hear, | |
fields.additional_informatio' | |
} | |
required_fields = { | |
fields.first_name, | |
fields.last_name, | |
fields.address, | |
fields.us_citizen, | |
fields.currently_employed, | |
fields.dob, | |
fields.monthly_income, | |
fields.income_source, | |
fields.monthly_expenses, | |
fields.serving_sentence, | |
fields.on_probation_parole, | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.contrib.postgres.fields import JSONField | |
from django.utils.translation import ugettext as _ | |
from intake import validators | |
import rest_framework | |
from rest_framework import serializers | |
YES_NO_CHOICES = ( | |
('yes', _('Yes')), | |
('no', _('No')), | |
) | |
class FalseIfHasEmptyValue: | |
def __bool__(self): | |
return all(vars(self).values()) | |
def __repr__(self): | |
fields = sorted(vars(self).keys()) | |
field_strs = ["{}='{}'".format(f, getattr(self, f)) for f in fields] | |
return '<{}({})>'.format(self.__class__.__name__, ', '.join(field_strs)) | |
def __eq__(self, other): | |
return vars(self) == vars(other) | |
class Address(FalseIfHasEmptyValue): | |
def __init__(self, street='', city='', state='', zip=''): | |
self.street = street | |
self.city = city | |
self.state = state | |
self.zip = zip | |
class DateOfBirth(FalseIfHasEmptyValue): | |
def __init__(self, month='', day='', year=''): | |
self.month = month | |
self.day = day | |
self.year = year | |
class ContactInfoJSONField(JSONField): | |
""" | |
A field for storing contact information that validates | |
data against expected keys and structure | |
""" | |
def validate(self, value, model_instance): | |
validators.contact_info_json(value) | |
super().validate(value, model_instance) | |
class FormFieldMixin: | |
"""A serializer field that adds some additional convenience attributes | |
for rendering as an HTML form and mimicking parts of the Django | |
FormField API | |
""" | |
label = None | |
help_text = "" | |
html_attrs = {} | |
def __init__(self, *args, **kwargs): | |
self.add_default_init_args(kwargs) | |
super().__init__(*args, **kwargs) | |
self.html_attrs.update(kwargs.get('html_attrs', {})) | |
def add_default_init_args(self, kwargs): | |
"""Allows FormField classes to set class attributes | |
that are passed to the parent class __init__ method | |
in order to be used as instance attributes. | |
In other words, add_default_init_args allows subclasses | |
to set class attributes that are used as default values | |
for instance attributes. | |
""" | |
inheritable_args = ['required', 'label', 'help_text'] | |
for key in inheritable_args: | |
if key not in kwargs and hasattr(self, key): | |
kwargs[key] = getattr(self, key) | |
def get_value(self, dictionary): | |
value = super().get_value(dictionary) | |
return self.coerce_if_empty(value) | |
def get_empty_value(self): | |
"""Gets the default value for empty versions of this field | |
Often overridden in subclasses in order to provide different types of empty | |
values | |
""" | |
return "" | |
def field_errors(self): | |
"""Returns any errors from a parent field or form that pertain to this field | |
""" | |
if hasattr(self, 'parent'): | |
parent = self.parent | |
if hasattr(parent, '_errors'): | |
return parent.errors.get(self.field_name, []) | |
return [] | |
def field_warnings(self): | |
"""Returns any warnings from a parent field or form that pertain to this field | |
""" | |
if hasattr(self, 'parent'): | |
parent = self.parent | |
if hasattr(parent, 'warnings'): | |
return parent.warnings.get(self.field_name, []) | |
return [] | |
def coerce_if_empty(self, value): | |
"""Coerces empty values to the default empty value for this field | |
""" | |
if value == rest_framework.fields.empty: | |
return self.get_empty_value() | |
return value | |
def current_value(self): | |
"""Returns the current value for this field | |
More research into Django REST Framework | |
might simplify or obviate this method | |
""" | |
if hasattr(self, 'parent'): | |
base_data = getattr(self.parent, 'initial_data', self.parent.get_initial()) | |
if hasattr(self, 'fields'): | |
base_value = self.get_value(base_data) | |
value = self.to_internal_value(base_value) | |
elif isinstance(self.parent, FormFieldMixin): | |
value = getattr(self.parent.current_value(), self.field_name) | |
else: | |
value = self.get_value(base_data) | |
return self.coerce_if_empty(value) | |
def input_name(self): | |
"""Returns a string for use as an html input name value | |
""" | |
if hasattr(self, 'parent'): | |
if getattr(self.parent, 'field_name', ''): | |
return "{}.{}".format(self.parent.field_name, self.field_name) | |
return self.field_name | |
def class_name(self): | |
return self.input_name().replace('.', '_') | |
class ChoicesMixin(FormFieldMixin): | |
def __init__(self, *args, **kwargs): | |
choices = kwargs.pop('choices', None) | |
if not choices and hasattr(self, 'choices'): | |
choices = getattr(self, 'choices') | |
if not choices: | |
raise TypeError("'choices' is a required attribute. It must be provided or passed to __init__.") | |
super().__init__(choices, *args, **kwargs) | |
class BlankIfNotRequiredMixin: | |
def __init__(self, *args, **kwargs): | |
if not kwargs.get('required', getattr(self, 'required', True)): | |
kwargs['allow_blank'] = True | |
super().__init__(*args, **kwargs) | |
class CharField(FormFieldMixin, BlankIfNotRequiredMixin, serializers.CharField): | |
pass | |
class ChoiceField(ChoicesMixin, BlankIfNotRequiredMixin, serializers.ChoiceField): | |
pass | |
class YesNoField(ChoiceField): | |
choices = YES_NO_CHOICES | |
class MultipleChoiceField(ChoicesMixin, serializers.MultipleChoiceField): | |
def to_internal_value(self, data): | |
return serializers.MultipleChoiceField.to_internal_value(self, data) | |
def to_representation(self, obj): | |
return list(obj) | |
def get_empty_value(self): | |
return [] | |
class MultiValueFormField(serializers.Serializer, FormFieldMixin): | |
def to_internal_value(self, data): | |
base_data = super().to_internal_value(data) | |
kwargs = {} | |
for key in self.fields: | |
kwargs[key] = base_data.get(key, "").strip() | |
# just need something that gives | |
return self.build_instance(**kwargs) | |
def get_empty_value(self): | |
return self.build_instance() | |
def to_representation(self, obj): | |
return vars(obj) | |
def get_value(self, dictionary): | |
value = super().get_value(dictionary) | |
if value == rest_framework.fields.empty: | |
return {} | |
return value | |
class MultiValueFormField(serializers.Serializer, FormFieldMixin): | |
def to_internal_value(self, data): | |
base_data = super().to_internal_value(data) | |
kwargs = {} | |
for key in self.fields: | |
kwargs[key] = base_data.get(key, "").strip() | |
# just need something that gives | |
return self.build_instance(**kwargs) | |
def get_empty_value(self): | |
return self.build_instance() | |
def to_representation(self, obj): | |
return vars(obj) | |
def get_value(self, dictionary): | |
value = super().get_value(dictionary) | |
if value == rest_framework.fields.empty: | |
return {} | |
return value | |
class AddressMultiValueFormField(MultiValueFormField): | |
street = CharField(required=False) | |
city = CharField(label=_("City"), required=False) | |
state = CharField(label=_("State"), required=False) | |
zip = CharField(label=_("Zip"), required=False) | |
def build_instance(self, **kwargs): | |
return Address(**kwargs) | |
class DateOfBirthMultiValueFormField(MultiValueFormField): | |
label = _("What is your date of birth?") | |
help_text = _("For example: 4/28/1986") | |
month = CharField(label=_("Month"), required=False) | |
day = CharField(label=_("Day"), required=False) | |
year = CharField(label=_("Year"), required=False) | |
def build_instance(self, **kwargs): | |
return DateOfBirth(**kwargs) | |
class SocialSecurityNumberField(CharField): | |
label = _('What is your Social Security Number?') | |
class PhoneNumberField(CharField): | |
label= _('What is your phone number?') | |
class EmailField(FormFieldMixin, BlankIfNotRequiredMixin, serializers.EmailField): | |
label =_ ('What is your email?') | |
help_text = _('For example "yourname@example.com"') | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Contains a complete list of all the field instances | |
that should be used by forms in intake. | |
""" | |
from collections import OrderedDict | |
from django.utils.translation import ugettext as _ | |
from intake.forms import field_types | |
from intake.constants import COUNTY_CHOICES, CONTACT_PREFERENCE_CHOICES | |
# Meta fields about the application | |
counties = field_types.MultipleChoiceField( | |
choices=COUNTY_CHOICES, | |
label=_("Which counties were you arrested in?")) | |
how_did_you_hear = field_types.CharField( | |
label=_("How did you hear about this program or website?")) | |
case_number = field_types.CharField( | |
label=_('If you have one, what is your case number?'), | |
help_text=_("If you don't have one or don't remember, that's okay.")) | |
additional_information = field_types.CharField( | |
label=_("Is there anything else you want to say?")) | |
# Identification questions | |
first_name = field_types.CharField( | |
label=_('What is your first name?')) | |
middle_name = field_types.CharField( | |
label=_('What is your middle name?')) | |
last_name = field_types.CharField( | |
label=_('What is your last name?')) | |
dob = field_types.DateOfBirthMultiValueFormField() | |
ssn = field_types.SocialSecurityNumberField( | |
help_text=_("The public defender's office will use this to get your San Francisco RAP sheet and find any convictions that can be reduced or dismissed.")) | |
# Contact info questions | |
contact_preferences = field_types.MultipleChoiceField( | |
choices=CONTACT_PREFERENCE_CHOICES, | |
label=_('How would you like us to contact you?'), | |
help_text=_('Code for America will use this to update you about your application.')) | |
phone_number = field_types.PhoneNumberField( | |
help_text=_('Code for America and the public defender will use this to contact you about your application.')) | |
email = field_types.EmailField() | |
address = field_types.AddressMultiValueFormField() | |
# Case status and screening questions | |
us_citizen = field_types.YesNoField( | |
label=_("Are you a U.S. citizen?"), | |
help_text=_("The public defender handles non-citizen cases differently and has staff who can help with citizenship issues.")) | |
being_charged = field_types.YesNoField( | |
label=_("Are you currently being charged with a crime?")) | |
serving_sentence = field_types.YesNoField( | |
label=_("Are you currently serving a sentence?")) | |
on_probation_parole = field_types.YesNoField( | |
label=_("Are you on probation or parole?")) | |
where_probation_or_parole = field_types.CharField( | |
label=_("Where is your probation or parole?")) | |
when_probation_or_parole = field_types.CharField( | |
label=_("When does your probation or parole end?")) | |
rap_outside_sf = field_types.YesNoField( | |
label=_("Have you ever been arrested or convicted outside of San Francisco?")) | |
when_where_outside_sf = field_types.CharField( | |
label=_("When and where were you arrested or convicted outside of San Francisco?")) | |
# Financial questions | |
financial_screening_note = _("The Clean Slate program is free for you, but the public defender uses this information to get money from government programs.") | |
currently_employed = field_types.YesNoField( | |
label=_("Are you currently employed?")) | |
monthly_income = field_types.CharField( | |
label=_("What is your monthly_income?")) | |
income_source = field_types.CharField( | |
label=_("Where does your income come from?"), | |
help_text=_("For example: Job, Social Security, Food stamps")) | |
monthly_expenses = field_types.CharField( | |
label=_("How much do you spend each month on things like rent, groceries, utilities, medical expenses, or childcare expenses?")) | |
# This defines the order of all fields in relation to each other | |
INTAKE_FIELDS = [ | |
counties, | |
contact_preferences, | |
first_name, | |
middle_name, | |
last_name, | |
phone_number, | |
email, | |
address, | |
dob, | |
ssn, | |
us_citizen, | |
serving_sentence, | |
on_probation_parole, | |
where_probation_or_parole, | |
when_probation_or_parole, | |
rap_outside_sf, | |
when_where_outside_sf, | |
financial_screening_note, | |
currently_employed, | |
monthly_income, | |
income_source, | |
monthly_expenses, | |
case_number, | |
how_did_you_hear, | |
additional_information, | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment