def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: forms = [ self.identification, ] for handler in forms: handler(user) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url)
def submit(self, user, error_callback_url): self.set_user_agent(user) self.error_callback_url = error_callback_url try: self.drivers_license(user) self.citizenship(user) self.age_verification(user) self.application_type(user) self.illinois_identification(user) self.illinois_name(user) self.illinois_address(user) self.illinois_personal_info(user) self.illinois_email(user) self.illinois_election_authority(user) self.illinois_mailing_address(user) self.illinois_different_name(user) self.illinois_different_address(user) self.illinois_assisting(user) self.illinois_summary(user) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url)
def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: forms = [ self.step1, self.step2, self.step3, self.step4, self.step5 ] for handler in forms: step_form = self.browser.get_form() if step_form: handler(step_form, user) errors = self.parse_errors(step_form) if errors: raise ValidationError(message='field_errors', payload=errors) if not step_form: raise ValidationError(message='no_form_found', payload=handler.__name__) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url)
def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url # KY doesn't have intermediate forms, they just submit as JSON all at once # assemble the data dict iteratively, to match style of other states form_data = {} try: steps = [ self.requirements, self.check_existing, self.personal_information, self.party_affiliation, self.address, self.signature ] for handler in steps: handler(user, form_data) r = self.browser.session.post( 'https://vrsws.sos.ky.gov/EVRwcf/EVRwcf.Service1.svc/UpdateVoter', json=form_data, headers={ 'X-Requested-With': 'XMLHttpRequest', 'Referer': 'https://vrsws.sos.ky.gov/ovrweb/' }) success_page = r.content if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url)
def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: # this one's a little different, all form stepping is in javascript # persist same form between handlers, don't submit until end self.set_registration_type(user) form = self.browser.get_form() handlers = [ self.eligibility, self.voter_information, self.address, self.previous_info, self.review_affirm, self.email_receipt ] for handler in handlers: handler(user, form) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url)
def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: forms = [ self.language, self.init_voter_registration, self.eligibility, self.personal_information, self.change_of_address, self.update_address, self.confirm_address, self.register_to_vote, self.verify_voter_registration, self.vote_by_mail ] for handler in forms: handler(user) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url)
def submit(self, user, error_callback_url=None): self.error_callback_url = error_callback_url raise OVRError(self, message="Always fail", payload=self.browser.parsed, error_callback_url=self.error_callback_url)
class Vermont(BaseOVRForm): def __init__(self): super(Vermont, self).__init__('https://olvr.sec.state.vt.us/') self.add_required_fields( ['will_be_18', 'legal_resident', 'state_id_number', 'voters_oath']) self.success_string = 'Thank you for completing your voter registration application' def parse_errors(self): if self.errors: return self.errors messages = [] for error in self.browser.select('.errorsPlaceHolder1 li'): messages.append({'error': error.text}) for error in self.browser.select('.text-danger'): messages.append({'error': error.text}) return messages def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: # this one's a little different, all form stepping is in javascript # persist same form between handlers, don't submit until end self.set_registration_type(user) form = self.browser.get_form() handlers = [ self.eligibility, self.voter_information, self.address, self.previous_info, self.review_affirm, self.email_receipt ] for handler in handlers: handler(user, form) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url) except Exception, e: ex_type, ex, tb = sys.exc_info() raise OVRError(self, message="%s %s" % (ex_type, ex), payload=traceback.format_tb(tb), error_callback_url=self.error_callback_url)
class Illinois(BaseOVRForm): def __init__(self): super(Illinois, self).__init__('https://ova.elections.il.gov/Step0.aspx') self.add_required_fields([ 'will_be_18', 'state_id_issue_date', 'ssn_last4', 'county', 'gender', 'has_previous_name', 'has_previous_address', 'confirm_name_address', 'consent_use_signature', 'reviewed_information' ]) self.success_string = 'Your application is now being processed by your local election authority' def submit(self, user, error_callback_url): self.set_user_agent(user) self.error_callback_url = error_callback_url try: self.drivers_license(user) self.citizenship(user) self.age_verification(user) self.application_type(user) self.illinois_identification(user) self.illinois_name(user) self.illinois_address(user) self.illinois_personal_info(user) self.illinois_email(user) self.illinois_election_authority(user) self.illinois_mailing_address(user) self.illinois_different_name(user) self.illinois_different_address(user) self.illinois_assisting(user) self.illinois_summary(user) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url) except Exception, e: ex_type, ex, tb = sys.exc_info() raise OVRError(self, message="%s %s" % (ex_type, ex), payload=traceback.format_tb(tb), error_callback_url=self.error_callback_url)
class Kentucky(BaseOVRForm): def __init__(self): super(Kentucky, self).__init__('https://vrsws.sos.ky.gov/ovrweb/') self.add_required_fields([ 'will_be_18', 'gender', 'ssn', 'political_party', 'incompetent', 'disenfranchised', 'claim_elsewhere' ]) self.success_string = 'Your Kentucky Voter Registration Application has been submitted' def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url # KY doesn't have intermediate forms, they just submit as JSON all at once # assemble the data dict iteratively, to match style of other states form_data = {} try: steps = [ self.requirements, self.check_existing, self.personal_information, self.party_affiliation, self.address, self.signature ] for handler in steps: handler(user, form_data) r = self.browser.session.post( 'https://vrsws.sos.ky.gov/EVRwcf/EVRwcf.Service1.svc/UpdateVoter', json=form_data, headers={ 'X-Requested-With': 'XMLHttpRequest', 'Referer': 'https://vrsws.sos.ky.gov/ovrweb/' }) success_page = r.content if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url) except Exception, e: ex_type, ex, tb = sys.exc_info() raise OVRError(self, message="%s %s" % (ex_type, ex), payload=traceback.format_tb(tb), error_callback_url=self.error_callback_url)
class Hawaii(BaseOVRForm): def __init__(self): super(Hawaii, self).__init__('https://olvr.hawaii.gov/register.aspx') self.add_required_fields( ['will_be_18', 'legal_resident', 'state_id_number', 'ssn']) self.success_string = 'TBD' def parse_errors(self): if self.errors: return self.errors messages = [] for error in self.browser.select('.ErrorMessage li'): messages.append({'error': error.text}) return messages def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: forms = [ self.identification, ] for handler in forms: handler(user) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url) except Exception, e: ex_type, ex, tb = sys.exc_info() raise OVRError(self, message="%s %s" % (ex_type, ex), payload=traceback.format_tb(tb), error_callback_url=self.error_callback_url)
class California(BaseOVRForm): def __init__(self): super(California, self).__init__('https://covr.sos.ca.gov/?language=en-US') self.add_required_fields([ 'will_be_18', 'political_party', 'disenfranchised', 'ssn_last4', 'county', 'consent_use_signature' ]) self.success_string = "Your voter registration application is now complete." def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: forms = [ self.step1, self.step2, self.step3, self.step4, self.step5 ] for handler in forms: step_form = self.browser.get_form() if step_form: handler(step_form, user) errors = self.parse_errors(step_form) if errors: raise ValidationError(message='field_errors', payload=errors) if not step_form: raise ValidationError(message='no_form_found', payload=handler.__name__) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url) except Exception, e: ex_type, ex, tb = sys.exc_info() raise OVRError(self, message="%s %s" % (ex_type, ex), payload=traceback.format_tb(tb), error_callback_url=self.error_callback_url)
class Arizona(BaseOVRForm): def __init__(self): super(Arizona, self).__init__( 'https://servicearizona.com/webapp/evoter/selectLanguage') self.add_required_fields([ 'will_be_18', 'legal_resident', 'incompetent', 'disenfranchised', 'ssn_last4', 'has_separate_mailing_address', 'political_party' ]) self.success_string = 'Your application for voter registration has been successfully completed.' def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: forms = [ self.language, self.init_voter_registration, self.eligibility, self.personal_information, self.change_of_address, self.update_address, self.confirm_address, self.register_to_vote, self.verify_voter_registration, self.vote_by_mail ] for handler in forms: handler(user) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url) except Exception, e: ex_type, ex, tb = sys.exc_info() raise OVRError(self, message="%s %s" % (ex_type, ex), payload=traceback.format_tb(tb), error_callback_url=self.error_callback_url)
def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: self.validate(user) # format is: [kwargs to select / identify form, method to call with form] # frustratingly, MA uses the same methods and IDs for each form... forms = [[{ 'action': "./MinRequirements.aspx?RMVId=True" }, self.minimum_requirements], [{ 'action': "./FormAndReview.aspx?RMVId=True" }, self.rmv_identification], [{ 'action': "./FormAndReview.aspx?RMVId=True" }, self.complete_form], [{ 'action': "./FormAndReview.aspx?RMVId=True" }, self.review]] for form_kwargs, handler in forms: step_form = self.browser.get_form(**form_kwargs) if step_form: handler(user, step_form) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) if not step_form: raise ValidationError(message='no_form_found', payload=handler.__name__) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: return {'status': 'failure'} except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url)
def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: # format is: [kwargs to select / identify form, method to call with form] forms = [ [{}, self.welcome], [{}, self.minimum_requirements], [{}, self.personal_information], [{}, self.consent_use_signature], [{ 'id': 'formId' }, self.residence_address ], # there are two forms on this page, but one is blank [{}, self.general_information], [{}, self.review_information], [{}, self.confirmation_email], ] for form_kwargs, handler in forms: step_form = self.browser.get_form(**form_kwargs) if step_form: handler(user, step_form) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) if not step_form: raise ValidationError(message='no_form_found', payload=handler.__name__) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url)
def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: self.validate(user) # format is: [kwargs to select / identify form, method to call with form] forms = [ [{ 'id': 'verifyNewVoterForm' }, self.verify_identification], [ {}, self.new_or_existing_voter ], # this splits between verify_eligibility, edit_voter_information [{ 'id': 'reviewVoterForm' }, self.review], [{ 'id': 'affirmationVoterForm' }, self.affirmation] ] for form_kwargs, handler in forms: step_form = self.browser.get_form(**form_kwargs) handler(user, step_form) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) if not step_form: raise ValidationError(message='no_form_found', payload=handler.__name__) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url)
def submit(self, user, error_callback_url = None): self.error_callback_url = error_callback_url try: self.get_started(user) self.full_registration(user) # return queue status immediately # check for pdf with get_download success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: # TODO, handle gracefully return {'status': 'failure'} except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url)
class WestVirginia(BaseOVRForm): def __init__(self): super(WestVirginia, self).__init__( 'https://ovr.sos.wv.gov/Register/Landing#Qualifications') self.add_required_fields([ 'will_be_18', 'legal_resident', 'state_id_number', 'ssn_last4', 'consent_use_signature' ]) self.success_string = 'TBD' def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: forms = [] for handler in forms: handler(user) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url) except Exception, e: ex_type, ex, tb = sys.exc_info() raise OVRError(self, message="%s %s" % (ex_type, ex), payload=traceback.format_tb(tb), error_callback_url=self.error_callback_url)
def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: # format is: [kwargs to select / identify form, method to call with form] forms = [ [{}, self.voting_eligibility], [{}, self.voting_identity], [{}, self.protected_voter], [{}, self.overseas_classification], [{}, self.absentee_ballot], [{}, self.residence_address], [{}, self.contact_information], [{}, self.affirmation] ] for form_kwargs, handler in forms: step_form = self.browser.get_form(**form_kwargs) if step_form: handler(user, step_form) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) if not step_form: raise ValidationError(message='no_form_found', payload=handler.__name__) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: return {'status': 'failure'} except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url)
class VoteDotOrg(BaseOVRForm): def __init__(self, partner_id=None): VOTEORG_URL = 'https://register.vote.org/' if partner_id: VOTEORG_URL += '?partner=%s' % partner_id super(VoteDotOrg, self).__init__(VOTEORG_URL) self.add_required_fields(['political_party', 'email']) self.success_string = "Almost done. You still need to print and mail your completed form." def parse_errors(self): messages = [] for error in self.browser.find_all(class_='usa-alert-error'): messages.append(error.find(class_='usa-alert-body').text) return messages def get_started(self, user): form = self.browser.get_form(id='get_started_form') form['first_name'].value = user['first_name'] form['last_name'].value = user['last_name'] # date_of_birth -> parts (year, month, day) = split_date(user['date_of_birth'], padding=False) form['date_of_birth_month'].value = month form['date_of_birth_day'].value = day form['date_of_birth_year'].value = year # street address # can't figure out how to bypass autocomplete, so reassemble parts into string form['address_autocomplete'] = '%(address)s, %(city)s, %(state)s %(zip)s' % user # contact form['email'] = user.get('email') form['mobile_phone'] = user.get('phone') self.browser.submit_form(form) def full_registration(self, user): # if given choice to register online, choose pdf form if self.browser.get_form(id='state_ovr'): finish_form = self.browser.get_form(id='finish') self.browser.submit_form(finish_form) full_form = self.browser.get_form(id='full_registration') if full_form: # BUG, user.get(field, '') results in silent 400 errors, wtf? # full_form['title'].value = user.get('title', '') # print 'set title', full_form['title'].value # full_form['suffix'].value = user.get('suffix', '') # print 'set suffix', full_form['suffix'].value full_form['state_id_number'].value = user['state_id_number'] party_translated = get_party_from_list(user.get('political_party'), options_dict(full_form['political_party']).keys()) if not party_translated: party_translated = 'No party' full_form['political_party'].value = options_dict(full_form['political_party'])[party_translated] # why does the form require bool as string? full_form['us_citizen'].value = str(bool_to_int(user['us_citizen'])) self.browser.submit_form(full_form) else: errors_string = ','.join(self.parse_errors()) raise ValidationError(message='unable to get_form full_registration.', payload=errors_string) def get_download(self, user): self.browser.open('https://register.vote.org/downloads.json') download_response = self.browser.state.response.json() if download_response['status'] == 'ready': return True def submit(self, user, error_callback_url = None): self.error_callback_url = error_callback_url try: self.get_started(user) self.full_registration(user) # return queue status immediately # check for pdf with get_download success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: # TODO, handle gracefully return {'status': 'failure'} except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url) except Exception, e: ex_type, ex, tb = sys.exc_info() raise OVRError(self, message="%s %s" % (ex_type, ex), payload=traceback.format_tb(tb), error_callback_url=self.error_callback_url)
class Georgia(BaseOVRForm): def __init__(self): super(Georgia, self).__init__( 'https://registertovote.sos.ga.gov/GAOLVR/welcometoga.do') self.success_string = 'You are NOT officially registered to vote until this application is approved.' self.add_required_fields( ['will_be_18', 'legal_resident', 'disenfranchised', 'incompetent']) def parse_errors(self): if self.errors: return self.errors messages = [] for error in self.browser.select('.fontError'): if error.text.strip() != '': messages.append({'error': error.text}) return messages def welcome(self, user, form): self.browser.submit_form(form, submit=form['ddsIdButton']) return form def minimum_requirements(self, user, form): if user['us_citizen']: form['citizenVer'].checked = True form['citizenVer'].value = "on" if user['will_be_18']: form['ageVer'].checked = True form['ageVer'].value = "on" if user['legal_resident']: form['stateVer'].checked = True form['stateVer'].value = "on" if not user['disenfranchised']: form['felonyVer'].checked = True form['felonyVer'].value = "on" if not user['incompetent']: form['mentally'].checked = True form['mentally'].value = "on" # every GA form has a "back" button which also does a submit, so we have to specify self.browser.submit_form(form, submit=form['beginReg']) return form def personal_information(self, user, form): form = self.browser.get_form("formId") # update form action, this happens in javascript on validateForm form.action = 'reqConsentAndDecline.do' if user.get('has_previous_address'): # change voter registration form['changeType'].value = 'CV' form['_addrChange'].checked = 'checked' # don't actually change registration here, do it later in general information else: # new voter registration form['changeType'].value = 'NV' if user.get('has_previous_name'): form['changeType'].value = 'CV' form['_nmChange'].checked = 'checked' (prev_first, prev_middle, prev_last) = split_name(user.get('previous_name')) form['preFirstName'].value = prev_first form['preLastName'].value = prev_last # county select from list form['county'].value = options_dict( form['county'])[user['county'].upper()] form['lastName'].value = user['last_name'].upper() form['firstName'].value = user['first_name'].upper() (year, month, day) = split_date(user['date_of_birth']) form['dobDate'].value = '/'.join([month, day, year]) form['ddsId'].value = user['state_id_number'] self.browser.submit_form(form, submit=form['next']) return form def consent_use_signature(self, user, form): if user.get('consent_use_signature'): form[ 'consent'].value = '0' # incredibly, this means "yes", 1 means "no" self.browser.submit_form(form, submit=form['next']) return form def residence_address(self, user, form): # reassemble address_components to match street name dropdowns # in the browser this autofills, but we get to do it manually address_components = get_address_components(user['address'], user['city'], user['state'], user['zip']) form['streetNum'].value = address_components['primary_number'] full_street_name = get_street_name_from_components(address_components) form['streetName1'].value = options_dict( form['streetName1'])[full_street_name.upper()] street_value = form['streetName1'].value # look up postal city key and rural_flag from street_value postal_city = self.get_postal_city( street_value, address_components['county_name'])[0] rural_flag = postal_city['fl_Rural_Flag'] form['ruralcityFlag'].value = rural_flag.lower() if rural_flag == "Y": form['rural_city'].options = (postal_city['key'], ) form['rural_city'].value = str(postal_city['key']) else: # replace weird city selector with a regular input form.fields.pop('city') city_field = robobrowser.forms.fields.Input( '<input type="hidden" id="city" name="city"></input>') city_field.value = str(postal_city['key']) form.add_field(city_field) # of course, there's also a hidden cityName field to append city_name = robobrowser.forms.fields.Input( '<input type="hidden" id="cityName" name="cityName"></input>') city_name.value = address_components['city_name'].upper() form.add_field(city_name) form['state'].value = address_components['state_abbreviation'] form['zip5'].value = address_components['zipcode'] form['countyS3'].value = address_components['county_name'].upper() # update form action, this happens in javascript on validateForm form.action = 'regStep4.do' self.browser.submit_form(form, submit=form['next']) return form def get_postal_city(self, street_value, county): # GA does clever stuff with modifying the select options in javascript # try to mimic it r = self.browser.session.get( "https://registertovote.sos.ga.gov/GAOLVR/getPostalCities.do", params={ 'streetName': street_value, 'countyName': county.upper() }) return r.json() def general_information(self, user, form): # these fields are all optional, fill in only if defined if user.get('gender'): form['gender'].options = [ 'Male', 'Female' ] # they have two buttons with the same name but different ids gender_str = parse_gender( user['gender']) # coerces free text to M/F if gender_str is 'F': form['gender'].value = 'Female' elif gender_str is 'M': form['gender'].value = 'Male' else: raise ValidationError(message='parse_gender error', payload=user['gender']) # poll_worker if user.get('ssn_last_4'): form['ssnId'] = user['ssn_last_4'] # also accepts full SSN, but no dashes if user.get('email'): form['emailId'] = user['email'] if user.get('phone'): form['telephone'] = user['phone'] # format? # ethnicity requires a dropdown, and is optional # skip it # previous address appears here if user.get('has_previous_address'): prev_address_components = get_address_components( user['previous_address'], user['previous_city'], user['previous_state'], user['previous_zip']) form['preStreetNo'].value = prev_address_components[ 'primary_number'] form['preStreetName'].value = get_street_name_from_components( prev_address_components).upper() if 'secondary_number' in prev_address_components: form['preAptNo'].value = prev_address_components[ 'secondary_number'] form['prePostalCity'].value = prev_address_components['city_name'] form[ 'ctl00$MainContent$TxtPrevRegZip'].value = prev_address_components[ 'zipcode'] form['preState'].value = prev_address_components[ 'state_abbreviation'] form.action = 'summary.do' self.browser.submit_form(form, submit=form['next']) return form def review_information(self, user, form): if user['us_citizen']: form['citizenCheck'].value = "on" else: self.add_error("You must be a U.S. Citizen.", field='us_citizen') if user['will_be_18']: form['ageCheck'].value = "on" else: self.add_error('You must be 18 by Election Day.', field='will_be_18') if not user.get('legal_resident'): self.add_error('You must be a legal resident of Georgia.', field='legal_resident') if user.get('disenfranchised'): self.add_error( 'You must not be serving a sentence for having been convicted of a felony involving moral turpitude.', field='disenfranchised') if user.get('incompetent'): self.add_error( 'You must not have been judicially declared to be mentally incompetent.', field='incompetent') user_is_eligible = user['legal_resident'] and ( not user['disenfranchised']) and (not user['incompetent']) if user_is_eligible: form['checkbox'].checked = "checked" form['checkbox'].value = "on" if self.errors: return False # mimic their javascript as closely as possible hidden_clicker = robobrowser.forms.fields.Input( '<input type="hidden" id="confirmSubmit_Clicker" name="confirmSubmit_Clicker"></input>' ) form.add_field(hidden_clicker) form.action = 'success.do' self.browser.submit_form(form, submit=form['submitBtn']) def confirmation_email(self, user, form): # send user email confirmation with reference number if user.get('email'): r = self.browser.session.get( 'https://registertovote.sos.ga.gov/GAOLVR/sendMail.do', params={ 'emailId': user['email'], 'referenceNumber': form['referenceNumber'].value }) def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: # format is: [kwargs to select / identify form, method to call with form] forms = [ [{}, self.welcome], [{}, self.minimum_requirements], [{}, self.personal_information], [{}, self.consent_use_signature], [{ 'id': 'formId' }, self.residence_address ], # there are two forms on this page, but one is blank [{}, self.general_information], [{}, self.review_information], [{}, self.confirmation_email], ] for form_kwargs, handler in forms: step_form = self.browser.get_form(**form_kwargs) if step_form: handler(user, step_form) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) if not step_form: raise ValidationError(message='no_form_found', payload=handler.__name__) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url) except Exception, e: ex_type, ex, tb = sys.exc_info() print ex_type, ex print traceback.format_tb(tb) raise OVRError(self, message="%s %s" % (ex_type, ex), payload=traceback.format_tb(tb), error_callback_url=self.error_callback_url)
class Virginia(BaseOVRForm): def __init__(self): super(Virginia, self).__init__('https://vote.elections.virginia.gov/Registration/Eligibility') self.add_required_fields(['county', 'legal_resident', 'incompetent', 'disenfranchised', 'ssn', 'gender', 'privacy_notice', 'consent_use_signature', 'confirm_name_address', 'authorize_cancellation']) self.success_string = 'Your voter registration application has been submitted.' def parse_errors(self): if self.errors: return self.errors messages = [] for error in self.browser.select('.field-validation-error'): if error.text.strip() != '': messages.append({'error': error.text}) return messages def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: # format is: [kwargs to select / identify form, method to call with form] forms = [ [{}, self.voting_eligibility], [{}, self.voting_identity], [{}, self.protected_voter], [{}, self.overseas_classification], [{}, self.absentee_ballot], [{}, self.residence_address], [{}, self.contact_information], [{}, self.affirmation] ] for form_kwargs, handler in forms: step_form = self.browser.get_form(**form_kwargs) if step_form: handler(user, step_form) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) if not step_form: raise ValidationError(message='no_form_found', payload=handler.__name__) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: return {'status': 'failure'} except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url) except Exception, e: ex_type, ex, tb = sys.exc_info() print ex_type, ex print traceback.format_tb(tb) raise OVRError(self, message="%s %s" % (ex_type, ex), payload=traceback.format_tb(tb), error_callback_url=self.error_callback_url)
class Massachusetts(BaseOVRForm): def __init__(self): super(Massachusetts, self).__init__( 'https://www.sec.state.ma.us/OVR/Pages/MinRequirements.aspx?RMVId=True' ) self.add_required_fields([ 'will_be_18', 'legal_resident', 'consent_use_signature', 'political_party', 'disenfranchised', 'disqualified' ]) self.success_string = 'Your application for voter registration has been transmitted' # careful of trailing spaces, that paragraph is hard wrapped def parse_errors(self): if self.errors: return self.errors messages = [] for error in self.browser.select('.ErrorMessage li'): messages.append({'error': error.text}) return messages def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: self.validate(user) # format is: [kwargs to select / identify form, method to call with form] # frustratingly, MA uses the same methods and IDs for each form... forms = [[{ 'action': "./MinRequirements.aspx?RMVId=True" }, self.minimum_requirements], [{ 'action': "./FormAndReview.aspx?RMVId=True" }, self.rmv_identification], [{ 'action': "./FormAndReview.aspx?RMVId=True" }, self.complete_form], [{ 'action': "./FormAndReview.aspx?RMVId=True" }, self.review]] for form_kwargs, handler in forms: step_form = self.browser.get_form(**form_kwargs) if step_form: handler(user, step_form) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) if not step_form: raise ValidationError(message='no_form_found', payload=handler.__name__) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: return {'status': 'failure'} except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url) except Exception, e: ex_type, ex, tb = sys.exc_info() raise OVRError(self, message="%s %s" % (ex_type, ex), payload=traceback.format_tb(tb), error_callback_url=self.error_callback_url)
class Colorado(BaseOVRForm): def __init__(self): super(Colorado, self).__init__( 'https://www.sos.state.co.us/voter-classic/pages/pub/olvr/verifyNewVoter.xhtml' ) self.add_required_fields([ 'military_or_overseas', 'vote_by_mail', 'legal_resident', 'political_party', 'email', 'gender', 'will_be_18', 'consent_use_signature', 'confirm_name_address' ]) self.success_string = "Your changes have been submitted to your County Clerk and Recorder for processing" def submit(self, user, error_callback_url=None): self.set_user_agent(user) self.error_callback_url = error_callback_url try: self.validate(user) # format is: [kwargs to select / identify form, method to call with form] forms = [ [{ 'id': 'verifyNewVoterForm' }, self.verify_identification], [ {}, self.new_or_existing_voter ], # this splits between verify_eligibility, edit_voter_information [{ 'id': 'reviewVoterForm' }, self.review], [{ 'id': 'affirmationVoterForm' }, self.affirmation] ] for form_kwargs, handler in forms: step_form = self.browser.get_form(**form_kwargs) handler(user, step_form) errors = self.parse_errors() if errors: raise ValidationError(message='field_errors', payload=errors) if not step_form: raise ValidationError(message='no_form_found', payload=handler.__name__) success_page = clean_browser_response(self.browser) if self.success_string in success_page: return {'status': 'success'} else: raise ValidationError(message='no_success_string') except ValidationError, e: raise OVRError(self, message=e.message, payload=e.payload, error_callback_url=self.error_callback_url) except Exception, e: ex_type, ex, tb = sys.exc_info() raise OVRError(self, message="%s %s" % (ex_type, ex), payload=traceback.format_tb(tb), error_callback_url=self.error_callback_url)