├── .gitignore ├── .powrc ├── .rspec ├── .ruby-version ├── .rvmrc ├── .travis.yml ├── Capfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Procfile ├── README.md ├── Rakefile ├── app ├── assets │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── Roboto-Black-webfont.eot │ │ ├── Roboto-Black-webfont.svg │ │ ├── Roboto-Black-webfont.ttf │ │ ├── Roboto-Black-webfont.woff │ │ ├── Roboto-Light-webfont.eot │ │ ├── Roboto-Light-webfont.svg │ │ ├── Roboto-Light-webfont.ttf │ │ ├── Roboto-Light-webfont.woff │ │ ├── Roboto-Regular-webfont.eot │ │ ├── Roboto-Regular-webfont.svg │ │ ├── Roboto-Regular-webfont.ttf │ │ ├── Roboto-Regular-webfont.woff │ │ ├── Roboto-Thin-webfont.eot │ │ ├── Roboto-Thin-webfont.svg │ │ ├── Roboto-Thin-webfont.ttf │ │ ├── Roboto-Thin-webfont.woff │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff │ ├── images │ │ ├── AskThem_NCAA.png │ │ ├── AskThem_Scotusblog.png │ │ ├── badge.ai │ │ ├── badge.jpg │ │ ├── credit_dmap.png │ │ ├── credit_google.png │ │ ├── credit_kfoundation.png │ │ ├── credit_opennorth.png │ │ ├── credit_openstates.png │ │ ├── credit_ppf.png │ │ ├── credit_sunlight.png │ │ ├── credit_sunlight_color.png │ │ ├── email_assets │ │ │ ├── ActionNetwork │ │ │ │ ├── email_footer.jpg │ │ │ │ ├── email_header_1.jpg │ │ │ │ ├── email_header_2.jpg │ │ │ │ ├── email_header_3.jpg │ │ │ │ ├── email_header_4.jpg │ │ │ │ ├── high-res │ │ │ │ │ ├── email_footer_high-res.jpg │ │ │ │ │ ├── email_header_orange_high-res.jpg │ │ │ │ │ └── email_headers-blue_high-res.jpg │ │ │ │ └── illustrator files │ │ │ │ │ ├── email_footers.ai │ │ │ │ │ └── email_headers.ai │ │ │ ├── AskThem_logo_652x113.png │ │ │ ├── AskThem_logo_email_header.png │ │ │ ├── AskThem_screenshot_slidedeck.png │ │ │ ├── email-header-blue.jpg │ │ │ ├── email-header-no-symbol.jpg │ │ │ ├── email-header-orange.jpg │ │ │ └── email-header-symbol.jpg │ │ ├── flag_icon.png │ │ ├── flag_icon@2x.png │ │ ├── followers_icon.png │ │ ├── followers_icon@2x.png │ │ ├── footer_illustration.jpg │ │ ├── how_1.png │ │ ├── how_1@2x.png │ │ ├── how_2.png │ │ ├── how_2@2x.png │ │ ├── how_3.png │ │ ├── how_3@2x.png │ │ ├── logo.png │ │ ├── logo.svg │ │ ├── logo_variations │ │ │ ├── logo-01.svg │ │ │ ├── logo-02.svg │ │ │ ├── logo-03.svg │ │ │ ├── logo-04.svg │ │ │ ├── logo-05.svg │ │ │ ├── logo-06.svg │ │ │ ├── logo-07.svg │ │ │ ├── logo-08.svg │ │ │ └── logo-09.svg │ │ ├── mag_glass.png │ │ ├── mag_glass@2x.png │ │ ├── mark.png │ │ ├── mark.svg │ │ ├── nav_arrow.png │ │ ├── nav_arrow@2x.png │ │ ├── pick.svg │ │ ├── placeholder.png │ │ ├── related_bg@2x.png │ │ ├── related_delimiter.png │ │ ├── seal.png │ │ ├── seal@2x.png │ │ ├── search_pick@2x.png │ │ ├── splash_avatars │ │ │ ├── amanda_michel.jpg │ │ │ ├── anthea_strong.jpg │ │ │ ├── david_karpf.jpg │ │ │ ├── david_moore.jpg │ │ │ ├── josh_segall.jpg │ │ │ ├── maryam_gunja.jpg │ │ │ ├── micah_sifry.jpg │ │ │ ├── nicco_mele.jpg │ │ │ ├── nick_grossman.jpg │ │ │ ├── steven_trevathan.jpg │ │ │ ├── susannah_vila.jpg │ │ │ ├── tiffiniy_cheng.jpg │ │ │ ├── tom_steinberg.jpg │ │ │ ├── walter_mcginnis.jpg │ │ │ └── zephyr_teachout.jpg │ │ ├── textarea_bg.png │ │ ├── textarea_bg@2x.png │ │ ├── textarea_bg_focus.png │ │ ├── textarea_bg_focus@2x.png │ │ ├── up_vote_sm.png │ │ ├── up_vote_sm@2x.png │ │ ├── usa-icon.svg │ │ └── usa.jpg │ ├── javascripts │ │ ├── application.js │ │ ├── authentication.js.coffee │ │ ├── banner.js │ │ ├── bills.js.coffee │ │ ├── equal_heights.js.coffee │ │ ├── filters.js.coffee │ │ ├── forms.js.coffee │ │ ├── hovertip.js │ │ ├── jquery.autogrow-textarea.js │ │ ├── jquery.equalheights.js │ │ ├── jquery.history.js │ │ ├── jquery.html5-placeholder-shim.js │ │ ├── jquery.scrollTo.min.js │ │ ├── jquery.timeago.js │ │ ├── modal.js │ │ ├── modernizr-2.5.3.min.js │ │ ├── people.js │ │ ├── progress_bar.js │ │ ├── questions.js.coffee │ │ ├── rails.validations.js │ │ ├── registrations.js.coffee │ │ ├── responsive.js.coffee │ │ ├── sign_on_user.js.coffee │ │ └── tabs.js.coffee │ └── stylesheets │ │ ├── application.sass │ │ ├── base.sass │ │ ├── font-awesome.css.scss │ │ ├── load.sass │ │ ├── misc.sass │ │ ├── modules │ │ ├── activity.sass │ │ ├── answers.sass │ │ ├── banner.sass │ │ ├── bills.sass │ │ ├── blurbs.sass │ │ ├── buttons.sass │ │ ├── candidates.sass │ │ ├── data_collection.sass │ │ ├── flash.sass │ │ ├── footer.sass │ │ ├── forms.sass │ │ ├── header.sass │ │ ├── home.sass │ │ ├── loading.sass │ │ ├── locator.sass │ │ ├── map.sass │ │ ├── meetings.sass │ │ ├── modal.sass │ │ ├── navigation.sass │ │ ├── partner-return-to.sass │ │ ├── people.sass │ │ ├── questions.sass │ │ ├── splash.sass │ │ └── static.sass │ │ ├── responsive.sass │ │ └── structure.sass ├── authorizers │ ├── application_authorizer.rb │ └── identity_authorizer.rb ├── controllers │ ├── answers_controller.rb │ ├── application_controller.rb │ ├── bills_controller.rb │ ├── blurbs_controller.rb │ ├── candidates_controller.rb │ ├── confirmations_controller.rb │ ├── email_upkeep_controller.rb │ ├── identities_controller.rb │ ├── meetings_controller.rb │ ├── omniauth_callbacks_controller.rb │ ├── pages_controller.rb │ ├── people_controller.rb │ ├── questions_controller.rb │ ├── registrations_controller.rb │ ├── robots_controller.rb │ ├── sessions_controller.rb │ ├── signatures_controller.rb │ ├── subjects_controller.rb │ └── users_controller.rb ├── helpers │ ├── application_helper.rb │ ├── pages_helper.rb │ ├── questions_helper.rb │ └── signatures_helper.rb ├── mailers │ ├── identity_mailer.rb │ ├── person_mailer.rb │ └── question_mailer.rb ├── models │ ├── agenda.rb │ ├── answer.rb │ ├── authentication.rb │ ├── bill.rb │ ├── bill_detail.rb │ ├── blurb.rb │ ├── cached_official.rb │ ├── cached_officials_from_google.rb │ ├── candidate.rb │ ├── committee.rb │ ├── councilmember.rb │ ├── county_official.rb │ ├── default_signature_threshold.rb │ ├── federal_legislator.rb │ ├── federal_official.rb │ ├── geo_data_from_request.rb │ ├── governor.rb │ ├── identity.rb │ ├── image_link_checker.rb │ ├── image_src_url.rb │ ├── influence_explorer_person_detail.rb │ ├── jurisdiction_id.rb │ ├── key_vote.rb │ ├── link.rb │ ├── location_formatter.rb │ ├── mayor.rb │ ├── meeting.rb │ ├── metadatum.rb │ ├── metadatum │ │ ├── seed_cities.rb │ │ ├── state.rb │ │ ├── unaffiliated.rb │ │ └── us.rb │ ├── minutes_document.rb │ ├── municipal_official.rb │ ├── people_identifier.rb │ ├── person.rb │ ├── person_detail.rb │ ├── person_detail_retriever.rb │ ├── president.rb │ ├── project_vote_smart_person_detail.rb │ ├── question.rb │ ├── rating.rb │ ├── rating_group.rb │ ├── rating_scorecard.rb │ ├── registered_redirect.rb │ ├── signature.rb │ ├── state_legislator.rb │ ├── state_official.rb │ ├── subject.rb │ ├── user.rb │ ├── user_role.rb │ ├── vice_president.rb │ ├── video_src_url.rb │ └── vote.rb ├── services │ ├── democracy_map_governor_service.rb │ ├── open_states_legislator_service.rb │ ├── sunlight_congress_legislator_service.rb │ └── twitter_person_service.rb ├── uploaders │ ├── image_uploader.rb │ └── media_uploader.rb ├── validators │ └── user_email_matches_validator.rb ├── views │ ├── answers │ │ ├── _featured.html.erb │ │ └── edit.html.erb │ ├── bills │ │ ├── _bill.html.erb │ │ ├── _page.html.erb │ │ ├── _questions.html.erb │ │ ├── _sponsors.html.erb │ │ ├── index.html.erb │ │ └── show.html.erb │ ├── blurbs │ │ ├── _blurb.html.erb │ │ ├── _form.html.erb │ │ ├── _managed_blurb.html.erb │ │ ├── edit.html.erb │ │ ├── index.html.erb │ │ ├── new.html.erb │ │ └── show.html.erb │ ├── candidates │ │ ├── _form.html.erb │ │ ├── _managed_candidate.html.erb │ │ ├── edit.html.erb │ │ ├── index.html.erb │ │ ├── new.html.erb │ │ └── show.html.erb │ ├── committees │ │ └── _committee.html.erb │ ├── devise │ │ ├── mailer │ │ │ ├── confirmation_instructions.html.erb │ │ │ └── reset_password_instructions.html.erb │ │ ├── passwords │ │ │ ├── edit.html.erb │ │ │ └── new.html.erb │ │ ├── sessions │ │ │ └── new.html.erb │ │ └── shared │ │ │ └── _links.erb │ ├── identity_mailer │ │ ├── identity_needs_inspection.html.erb │ │ ├── identity_needs_inspection.text.erb │ │ ├── identity_rejected.html.erb │ │ ├── identity_rejected.text.erb │ │ ├── identity_submitted.html.erb │ │ ├── identity_submitted.text.erb │ │ ├── identity_verified.html.erb │ │ └── identity_verified.text.erb │ ├── kaminari │ │ ├── _first_page.html.erb │ │ ├── _gap.html.erb │ │ ├── _last_page.html.erb │ │ ├── _next_page.html.erb │ │ ├── _page.html.erb │ │ ├── _paginator.html.erb │ │ └── _prev_page.html.erb │ ├── key_votes │ │ └── _key_vote.html.erb │ ├── layouts │ │ ├── application.html.erb │ │ ├── data_collection.html.erb │ │ ├── homepage.html.erb │ │ ├── mailer.html.erb │ │ ├── maintenance.html.erb │ │ └── splash.html.erb │ ├── meetings │ │ └── _meeting.html.erb │ ├── pages │ │ ├── _bills.html.erb │ │ ├── _key_votes.html.erb │ │ ├── _lower.html.erb │ │ ├── _meetings.html.erb │ │ ├── _people_for_location.html.erb │ │ ├── _question.html.erb │ │ ├── _upper.html.erb │ │ ├── about.html.erb │ │ ├── candidates.html.erb │ │ ├── channel.html.erb │ │ ├── contact_info.csv.erb │ │ ├── elected_signup.html.erb │ │ ├── faq.html.erb │ │ ├── honestads.html.erb │ │ ├── index.html.erb │ │ ├── locator.html.erb │ │ ├── map.html.erb │ │ ├── overview.html.erb │ │ ├── overview.js.erb │ │ ├── privacy_policy.html.erb │ │ ├── search.html.erb │ │ ├── splash.html.erb │ │ ├── support.html.erb │ │ ├── terms_of_service.html.erb │ │ └── widget_builder.html.erb │ ├── people │ │ ├── _bills.html.erb │ │ ├── _committees.html.erb │ │ ├── _featured.html.erb │ │ ├── _person.html.erb │ │ ├── _questions.html.erb │ │ ├── _ratings.html.erb │ │ ├── _votes.html.erb │ │ ├── index.html.erb │ │ └── show.html.erb │ ├── person_mailer │ │ ├── notify_staff_bad_person.html.erb │ │ ├── notify_staff_bad_person.text.erb │ │ ├── notify_staff_new_from_twitter.html.erb │ │ └── notify_staff_new_from_twitter.text.erb │ ├── question_mailer │ │ ├── _honestads_question_posted.html.erb │ │ ├── _honestads_question_posted.text.erb │ │ ├── answered_for_author.html.erb │ │ ├── answered_for_author.text.erb │ │ ├── answered_for_signer.html.erb │ │ ├── answered_for_signer.text.erb │ │ ├── email_person.html.erb │ │ ├── email_person.text.erb │ │ ├── notify_staff_members_answered.html.erb │ │ ├── notify_staff_members_answered.text.erb │ │ ├── notify_staff_question_at_threshold.html.erb │ │ ├── notify_staff_question_at_threshold.text.erb │ │ ├── question_posted.html.erb │ │ ├── question_posted.text.erb │ │ ├── signed_on.html.erb │ │ └── signed_on.text.erb │ ├── questions │ │ ├── _confirm_step.html.erb │ │ ├── _content_step.html.erb │ │ ├── _media.html.erb │ │ ├── _page.html.erb │ │ ├── _progress.html.erb │ │ ├── _question.html.erb │ │ ├── _recipient_step.html.erb │ │ ├── _sign_up_step.html.erb │ │ ├── edit.html.erb │ │ ├── index.html.erb │ │ ├── new.html.erb │ │ └── show.html.erb │ ├── ratings │ │ └── _rating.html.erb │ ├── registrations │ │ ├── edit.html.erb │ │ └── new.html.erb │ ├── robots │ │ └── show.text.erb │ ├── shared │ │ ├── _accept_terms.html.erb │ │ ├── _banner.html.erb │ │ ├── _chartbeat.html.erb │ │ ├── _facebook_connect.html.erb │ │ ├── _google_analytics.html.erb │ │ ├── _navigation.html.erb │ │ ├── _no_questions.html.erb │ │ ├── _optimizely.html.erb │ │ ├── _partner_return_to.html.erb │ │ └── _user.html.erb │ ├── signatures │ │ ├── _as_signer.html.erb │ │ └── index.csv.erb │ ├── subjects │ │ ├── _page.html.erb │ │ ├── index.html.erb │ │ └── show.html.erb │ ├── unknown │ │ └── _unknown.html.erb │ ├── users │ │ ├── _questions.html.erb │ │ ├── _signatures.html.erb │ │ └── show.html.erb │ └── votes │ │ └── _vote.html.erb └── workers │ ├── geocode_worker.rb │ ├── person_check_photo_url_worker.rb │ ├── question_answered_notifier_worker.rb │ ├── question_coordinates_worker.rb │ ├── unaffiliated_person_tidy_worker.rb │ ├── user_set_local_jurisdiction_abbreviation_worker.rb │ └── user_set_password_notice_worker.rb ├── config.ru ├── config ├── application.rb ├── boot.rb ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── airbrake.rb │ ├── authority.rb │ ├── carrierwave.rb │ ├── client_side_validations.rb │ ├── devise.rb │ ├── google_civic_info.rb │ ├── kaminari_config.rb │ ├── mongoid.rb │ ├── rolify.rb │ ├── secret_token.rb │ ├── session_store.rb │ ├── sidekiq.rb │ ├── simple_form.rb │ └── wrap_parameters.rb ├── locales │ ├── devise.en.yml │ ├── en.yml │ └── simple_form.en.yml ├── mongoid.yml ├── newrelic.yml ├── routes.rb └── unicorn.rb ├── data_dumps ├── ca-san-jose.json ├── il-chicago.json └── pa-philadelphia.json ├── doc ├── README.md ├── indexes.txt └── variety │ ├── README.md │ ├── bills.txt │ ├── committees.txt │ ├── districts.txt │ ├── events.txt │ ├── legislators.txt │ ├── subjects.txt │ └── votes.txt ├── examples └── _heroku.rb ├── lib ├── democracy_map_governor_adapter.rb ├── influence_explorer.rb ├── legislator.rb ├── legislator_finder.rb ├── open_government.rb ├── project_vote_smart.rb ├── sunlight_congress_legislator_adapter.rb ├── sunlight_legislator_locator_base.rb ├── tasks │ ├── congress.rake │ ├── cron.rake │ ├── governors.rake │ ├── influenceexplorer.rake │ ├── mongodb.rake │ ├── openstates.rake │ ├── projectvotesmart.rake │ ├── scraped_local_gov.rake │ └── seed_cities.rake ├── templates │ └── erb │ │ └── scaffold │ │ └── _form.html.erb └── twitter_person_adapter.rb ├── log └── .gitkeep ├── public ├── 403.html ├── 404.html ├── 422.html ├── 500.html ├── apple-touch-icon-120x120-precomposed.png ├── apple-touch-icon-120x120.png ├── apple-touch-icon-57x57-precomposed.png ├── apple-touch-icon-57x57.png ├── apple-touch-icon-76x76-precomposed.png ├── apple-touch-icon-76x76.png ├── apple-touch-icon.png ├── favicon.ico ├── mark.png ├── us.json └── widgets │ ├── address │ ├── README.md │ ├── app-concoction.txt │ ├── assets │ │ ├── address-widget-f6cc94e43aaf608ff909368ac5b59e29.css │ │ ├── vendor-ade829476ace9e79a697b45904164efd.js │ │ └── vendor-ba26407e909fb4a64f1f0a2ade32443c.css │ └── widget.js │ ├── person │ ├── README.md │ ├── app-concoction.txt │ ├── assets │ │ ├── person-widget-5026464cc3f47e1a262bc265daae12e0.css │ │ ├── vendor-ade829476ace9e79a697b45904164efd.js │ │ └── vendor-ba26407e909fb4a64f1f0a2ade32443c.css │ └── widget.js │ ├── widget-builder │ ├── README.md │ ├── app-concoction.txt │ ├── assets │ │ ├── vendor-4eac7f1e9eed0dee3fa372084070809c.js │ │ ├── vendor-ba26407e909fb4a64f1f0a2ade32443c.css │ │ └── widget-builder-widget-e9923a4753a83d90577a16682bf95024.css │ └── widget.js │ └── zip │ ├── ask-little.png │ ├── honestads2.png │ ├── question-little.png │ ├── widget.css │ └── widget.js ├── script ├── count.js ├── openstates.sh ├── rails ├── sanity │ ├── code-lists.js │ ├── counts.js │ ├── denormalization.js │ ├── foreign-keys.js │ ├── helper.js │ ├── hierarchy.js │ ├── manual-review.js │ └── miscellaneous.js └── variety.js └── spec ├── authorizers ├── application_authorizer_spec.rb └── identify_authorizer_spec.rb ├── cassettes ├── CachedOfficialsFromGoogle │ ├── _each │ │ └── iterates_over_the_collection_of_cached_officials.yml │ └── if_a_matching_cached_official_exists │ │ └── returns_existing_official_rather_than_creating_a_new_one.yml ├── Councilmember │ └── _for_location │ │ └── returns_matching_people_given_a_location.yml ├── CountyOfficial │ └── _for_location │ │ └── returns_matching_people_given_a_location.yml ├── DemocracyMapGovernorService │ ├── _governor_for │ │ └── hash_of_data_from_api_for_requested_state.yml │ └── _parsed_results_for_jurisdiction │ │ └── returns_matching_governor_data_for_juridisction_as_array.yml ├── EmailUpkeepController │ └── POST_index │ │ └── when_a_subscription_confirmation_is_sent │ │ └── should_request_subscription_url_and_end_processing.yml ├── FederalLegislator │ ├── _for_location │ │ └── returns_matching_people_given_a_location.yml │ └── _load_from_api_for_jurisdiction │ │ └── loads_people_into_database_given_a_state_abbreviation.yml ├── FederalOfficial │ └── _for_location │ │ └── returns_matching_people_given_a_location.yml ├── GeocodeWorker │ └── _perform │ │ └── should_geocode_the_object_s_address.yml ├── Governor │ ├── _for_location │ │ └── returns_matching_people_given_a_location.yml │ └── _load_governors │ │ └── populates_governor_data_for_all_states.yml ├── ImageLinkChecker │ └── _accessible_ │ │ ├── is_false_if_url_404_or_similar.yml │ │ ├── is_false_if_url_s_content_type_is_not_an_image.yml │ │ └── is_true_if_url_is_available_and_its_content_type_is_an_image.yml ├── InfluenceExplorer │ └── _data_for │ │ └── returns_hash_of_data_from_Influence_Explorer_api.yml ├── InfluenceExplorerPersonDetail │ └── _person_detail │ │ └── when_person_does_not_have_a_biography │ │ ├── returns_existing_person_detail.yml │ │ └── returns_updated_person_detail.yml ├── LocationFormatter │ └── _format │ │ ├── returns_geocode_result_for_valid_address.yml │ │ └── returns_nil_when_location_is_invalid.yml ├── Mayor │ └── _for_location │ │ └── returns_matching_people_given_a_location.yml ├── Metadatum_State │ ├── _create_states_from_api │ │ └── creates_states_from_api_attributes.yml │ └── _create_states_if_none │ │ └── when_no_state_jurisdictions_exist │ │ └── creates_a_Metadatum_with_the_states_jurisdiction_attributes.yml ├── MunicipalOfficial │ └── _for_location │ │ └── returns_matching_people_given_a_location.yml ├── OpenStatesLegislatorService │ ├── _ids_for │ │ └── takes_a_location_and_returns_matching_state_legislator_ids.yml │ └── _parsed_results_for_jurisdiction │ │ └── returns_matching_state_legislator_data_for_juridisction.yml ├── PagesController │ ├── _locator │ │ ├── when_passed_partner_info_parameters │ │ │ └── stores_info_in_user_session.yml │ │ └── when_passed_question_parameters │ │ │ └── stores_info_in_user_session.yml │ └── when_requesting_json │ │ ├── _identifier │ │ └── when_submittting_a_twitter_id │ │ │ └── and_there_isn_t_a_person_in_the_db_with_the_twitter_id │ │ │ ├── is_empty_array_if_no_matching_person_on_twitter.yml │ │ │ └── returns_matching_person_from_twitter_if_there_is_one.yml │ │ └── _locator │ │ └── takes_a_geographic_address_and_returns_matching_people.yml ├── PeopleIdentifier │ └── _people │ │ └── when_an_twitter_id_is_submitted │ │ └── returns_no_people_when_no_one_no_matches_in_db_or_twitter.yml ├── Person │ └── _load_from_api_for_jurisdiction │ │ └── loads_people_into_database_given_a_jurisdiction_abbreviation.yml ├── PersonCheckPhotoUrlWorker │ └── _perform │ │ └── when_person_s_photo_url_is_not_available │ │ └── the_photo_url_is_archived.yml ├── PersonDetailRetriever │ └── _person_detail │ │ └── updates_person_detail_with_data_from_apis.yml ├── President │ └── _for_location │ │ └── returns_matching_people_given_a_location.yml ├── ProjectVoteSmart │ ├── _get │ │ └── returns_results_from_Project_Vote_Smart_api.yml │ └── _officials_by_state_and_office │ │ ├── returns_federal_officials_for_office_when_state_is_us.yml │ │ └── returns_officials_for_state_and_office.yml ├── ProjectVoteSmartPersonDetail │ ├── _officials │ │ └── when_officials_are_not_passed_in │ │ │ └── returns_officials_from_api.yml │ └── _votesmart_id │ │ └── when_person_does_not_have_a_votesmart_id │ │ └── officials_are_not_passed_in │ │ ├── and_there_is_no_matching_official │ │ └── returns_nil_for_votesmart_id.yml │ │ └── returns_the_votesmart_id_for_the_person.yml ├── QuestionsController │ └── _create │ │ └── when_referring_partner_info_is_passed │ │ ├── via_partner_in_params │ │ ├── and_the_format_is_json │ │ │ ├── if_invalid_it_returns_errors_in_json.yml │ │ │ ├── if_user_exists_w │ │ │ │ ├── _email_not_logged_in_question_unconfirmed.yml │ │ │ │ └── _same_email_logged_in_populates_question.yml │ │ │ └── if_valid_it_populates_question_user_and_person_correctly.yml │ │ ├── populate_question_user_with_attributes_based_on_partner.yml │ │ └── populate_question_user_with_referring_partner_info.yml │ │ └── via_session │ │ ├── populate_question_user_with_attributes_based_on_partner.yml │ │ └── populate_question_user_with_referring_partner_info.yml ├── SignaturesHelper │ └── _signers_description │ │ └── when_there_is_only_a_zipcode │ │ └── returns_signer_s_name_only.yml ├── StateLegislator │ └── _for_location │ │ └── returns_matching_people_given_a_location.yml ├── StateOfficial │ └── _for_location │ │ └── returns_matching_people_given_a_location.yml ├── SunlightCongressLegislatorService │ ├── _ids_for │ │ └── takes_a_location_and_returns_matching_federal_legislator_ids.yml │ └── _parsed_results_for_jurisdiction │ │ └── returns_matching_federal_legislator_data_for_juridisction.yml ├── User │ ├── _set_attributes_based_on_partner │ │ └── populates_appropriate_attributes_based_on_partner.yml │ ├── _update_address_from_string │ │ └── populates_address_attributes_for_user.yml │ └── with_after_create_callback │ │ └── geocodes_address_to_lat_long.yml ├── VicePresident │ └── _for_location │ │ └── returns_matching_people_given_a_location.yml ├── pages_index │ ├── Get_Answers_from_Elected_Officials │ │ ├── can_list_questions_near_an_address_or_zipcode.yml │ │ └── can_search_for_federal_people_matching_an_address_or_zipcode.yml │ └── Top_Questions_Near │ │ ├── displays_user_s_city.yml │ │ └── when_there_are_questions_near_the_user │ │ ├── displays_number_of_answers_near_a_user_s_location.yml │ │ └── displays_number_of_signatures_near_a_user_s_location.yml ├── pages_locator │ └── when_passed_only_show_parameter_with_people_as_value │ │ ├── includes_a_button_to_ask_each_person_a_question.yml │ │ └── only_shows_elected_officials.yml ├── questions │ ├── _new │ │ ├── as_a_non-registered_user │ │ │ ├── can_fill_out_and_submit_complete_form.yml │ │ │ ├── when_a_recipient_is_already_specified │ │ │ │ └── can_fill_out_and_submit_complete_form.yml │ │ │ └── when_choosing_a_recipient │ │ │ │ ├── can_choose_a_person_from_address_locator.yml │ │ │ │ └── can_get_feedback_based_on_person_chosen_address_locator.yml │ │ └── as_signed_in_user │ │ │ ├── can_fill_out_and_submit_complete_form.yml │ │ │ └── when_adding_adding_media_via_a_url │ │ │ └── can_enter_image_or_video_url_for_question.yml │ └── _show │ │ └── when_displaying_signature_information │ │ └── allows_new_user_to_register_and_sign_on_to_a_question.yml └── registrations │ └── _new │ ├── can_fill_out_form_to_sign_up.yml │ └── user_has_email_of_recognized_person │ └── adds_an_identity_and_notifies_appropriately.yml ├── controllers ├── application_controller_spec.rb ├── blurbs_controller_spec.rb ├── email_upkeep_controller_spec.rb ├── identities_controller_spec.rb ├── pages_controller_spec.rb ├── questions_controller_spec.rb ├── robots_controller_spec.rb └── signature_controller_spec.rb ├── factories.rb ├── features ├── answers_spec.rb ├── features_helper.rb ├── homepage_spec.rb ├── locator_spec.rb ├── meetings_spec.rb ├── people_spec.rb ├── questions_spec.rb ├── registrations_spec.rb └── users_spec.rb ├── helpers ├── application_helper_spec.rb ├── pages_helper_spec.rb ├── questions_helper_spec.rb └── signatures_helper_spec.rb ├── lib ├── democracy_map_governor_adapter_spec.rb ├── influence_explorer_spec.rb ├── legislator_spec.rb ├── project_vote_smart_spec.rb ├── sunlight_congress_legislator_adapter_spec.rb └── twitter_person_adapter_spec.rb ├── mailers ├── identity_mailer_spec.rb ├── person_mailer_spec.rb └── question_mailer_spec.rb ├── models ├── agenda_spec.rb ├── answer_spec.rb ├── bill_detail_spec.rb ├── blurb_spec.rb ├── cached_official_spec.rb ├── cached_officials_from_google_spec.rb ├── candidate_spec.rb ├── committee_spec.rb ├── councilmember_spec.rb ├── county_official_spec.rb ├── default_signature_threshold_spec.rb ├── federal_legislator_spec.rb ├── federal_official_spec.rb ├── geo_data_from_request_spec.rb ├── governor_spec.rb ├── identity_spec.rb ├── image_link_checker_spec.rb ├── image_src_url_spec.rb ├── influence_explorer_person_detail_spec.rb ├── jurisdiction_id_spec.rb ├── location_formatter_spec.rb ├── mayor_spec.rb ├── meeting_record_spec.rb ├── meeting_spec.rb ├── metadatum │ ├── seed_cities_spec.rb │ ├── state_spec.rb │ ├── unaffiliated_spec.rb │ └── us_spec.rb ├── metadatum_spec.rb ├── municipal_official_spec.rb ├── people_identifier_spec.rb ├── person_detail_retriever_spec.rb ├── person_detail_spec.rb ├── person_spec.rb ├── president_spec.rb ├── project_vote_smart_person_detail_spec.rb ├── question_spec.rb ├── registered_redirect_spec.rb ├── signature_spec.rb ├── state_legislator_spec.rb ├── state_official_spec.rb ├── user_role_spec.rb ├── user_spec.rb ├── vice_president_spec.rb ├── video_src_url_spec.rb └── vote_spec.rb ├── services ├── democracy_map_governor_service_spec.rb ├── open_states_legislator_service_spec.rb ├── sunlight_congress_legislator_service_spec.rb └── twitter_person_service_spec.rb ├── spec_helper.rb ├── support ├── disqus.rb └── files │ └── teststrip.mpg ├── uploaders └── media_uploader_spec.rb ├── validators └── user_email_matches_validator_spec.rb └── workers ├── geocode_worker_spec.rb ├── person_check_photo_url_worker_spec.rb ├── question_answered_notifier_worker_spec.rb ├── question_coordinates_worker_spec.rb ├── unaffiliated_person_tidy_worker_spec.rb ├── user_set_local_jurisdiction_abbreviation_spec.rb └── user_set_password_notice_worker_spec.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle 2 | /bin 3 | /log/*.log 4 | /tmp 5 | /dump-dir 6 | /public/assets 7 | /dump 8 | latest-mongo-dump.tar.gz 9 | /config/initializers/_heroku.rb 10 | /config/initializers/mongoid_billy_shim.rb 11 | /coverage 12 | /public/uploads 13 | .DS_Store 14 | .rbenv-version 15 | /.sass-cache 16 | dump.rdb 17 | rspec.failures 18 | -------------------------------------------------------------------------------- /.powrc: -------------------------------------------------------------------------------- 1 | if [ -f "$rvm_path/scripts/rvm" ] && [ -f ".rvmrc" ]; then 2 | source "$rvm_path/scripts/rvm" 3 | source ".rvmrc" 4 | fi 5 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 1.9.3-p484 2 | -------------------------------------------------------------------------------- /.rvmrc: -------------------------------------------------------------------------------- 1 | rvm ruby-1.9.3 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # use rspec-rerun for flickering tests due to poltergeist time outs 2 | language: ruby 3 | rvm: 4 | - 1.9.3 5 | services: 6 | - mongodb 7 | notifications: 8 | email: 9 | - web@mars-hq.com 10 | irc: 11 | channels: 12 | - 'irc.freednode.net#ogchatter' 13 | on_success: change 14 | use_notice: true 15 | skip_join: true -------------------------------------------------------------------------------- /Capfile: -------------------------------------------------------------------------------- 1 | load 'deploy' 2 | load 'deploy/assets' 3 | load 'config/deploy' if File.exists?('./config/deploy.rb') 4 | 5 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec unicorn -p $PORT -E production -c ./config/unicorn.rb 2 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | OpenGovernment::Application.load_tasks 7 | -------------------------------------------------------------------------------- /app/assets/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /app/assets/fonts/Roboto-Black-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/Roboto-Black-webfont.eot -------------------------------------------------------------------------------- /app/assets/fonts/Roboto-Black-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/Roboto-Black-webfont.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Roboto-Black-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/Roboto-Black-webfont.woff -------------------------------------------------------------------------------- /app/assets/fonts/Roboto-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/Roboto-Light-webfont.eot -------------------------------------------------------------------------------- /app/assets/fonts/Roboto-Light-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/Roboto-Light-webfont.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Roboto-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/Roboto-Light-webfont.woff -------------------------------------------------------------------------------- /app/assets/fonts/Roboto-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/Roboto-Regular-webfont.eot -------------------------------------------------------------------------------- /app/assets/fonts/Roboto-Regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/Roboto-Regular-webfont.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Roboto-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/Roboto-Regular-webfont.woff -------------------------------------------------------------------------------- /app/assets/fonts/Roboto-Thin-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/Roboto-Thin-webfont.eot -------------------------------------------------------------------------------- /app/assets/fonts/Roboto-Thin-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/Roboto-Thin-webfont.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Roboto-Thin-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/Roboto-Thin-webfont.woff -------------------------------------------------------------------------------- /app/assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /app/assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /app/assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /app/assets/images/AskThem_NCAA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/AskThem_NCAA.png -------------------------------------------------------------------------------- /app/assets/images/AskThem_Scotusblog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/AskThem_Scotusblog.png -------------------------------------------------------------------------------- /app/assets/images/badge.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/badge.ai -------------------------------------------------------------------------------- /app/assets/images/badge.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/badge.jpg -------------------------------------------------------------------------------- /app/assets/images/credit_dmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/credit_dmap.png -------------------------------------------------------------------------------- /app/assets/images/credit_google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/credit_google.png -------------------------------------------------------------------------------- /app/assets/images/credit_kfoundation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/credit_kfoundation.png -------------------------------------------------------------------------------- /app/assets/images/credit_opennorth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/credit_opennorth.png -------------------------------------------------------------------------------- /app/assets/images/credit_openstates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/credit_openstates.png -------------------------------------------------------------------------------- /app/assets/images/credit_ppf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/credit_ppf.png -------------------------------------------------------------------------------- /app/assets/images/credit_sunlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/credit_sunlight.png -------------------------------------------------------------------------------- /app/assets/images/credit_sunlight_color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/credit_sunlight_color.png -------------------------------------------------------------------------------- /app/assets/images/email_assets/ActionNetwork/email_footer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/ActionNetwork/email_footer.jpg -------------------------------------------------------------------------------- /app/assets/images/email_assets/ActionNetwork/email_header_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/ActionNetwork/email_header_1.jpg -------------------------------------------------------------------------------- /app/assets/images/email_assets/ActionNetwork/email_header_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/ActionNetwork/email_header_2.jpg -------------------------------------------------------------------------------- /app/assets/images/email_assets/ActionNetwork/email_header_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/ActionNetwork/email_header_3.jpg -------------------------------------------------------------------------------- /app/assets/images/email_assets/ActionNetwork/email_header_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/ActionNetwork/email_header_4.jpg -------------------------------------------------------------------------------- /app/assets/images/email_assets/ActionNetwork/high-res/email_footer_high-res.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/ActionNetwork/high-res/email_footer_high-res.jpg -------------------------------------------------------------------------------- /app/assets/images/email_assets/ActionNetwork/high-res/email_header_orange_high-res.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/ActionNetwork/high-res/email_header_orange_high-res.jpg -------------------------------------------------------------------------------- /app/assets/images/email_assets/ActionNetwork/high-res/email_headers-blue_high-res.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/ActionNetwork/high-res/email_headers-blue_high-res.jpg -------------------------------------------------------------------------------- /app/assets/images/email_assets/ActionNetwork/illustrator files/email_footers.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/ActionNetwork/illustrator files/email_footers.ai -------------------------------------------------------------------------------- /app/assets/images/email_assets/ActionNetwork/illustrator files/email_headers.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/ActionNetwork/illustrator files/email_headers.ai -------------------------------------------------------------------------------- /app/assets/images/email_assets/AskThem_logo_652x113.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/AskThem_logo_652x113.png -------------------------------------------------------------------------------- /app/assets/images/email_assets/AskThem_logo_email_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/AskThem_logo_email_header.png -------------------------------------------------------------------------------- /app/assets/images/email_assets/AskThem_screenshot_slidedeck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/AskThem_screenshot_slidedeck.png -------------------------------------------------------------------------------- /app/assets/images/email_assets/email-header-blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/email-header-blue.jpg -------------------------------------------------------------------------------- /app/assets/images/email_assets/email-header-no-symbol.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/email-header-no-symbol.jpg -------------------------------------------------------------------------------- /app/assets/images/email_assets/email-header-orange.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/email-header-orange.jpg -------------------------------------------------------------------------------- /app/assets/images/email_assets/email-header-symbol.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/email_assets/email-header-symbol.jpg -------------------------------------------------------------------------------- /app/assets/images/flag_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/flag_icon.png -------------------------------------------------------------------------------- /app/assets/images/flag_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/flag_icon@2x.png -------------------------------------------------------------------------------- /app/assets/images/followers_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/followers_icon.png -------------------------------------------------------------------------------- /app/assets/images/followers_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/followers_icon@2x.png -------------------------------------------------------------------------------- /app/assets/images/footer_illustration.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/footer_illustration.jpg -------------------------------------------------------------------------------- /app/assets/images/how_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/how_1.png -------------------------------------------------------------------------------- /app/assets/images/how_1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/how_1@2x.png -------------------------------------------------------------------------------- /app/assets/images/how_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/how_2.png -------------------------------------------------------------------------------- /app/assets/images/how_2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/how_2@2x.png -------------------------------------------------------------------------------- /app/assets/images/how_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/how_3.png -------------------------------------------------------------------------------- /app/assets/images/how_3@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/how_3@2x.png -------------------------------------------------------------------------------- /app/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/logo.png -------------------------------------------------------------------------------- /app/assets/images/mag_glass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/mag_glass.png -------------------------------------------------------------------------------- /app/assets/images/mag_glass@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/mag_glass@2x.png -------------------------------------------------------------------------------- /app/assets/images/mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/mark.png -------------------------------------------------------------------------------- /app/assets/images/nav_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/nav_arrow.png -------------------------------------------------------------------------------- /app/assets/images/nav_arrow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/nav_arrow@2x.png -------------------------------------------------------------------------------- /app/assets/images/pick.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/assets/images/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/placeholder.png -------------------------------------------------------------------------------- /app/assets/images/related_bg@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/related_bg@2x.png -------------------------------------------------------------------------------- /app/assets/images/related_delimiter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/related_delimiter.png -------------------------------------------------------------------------------- /app/assets/images/seal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/seal.png -------------------------------------------------------------------------------- /app/assets/images/seal@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/seal@2x.png -------------------------------------------------------------------------------- /app/assets/images/search_pick@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/search_pick@2x.png -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/amanda_michel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/amanda_michel.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/anthea_strong.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/anthea_strong.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/david_karpf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/david_karpf.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/david_moore.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/david_moore.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/josh_segall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/josh_segall.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/maryam_gunja.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/maryam_gunja.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/micah_sifry.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/micah_sifry.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/nicco_mele.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/nicco_mele.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/nick_grossman.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/nick_grossman.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/steven_trevathan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/steven_trevathan.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/susannah_vila.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/susannah_vila.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/tiffiniy_cheng.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/tiffiniy_cheng.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/tom_steinberg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/tom_steinberg.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/walter_mcginnis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/walter_mcginnis.jpg -------------------------------------------------------------------------------- /app/assets/images/splash_avatars/zephyr_teachout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/splash_avatars/zephyr_teachout.jpg -------------------------------------------------------------------------------- /app/assets/images/textarea_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/textarea_bg.png -------------------------------------------------------------------------------- /app/assets/images/textarea_bg@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/textarea_bg@2x.png -------------------------------------------------------------------------------- /app/assets/images/textarea_bg_focus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/textarea_bg_focus.png -------------------------------------------------------------------------------- /app/assets/images/textarea_bg_focus@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/textarea_bg_focus@2x.png -------------------------------------------------------------------------------- /app/assets/images/up_vote_sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/up_vote_sm.png -------------------------------------------------------------------------------- /app/assets/images/up_vote_sm@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/up_vote_sm@2x.png -------------------------------------------------------------------------------- /app/assets/images/usa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opengovernment/askthem/4f5c2199c4818df929fa6b647b9271dcfbf66793/app/assets/images/usa.jpg -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // the compiled file. 9 | // 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD 11 | // GO AFTER THE REQUIRES BELOW. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require jquery.autogrow-textarea 16 | //= require jquery.history 17 | //= require jquery.timeago 18 | //= require jquery.scrollTo.min 19 | //= require jquery.html5-placeholder-shim 20 | //= require jquery.equalheights 21 | //= require authentication 22 | //= require tabs 23 | //= require banner 24 | //= require bills 25 | //= require questions 26 | //= require responsive 27 | //= require forms 28 | //= require rails.validations 29 | //= require sign_on_user 30 | //= require modal 31 | //= require people 32 | //= require registrations 33 | //= require hovertip 34 | //= require equal_heights 35 | //= require progress_bar 36 | -------------------------------------------------------------------------------- /app/assets/javascripts/authentication.js.coffee: -------------------------------------------------------------------------------- 1 | jQuery ($) -> 2 | $('#new_registration #user_given_name,#edit_registration #user_given_name,#new_session #user_email,#new_password #user_email,#edit_password #user_password').focus() 3 | -------------------------------------------------------------------------------- /app/assets/javascripts/banner.js: -------------------------------------------------------------------------------- 1 | $('.banner-close').click(function() { 2 | $('.banner').fadeOut('fast'); 3 | }); 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/bills.js.coffee: -------------------------------------------------------------------------------- 1 | jQuery ($) -> 2 | $('a.show_full_title').click (e) -> 3 | e.preventDefault() 4 | target = $(this).attr('target') 5 | $(".#{target}_short").hide() 6 | $(".#{target}_long").show() 7 | 8 | $('a.show_short_title').click (e) -> 9 | e.preventDefault() 10 | target = $(this).attr('target') 11 | $(".#{target}_short").show() 12 | $(".#{target}_long").hide() 13 | -------------------------------------------------------------------------------- /app/assets/javascripts/equal_heights.js.coffee: -------------------------------------------------------------------------------- 1 | $(".radio_nav a").equalHeights() 2 | -------------------------------------------------------------------------------- /app/assets/javascripts/filters.js.coffee: -------------------------------------------------------------------------------- 1 | jQuery ($) -> 2 | 3 | filterContent = (e) -> 4 | radioName = e.delegateTarget 5 | if $(radioName).hasClass 'inactive' 6 | $(radioName).addClass('active').removeClass('inactive') 7 | $(radioName).siblings('a.radio_button').removeClass('active').addClass('inactive') 8 | else 9 | $(radioName).removeClass('active').addClass('inactive') 10 | 11 | if $('div.filters').length 12 | $('a.radio_button.filter').click (e) -> 13 | e.preventDefault() 14 | filterContent(e) 15 | -------------------------------------------------------------------------------- /app/assets/javascripts/hovertip.js: -------------------------------------------------------------------------------- 1 | $('.people .depiction').hover(function(){ 2 | $(this).children('.hover-tip').addClass('is-showing'); 3 | },function(){ 4 | $(this).children('.hover-tip').removeClass('is-showing'); 5 | }); 6 | -------------------------------------------------------------------------------- /app/assets/javascripts/jquery.equalheights.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Equal Heights Plugin 3 | * Equalize the heights of elements. Great for columns or any elements 4 | * that need to be the same size (floats, etc). 5 | * 6 | * Version 1.0 7 | * Updated 12/10/2008 8 | * 9 | * Copyright (c) 2008 Rob Glazebrook (cssnewbie.com) 10 | * 11 | * Usage: $(object).equalHeights([minHeight], [maxHeight]); 12 | * 13 | * Example 1: $(".cols").equalHeights(); Sets all columns to the same height. 14 | * Example 2: $(".cols").equalHeights(400); Sets all cols to at least 400px tall. 15 | * Example 3: $(".cols").equalHeights(100,300); Cols are at least 100 but no more 16 | * than 300 pixels tall. Elements with too much content will gain a scrollbar. 17 | * 18 | */ 19 | 20 | (function($) { 21 | $.fn.equalHeights = function(minHeight, maxHeight) { 22 | tallest = (minHeight) ? minHeight : 0; 23 | this.each(function() { 24 | if($(this).height() > tallest) { 25 | tallest = $(this).height(); 26 | } 27 | }); 28 | if((maxHeight) && tallest > maxHeight) tallest = maxHeight; 29 | return this.each(function() { 30 | $(this).height(tallest).css("overflow","hidden"); 31 | }); 32 | } 33 | })(jQuery); 34 | -------------------------------------------------------------------------------- /app/assets/javascripts/modal.js: -------------------------------------------------------------------------------- 1 | $('#overlay, .modal-close, .navigation-overlay').click(function() { 2 | $('#overlay, #modal, .navigation-overlay, .navigation-modal').fadeOut('fast'); 3 | }); 4 | 5 | $('.navigation-modal-open').click(function() { 6 | $('.navigation-overlay, .navigation-modal, i.icon-remove').fadeTo('slow', 1) 7 | }); 8 | -------------------------------------------------------------------------------- /app/assets/javascripts/people.js: -------------------------------------------------------------------------------- 1 | $('.is-verified').hover(function() { 2 | $('.verified-tooltip', this).addClass('is-showing').removeClass('is-hidden'); 3 | }, function() { 4 | $('.verified-tooltip', this).addClass('is-hidden').removeClass('is-showing'); 5 | }); 6 | -------------------------------------------------------------------------------- /app/assets/javascripts/progress_bar.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | var progress_width = $('[data-width]').data('width'); 3 | $('.progress_filler').width(progress_width + "%"); 4 | }); 5 | -------------------------------------------------------------------------------- /app/assets/javascripts/responsive.js.coffee: -------------------------------------------------------------------------------- 1 | jQuery ($) -> 2 | $('.mobile_admin_nav a.expose_nav').click -> 3 | $this = $(this) 4 | if $this.hasClass('expanded') 5 | $this.removeClass('expanded') 6 | $this.siblings('.admin_nav').hide() 7 | else 8 | $this.addClass('expanded') 9 | $this.siblings('.admin_nav').show() 10 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.sass: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | *= require_self 12 | *= require structure 13 | *= require_tree . 14 | */ 15 | -------------------------------------------------------------------------------- /app/assets/stylesheets/base.sass: -------------------------------------------------------------------------------- 1 | @import compass/reset 2 | @import load 3 | 4 | html 5 | -webkit-font-smoothing: antialiased 6 | 7 | body 8 | background-color: #d8f2f6 9 | font-family: helvetica, arial, verdana, sans-serif 10 | color: $darkblue 11 | 12 | a 13 | color: $linkcolor 14 | text-decoration: none 15 | outline: none 16 | cursor: pointer 17 | &:hover 18 | color: $linkhover 19 | 20 | h1, h2, h3, h4, h5, p 21 | word-wrap: break-word 22 | 23 | h1 24 | +RobotoRegular 25 | font: 26 | size: 2.625em 27 | weight: 100 28 | line-height: 1em 29 | color: $darkblue 30 | 31 | h2 32 | +RobotoRegular 33 | font-size: 1.125em 34 | line-height: 1.333em 35 | 36 | h3 37 | font: 38 | size: 1em 39 | weight: 600 40 | line-height: 1.5em 41 | color: $middleblue 42 | 43 | h4 44 | padding-bottom: 6px 45 | font: 46 | size: 0.813em 47 | weight: 600 48 | line-height: 1.385em 49 | color: $darkblue 50 | 51 | h5 52 | font: 53 | size: 0.625em 54 | weight: 600 55 | line-height: 2.4em 56 | text-transform: uppercase 57 | color: $darkblue 58 | 59 | strong 60 | font-weight: 600 61 | 62 | 63 | -------------------------------------------------------------------------------- /app/assets/stylesheets/misc.sass: -------------------------------------------------------------------------------- 1 | @import load 2 | 3 | article header h4 4 | font-weight: 200 5 | 6 | footer h5 7 | font-size: 0.813em 8 | line-height: 1.385em 9 | 10 | span.info 11 | font: 12 | size: 0.688em 13 | weight: 600 14 | line-height: 1.364em 15 | text-transform: uppercase 16 | color: $middlegrey 17 | 18 | span.emph 19 | padding: 0 3px 20 | display: inline-block 21 | border: 1px solid #DFDFDF 22 | +border-radius(3px) 23 | background-color: #EFEFEF 24 | font-weight: 600 25 | color: #818181 26 | 27 | .push 28 | margin-top: 1em 29 | display: block 30 | 31 | div.first-question-in-area 32 | h3 33 | margin-bottom: 18px 34 | -------------------------------------------------------------------------------- /app/assets/stylesheets/modules/activity.sass: -------------------------------------------------------------------------------- 1 | @import load 2 | 3 | .committee-activity 4 | margin-top: 1em 5 | display: inline-block 6 | .depiction 7 | margin: 8 | right: 10px 9 | bottom: 10px 10 | display: inline-block 11 | position: relative 12 | 13 | -------------------------------------------------------------------------------- /app/assets/stylesheets/modules/banner.sass: -------------------------------------------------------------------------------- 1 | @import load 2 | 3 | .banner 4 | padding-top: 2em 5 | position: fixed 6 | background-color: #F9F9F9 7 | z-index: 15000 8 | width: 100% 9 | height: 63px 10 | border-bottom: 1px solid #c6c6c6 11 | @media (max-width: 420px) 12 | padding-top: 1em 13 | padding-bottom: 1em 14 | height: auto 15 | 16 | .banner-close 17 | font-size: 1.5em 18 | position: absolute 19 | top: 7px 20 | right: 25px 21 | @media (max-width: 420px) 22 | right: 7px 23 | 24 | .banner-header 25 | font-size: 1.5em 26 | text-align: center 27 | @media (min-width: 420px) 28 | margin: 29 | right: auto 30 | left: auto 31 | width: 80% 32 | @media (max-width: 420px) 33 | margin: 34 | right: auto 35 | left: auto 36 | width: 70% 37 | -------------------------------------------------------------------------------- /app/assets/stylesheets/modules/blurbs.sass: -------------------------------------------------------------------------------- 1 | @import load 2 | 3 | .manage-blurb-show 4 | margin-top: 20px 5 | 6 | .blurb-active 7 | text-transform: uppercase 8 | .manage-blurb-headline 9 | font-size: larger 10 | font-weight: bold 11 | 12 | .manage-blurbs-list li 13 | border-bottom: 1px solid #000 14 | padding: 8px 15 | padding-bottom: 25px 16 | 17 | .manage-blurbs-blurb-summary 18 | display: inline 19 | 20 | .manage-actions 21 | display: inline-block 22 | float: right 23 | ul 24 | display: inline 25 | ul li 26 | display: inline 27 | padding: 1px 2px 1px 3px 28 | border: 1px solid #000 29 | 30 | .manage-blurbs-navigation 31 | margin-top: 10px 32 | text-align: center 33 | 34 | section.people .blurb-display 35 | padding-top: 0px 36 | -------------------------------------------------------------------------------- /app/assets/stylesheets/modules/candidates.sass: -------------------------------------------------------------------------------- 1 | @import load 2 | 3 | .manage-candidate-show 4 | margin-top: 20px 5 | 6 | .manage-candidate-full-name 7 | margin-left: 5px 8 | font-size: larger 9 | font-weight: bold 10 | 11 | .manage-candidates-list li 12 | border-bottom: 1px solid #000 13 | padding: 8px 14 | padding-bottom: 25px 15 | 16 | .manage-candidates-candidate-summary 17 | display: inline 18 | div.avatar 19 | display: inline-block 20 | max-width: 60px 21 | width: 20% 22 | margin: 5px 23 | 24 | .manage-candidates-navigation 25 | margin-top: 10px 26 | text-align: center 27 | 28 | form.pre-populate-candidate-form 29 | label, .cta-pill 30 | margin-top: 1em 31 | 32 | form.new_candidate 33 | label, .cta-pill 34 | margin-top: 1em 35 | -------------------------------------------------------------------------------- /app/assets/stylesheets/modules/flash.sass: -------------------------------------------------------------------------------- 1 | @import load 2 | 3 | .notice, .alert 4 | margin: 5 | top: 3em 6 | left: 7.69231% 7 | padding: 10px 8 | width: 85.71429% 9 | border: 1px solid #ececec 10 | +border-radius(3px) 11 | background-color: #fbfbfb 12 | font-size: 0.813em 13 | text-align: center 14 | -------------------------------------------------------------------------------- /app/assets/stylesheets/modules/loading.sass: -------------------------------------------------------------------------------- 1 | @import load 2 | 3 | .loading 4 | margin-top: 50px 5 | font-size: 1.5em 6 | //display: none 7 | text-transform: uppercase 8 | 9 | .loading-1 10 | opacity: 0 11 | -webkit-animation: dot 1.3s infinite 12 | -webkit-animation-delay: 0.0s 13 | 14 | .loading-2 15 | opacity: 0 16 | -webkit-animation: dot 1.3s infinite 17 | -webkit-animation-delay: 0.2s 18 | 19 | .loading-3 20 | opacity: 0 21 | -webkit-animation: dot 1.3s infinite 22 | -webkit-animation-delay: 0.3s 23 | 24 | @-webkit-keyframes dot 25 | 0%, 50% 26 | opacity: 0 27 | 100% 28 | opacity: 1 29 | -------------------------------------------------------------------------------- /app/assets/stylesheets/modules/locator.sass: -------------------------------------------------------------------------------- 1 | @import load 2 | 3 | .locator .level 4 | margin-bottom: 1em 5 | 6 | .locator-people-list 7 | margin-top: 2em 8 | 9 | .more-candidates-info 10 | clear: both 11 | padding-top: 2em 12 | border-top: 1px solid #ebf1f3 13 | font-size: smaller 14 | 15 | .more-candidates-info p 16 | margin-bottom: 1em 17 | -------------------------------------------------------------------------------- /app/assets/stylesheets/modules/navigation.sass: -------------------------------------------------------------------------------- 1 | @import load 2 | 3 | .jurisdiction-change 4 | a.navigation-modal-open 5 | padding: 0 6 | margin-left: -15px 7 | display: inline 8 | font-size: smaller 9 | font-weight: normal 10 | vertical-align: super 11 | a.navigation-modal-open:before 12 | content: "[" 13 | a.navigation-modal-open:after 14 | content: "]" 15 | -------------------------------------------------------------------------------- /app/assets/stylesheets/modules/partner-return-to.sass: -------------------------------------------------------------------------------- 1 | .partner-return-to 2 | background-color: #CCE3DB 3 | text-align: center 4 | height: 66px 5 | width: 100% 6 | padding-top: 8px 7 | position: fixed 8 | left: 0px 9 | bottom: 0px 10 | 11 | .partner-intro 12 | padding-bottom: .3em 13 | .partner-logo 14 | height: 40px 15 | vertical-align: bottom 16 | padding-bottom: 2px 17 | -------------------------------------------------------------------------------- /app/assets/stylesheets/modules/static.sass: -------------------------------------------------------------------------------- 1 | @import load 2 | 3 | .static 4 | padding-top: 42px 5 | 6 | .related_data 7 | padding: 8 | top: 42px 9 | right: 42px 10 | left: 42px 11 | line-height: 1.75 12 | overflow: auto 13 | 14 | p 15 | padding-bottom: .5em 16 | 17 | em 18 | font-style: italic 19 | 20 | ul 21 | list-style-type: disc 22 | 23 | li 24 | padding-bottom: .5em 25 | 26 | h3 27 | padding-bottom: .5em 28 | 29 | h3:not(:first-child) 30 | padding-top: 1.5em 31 | -------------------------------------------------------------------------------- /app/authorizers/identity_authorizer.rb: -------------------------------------------------------------------------------- 1 | class IdentityAuthorizer < ApplicationAuthorizer 2 | # Class method: all users can create identities 3 | def self.creatable_by?(user) 4 | true 5 | end 6 | 7 | # only staff members can verify or reject an identity 8 | def updatable_by?(user) 9 | user.has_role? :staff_member 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/controllers/blurbs_controller.rb: -------------------------------------------------------------------------------- 1 | class BlurbsController < InheritedResources::Base 2 | before_filter :force_http 3 | before_filter :authenticate_user! 4 | before_filter :check_manage_blurbs 5 | before_filter :set_blurb_user, only: :create 6 | 7 | def new 8 | @target_url = params[:target_url] || "/" 9 | new! 10 | end 11 | 12 | def edit 13 | @target_url = params[:target_url] || resource.target_url 14 | edit! 15 | end 16 | 17 | private 18 | def set_blurb_user 19 | params[:blurb][:user] = current_user 20 | end 21 | 22 | def check_manage_blurbs 23 | unless current_user.can?(:manage_blurbs) 24 | raise Authority::SecurityViolation.new(current_user, 25 | :manage_blurbs, 26 | BlurbsController) 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /app/controllers/identities_controller.rb: -------------------------------------------------------------------------------- 1 | class IdentitiesController < ApplicationController 2 | before_filter :authenticate_user! 3 | 4 | def update 5 | @identity = Identity.find(params[:id]) 6 | authorize_action_for @identity 7 | 8 | @event = params[:event] 9 | @identity.inspection_event(@event, current_user) 10 | 11 | redirect_to user_path(@identity.user) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/controllers/meetings_controller.rb: -------------------------------------------------------------------------------- 1 | class MeetingsController < ApplicationController 2 | before_filter :force_http 3 | 4 | def show 5 | 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/controllers/omniauth_callbacks_controller.rb: -------------------------------------------------------------------------------- 1 | class OmniauthCallbacksController < Devise::OmniauthCallbacksController 2 | force_ssl if Rails.env.production? 3 | 4 | # If a user is already signed in, do not allow Facebook sign in. 5 | prepend_before_filter :require_no_authentication, only: :facebook 6 | 7 | # @see https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview 8 | def facebook 9 | user = User.where(authentications: {'$elemMatch' => request.env['omniauth.auth'].slice('provider', 'uid')}.to_hash).first 10 | if user 11 | # Forces all authentication callbacks. 12 | sign_in_and_redirect(user, event: :authentication) 13 | else 14 | session['devise.facebook_data'] = request.env['omniauth.auth'].to_hash 15 | redirect_to new_user_registration_path 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/controllers/robots_controller.rb: -------------------------------------------------------------------------------- 1 | class RobotsController < ApplicationController 2 | # handles /robots.txt 3 | def show 4 | @disallows = disallowed_pages + disallowed_directories + disallowed_actions 5 | end 6 | 7 | private 8 | def disallowed_pages 9 | ["/locator", "/identifier", "/contact_info", 10 | "/users/sign_in", "/users/sign_up", "/users/edit", "/users/confirmation"] 11 | end 12 | 13 | def disallowed_directories 14 | names = %w{identities answers signatures} 15 | names += ["users/auth", "users/password", "users/confirmation"] 16 | names.collect { |name| "/#{name}/"} 17 | end 18 | 19 | def disallowed_actions 20 | Metadatum.all.inject([]) do |disallowed_actions, metadatum| 21 | disallowed_actions << "/#{metadatum.id}/questions/new" 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < Devise::SessionsController 2 | force_ssl if Rails.env.production? 3 | 4 | layout 'data_collection' 5 | end 6 | -------------------------------------------------------------------------------- /app/controllers/subjects_controller.rb: -------------------------------------------------------------------------------- 1 | class SubjectsController < ApplicationController 2 | before_filter :force_http 3 | 4 | inherit_resources 5 | belongs_to :jurisdiction, parent_class: Metadatum, finder: :find_by_abbreviation, param: :jurisdiction 6 | respond_to :html 7 | respond_to :js, only: :show 8 | actions :index, :show 9 | 10 | def show 11 | show! do |format| 12 | @bills = chain.recent.where(subjects: @subject) 13 | .includes(:questions) 14 | .page(params[:page]) # no index includes `session`, so we omit it 15 | 16 | format.js { render partial: "page" } 17 | end 18 | end 19 | 20 | private 21 | # @note MT, RI and WI have inconsistent subject names (typos, etc.). 22 | def chain 23 | Bill.connected_to(parent.abbreviation) 24 | end 25 | 26 | def collection 27 | @subjects ||= chain.distinct("subjects").sort 28 | end 29 | 30 | def resource 31 | @subject ||= chain.distinct("subjects") 32 | .find { |subject| subject.parameterize == params[:id].parameterize } 33 | 34 | raise Exception, "Subject #{params[:id]} not valid" unless @subject 35 | 36 | @subject 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | before_filter :force_http 3 | 4 | inherit_resources 5 | respond_to :html 6 | actions :show, :update 7 | custom_actions resource: [:questions, :signatures] 8 | 9 | before_filter :authenticate_user!, only: [:update] 10 | before_filter :check_can_manage_user, only: :update 11 | 12 | def show 13 | @questions = resource.questions.includes(:user).page(params[:page]) 14 | tab "questions" 15 | end 16 | 17 | def signatures 18 | @signatures = resource.signatures.page(params[:page]) 19 | tab "signatures" 20 | end 21 | 22 | private 23 | 24 | def tab(tab) 25 | @tab = tab 26 | show! do |format| 27 | format.html { render action: "show" } 28 | format.js { render partial: @tab } 29 | end 30 | end 31 | 32 | def check_can_manage_user 33 | unless current_user.can?(:manage_user) 34 | raise Authority::SecurityViolation.new(current_user, 35 | :manage_user, 36 | UsersController) 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /app/helpers/pages_helper.rb: -------------------------------------------------------------------------------- 1 | module PagesHelper 2 | def csv_safe_links_for(person) 3 | links = person.person_detail.links.inject([]) do |results, link| 4 | results << "#{link.note}: #{link.url}" 5 | end 6 | links.any? ? links.join(' ; ') : nil 7 | end 8 | 9 | def csv_safe_office_details_for(person) 10 | offices = person.read_attribute(:offices) 11 | if offices.any? 12 | offices.to_s.gsub('"', "").gsub("=>", ":").gsub("[", "").gsub("\\n", " ") 13 | .gsub("]", "").gsub("},", " - ").gsub("{", "").gsub(",", "") 14 | .gsub("nil", "").gsub("}", "") 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/helpers/signatures_helper.rb: -------------------------------------------------------------------------------- 1 | module SignaturesHelper 2 | def signers_description(signer) 3 | description = sanitize("#{signer.given_name} #{signer.family_name}") 4 | 5 | avatar_tag = if signer.image? 6 | cdn_image_tag(signer.image.url, 7 | size: "40x40", 8 | alt: "", 9 | class: "avatar-image") 10 | else 11 | image_tag("placeholder.png", 12 | size: "40x40", 13 | class: "avatar-image") 14 | end 15 | 16 | description = "#{avatar_tag} #{description}" 17 | 18 | if signer.locality.present? && signer.region.present? 19 | signer_from = sanitize("(#{signer.locality}, #{signer.region.upcase})") 20 | description = "#{description} #{signer_from}" 21 | end 22 | 23 | description.html_safe 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /app/mailers/identity_mailer.rb: -------------------------------------------------------------------------------- 1 | class IdentityMailer < ActionMailer::Base 2 | add_template_helper(ApplicationHelper) 3 | 4 | default from: ENV["NOTIFICATION_SENDER_EMAIL"] 5 | 6 | def identity_submitted(identity) 7 | send_user_mail_for(identity, "Your AskThem identity is being verified") 8 | end 9 | 10 | def identity_needs_inspection(identity, staff_member) 11 | @staff_member = staff_member 12 | @user = identity.user 13 | @person = identity.person 14 | mail(:to => @staff_member.email, 15 | :subject => "An AskThem identity needs to be inspected") 16 | end 17 | 18 | def identity_verified(identity) 19 | send_user_mail_for(identity, "Your AskThem identity has been verified") 20 | end 21 | 22 | def identity_rejected(identity) 23 | send_user_mail_for(identity, "Your AskThem identity could not be verified") 24 | end 25 | 26 | private 27 | def send_user_mail_for(identity, subject) 28 | @user = identity.user 29 | @person = identity.person 30 | mail :to => @user.email, :subject => subject 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /app/mailers/person_mailer.rb: -------------------------------------------------------------------------------- 1 | class PersonMailer < ActionMailer::Base 2 | add_template_helper(ApplicationHelper) 3 | 4 | default from: ENV["NOTIFICATION_SENDER_EMAIL"] 5 | 6 | def notify_staff_new_from_twitter(person) 7 | @person = person 8 | @screen_name = person.read_attribute(:twitter_id) 9 | subject = "New person added from Twitter: #{@screen_name}" 10 | 11 | mail to: UserRole.staff_members.pluck(:email), subject: subject 12 | end 13 | 14 | def notify_staff_bad_person(cached_official) 15 | @cached_official = cached_official 16 | subject = "Cached Official does not match person" 17 | 18 | mail to: UserRole.staff_members.pluck(:email), subject: subject 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /app/models/agenda.rb: -------------------------------------------------------------------------------- 1 | class Agenda 2 | include Mongoid::Document 3 | 4 | embedded_in :meeting 5 | 6 | field :url, type: String 7 | field :full_text, type: String 8 | 9 | validates_presence_of :url 10 | end 11 | -------------------------------------------------------------------------------- /app/models/authentication.rb: -------------------------------------------------------------------------------- 1 | class Authentication 2 | include Mongoid::Document 3 | include Mongoid::Timestamps 4 | 5 | embedded_in :user 6 | 7 | field :provider, type: String 8 | field :uid, type: String 9 | 10 | validates_presence_of :provider, :uid 11 | validates_inclusion_of :provider, in: %w(facebook), allow_blank: true 12 | validates_uniqueness_of :provider 13 | end 14 | -------------------------------------------------------------------------------- /app/models/bill_detail.rb: -------------------------------------------------------------------------------- 1 | # Exists only because we blow away the `bills` collection regularly. 2 | class BillDetail 3 | include Mongoid::Document 4 | 5 | # The bill's jurisdiction. 6 | field :state, type: String 7 | # The bill. 8 | field :bill_id, type: String 9 | # The bill's billId from Project VoteSmart. 10 | field :votesmart_id, type: String 11 | 12 | index(state: 1) 13 | index(bill_id: 1) 14 | index(votesmart_id: 1) 15 | 16 | validates_presence_of :state, :bill_id 17 | 18 | # @return [Metadatum] the jurisdiction in which the bill belongs 19 | def metadatum 20 | Metadatum.find_by_abbreviation(state) 21 | end 22 | 23 | # @todo delete if unnecessary with only 1 db 24 | # i.e. does belongs_to now work 25 | # @return [Bill] the bill 26 | def bill 27 | Bill.find(bill_id) 28 | end 29 | 30 | # @todo delete if unnecessary with only 1 db 31 | # i.e. does belongs_to now work (with delegate state to bill) 32 | # @param [Bill] bill a bill 33 | def bill=(bill) 34 | if bill 35 | self.bill_id = bill.id 36 | self.state = bill['state'] 37 | else 38 | self.bill_id = nil 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /app/models/blurb.rb: -------------------------------------------------------------------------------- 1 | # simple snippets of content meant for use on homepage & maybe other spots 2 | class Blurb 3 | include Mongoid::Document 4 | include Mongoid::Timestamps 5 | 6 | belongs_to :user 7 | 8 | field :headline, type: String 9 | field :body, type: String 10 | field :active, type: Boolean, default: false 11 | 12 | # if "/" then blurb is for homepage 13 | field :target_url, type: String, default: "/" 14 | 15 | field :avatar_url, type: String 16 | 17 | # only one active blurb at a time 18 | after_save :make_all_others_inactive, if: :active? 19 | 20 | validates_presence_of :headline, :body 21 | 22 | scope :active, where(active: true) 23 | 24 | private 25 | def make_all_others_inactive 26 | other_blurbs = self.class.where(active: true).nin(id: [id]) 27 | 28 | if target_url 29 | other_blurbs = other_blurbs.where(target_url: target_url) 30 | else 31 | other_blurbs = other_blurbs.where(target_url: nil) 32 | end 33 | 34 | other_blurbs.each do |record| 35 | record.update_attributes(active: false) 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /app/models/committee.rb: -------------------------------------------------------------------------------- 1 | # Billy 2 | class Committee 3 | include Mongoid::Document 4 | 5 | belongs_to :metadatum, foreign_key: "state" 6 | 7 | # Returns the committee"s name. 8 | # 9 | # @return [String] the committee"s name 10 | # @note From Popolo. 11 | def name 12 | read_attribute(:subcommittee) || read_attribute(:committee) 13 | end 14 | 15 | # Returns the committee"s members. 16 | # 17 | # @return the committee"s members as scope 18 | # @note We do this because the OpenStates database is inconsistent. 19 | def people 20 | ids = read_attribute(:members).map { |x| x["leg_id"] }.compact 21 | return Person.in(id: []) unless ids.present? 22 | 23 | Person.in(id: ids) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /app/models/councilmember.rb: -------------------------------------------------------------------------------- 1 | require "legislator" 2 | 3 | class Councilmember < Person 4 | include Legislator 5 | 6 | # this is a very naive implementation, only does city or county wide 7 | # handle special case where councilmember is on county as well 8 | def self.for_location(location) 9 | location = LocationFormatter.new(location).format 10 | return where(id: []) unless location 11 | 12 | city = location.city 13 | return where(id: []) unless city 14 | 15 | any_of({ state: JurisdictionId.new(state: location.state_code, 16 | municipality: city).id }, 17 | { state: JurisdictionId.new(state: location.state_code, 18 | county: city).id }) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /app/models/county_official.rb: -------------------------------------------------------------------------------- 1 | class CountyOfficial < Person 2 | def self.for_location(location) 3 | location = LocationFormatter.new(location).format 4 | return where(id: []) unless location 5 | 6 | where(state: JurisdictionId.new(state: location.state_code, 7 | county: location.sub_state_code).id) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/models/default_signature_threshold.rb: -------------------------------------------------------------------------------- 1 | class DefaultSignatureThreshold 2 | DEFAULT_VALUES = { unspecified_person: 100, 3 | unaffiliated: 100, 4 | candidate: 15, 5 | federal: { upper: 500, lower: 350 }, 6 | major_city_council: 25, 7 | state: 100, 8 | governor: 500 } 9 | 10 | def initialize(person) 11 | @person = person if person 12 | end 13 | 14 | def value 15 | return DEFAULT_VALUES[:unspecified_person] unless @person 16 | 17 | # @todo replace with more sophisticated calculation 18 | case @person.class.name 19 | when "Councilmember" 20 | DEFAULT_VALUES[:major_city_council] 21 | when "FederalLegislator" 22 | DEFAULT_VALUES[:federal][@person.chamber.to_sym] 23 | when "Governor" 24 | DEFAULT_VALUES[:governor] 25 | when "Candidate" 26 | DEFAULT_VALUES[:candidate] 27 | when "Person" 28 | DEFAULT_VALUES[:unaffiliated] 29 | else 30 | DEFAULT_VALUES[:unspecified_person] 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /app/models/federal_legislator.rb: -------------------------------------------------------------------------------- 1 | require "legislator" 2 | require "legislator_finder" 3 | require "sunlight_congress_legislator_adapter" 4 | 5 | class FederalLegislator < Person 6 | include Legislator 7 | extend LegislatorFinder 8 | 9 | PHOTOS_BASE_URL = "http://theunitedstates.io/images/congress/225x275/" 10 | 11 | def self.default_api 12 | SunlightCongressLegislatorService 13 | end 14 | 15 | def image? 16 | persisted? && id.present? 17 | end 18 | 19 | def image 20 | read_attribute(:photo_url) || "#{PHOTOS_BASE_URL}#{id}.jpg" 21 | end 22 | 23 | alias_method :photo_url, :image 24 | 25 | def political_position_title 26 | case political_position 27 | when "upper" 28 | "Senator" 29 | when "lower" 30 | "Representative" 31 | end 32 | end 33 | 34 | private 35 | def adapt(attributes, options = {}) 36 | adapter = options[:adapter] || SunlightCongressLegislatorAdapter.new(self) 37 | super(attributes, options.merge({ adapter: adapter })) 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /app/models/federal_official.rb: -------------------------------------------------------------------------------- 1 | class FederalOfficial < Person 2 | def self.for_location(location) 3 | location = LocationFormatter.new(location).format 4 | return where(id: []) unless location 5 | 6 | where(state: JurisdictionId.new(state: location.country_code).id) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/models/geo_data_from_request.rb: -------------------------------------------------------------------------------- 1 | class GeoDataFromRequest 2 | attr_accessor :request, :geo_data 3 | 4 | def initialize(request) 5 | @request = request 6 | end 7 | 8 | def geo_data 9 | @geo_data = existing_value || request.location 10 | 11 | redis.set(ip, Marshal.dump(@geo_data)) unless existing_value 12 | 13 | @geo_data 14 | rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ENETUNREACH 15 | nil 16 | end 17 | 18 | private 19 | def redis 20 | @redis ||= Redis.new 21 | rescue Redis::CannotConnectError, Errno::ENETUNREACH 22 | NullRedis.new 23 | end 24 | 25 | def ip 26 | @ip ||= request.remote_addr 27 | end 28 | 29 | def existing_value 30 | geo_data_as_dump = redis.get(ip) 31 | geo_data_as_dump && !geo_data_as_dump.empty? ? Marshal.load(geo_data_as_dump) : nil 32 | end 33 | 34 | # answer the same API that we need from Redis, but do nothing 35 | # useful for handling connectivity issues 36 | class NullRedis 37 | def set(key, value) 38 | end 39 | 40 | def get(key) 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /app/models/governor.rb: -------------------------------------------------------------------------------- 1 | require "democracy_map_governor_adapter" 2 | 3 | class Governor < Person 4 | def self.default_api 5 | DemocracyMapGovernorService 6 | end 7 | 8 | def self.load_governors 9 | # drop non-states from array 10 | # @todo evaluate how to handle pr (think has governor, 11 | # but doesn't show up in dm data) 12 | states = OpenGovernment::STATES.values - ["dc", "pr"] 13 | states.collect { |state| load_from_apis_for_jurisdiction(state) } 14 | end 15 | 16 | def self.for_location(location) 17 | location = LocationFormatter.new(location).format 18 | return where(id: []) unless location 19 | 20 | where(state: JurisdictionId.new(state: location.state_code).id) 21 | end 22 | 23 | private 24 | def adapt(attributes, options = {}) 25 | adapter = options[:adapter] || DemocracyMapGovernorAdapter.new(self) 26 | super(attributes, options.merge({ adapter: adapter })) 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/models/image_src_url.rb: -------------------------------------------------------------------------------- 1 | class ImageSrcUrl 2 | IMAGE_TYPES = %w(jpg jpeg gif png) 3 | 4 | attr_accessor :url 5 | 6 | def initialize(url) 7 | @url = url 8 | end 9 | 10 | def is_image? 11 | IMAGE_TYPES.include?(File.extname(url.downcase).sub(".", "")) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/models/jurisdiction_id.rb: -------------------------------------------------------------------------------- 1 | class JurisdictionId 2 | attr_accessor :state, :municipality, :county 3 | 4 | def initialize(options) 5 | @state = options[:state] 6 | @municipality = options[:municipality] 7 | @county = options[:county] 8 | end 9 | 10 | def id 11 | raise "Must specify state" unless state 12 | raise "Only municipality or county, not both" if municipality && county 13 | 14 | id = state.downcase 15 | id += "-#{for_id(municipality)}" if municipality 16 | id += "-county-#{for_id(county)}" if county 17 | id 18 | end 19 | 20 | private 21 | def for_id(name) 22 | name.downcase.gsub(" ", "-").gsub("_", "-") 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /app/models/key_vote.rb: -------------------------------------------------------------------------------- 1 | # Project VoteSmart 2 | # @see http://api.votesmart.org/docs/Votes.html 3 | class KeyVote 4 | include Mongoid::Document 5 | 6 | # @todo add fields, associations 7 | end 8 | -------------------------------------------------------------------------------- /app/models/link.rb: -------------------------------------------------------------------------------- 1 | # A URL for a document about a person. 2 | # @note From Popolo. 3 | class Link 4 | include Mongoid::Document 5 | 6 | embedded_in :person_detail 7 | 8 | # A URL for a document about a person. 9 | field :url, type: String 10 | # A note, e.g. 'Wikipedia page'. 11 | field :note, type: String 12 | 13 | validates_presence_of :url 14 | end 15 | -------------------------------------------------------------------------------- /app/models/location_formatter.rb: -------------------------------------------------------------------------------- 1 | class LocationFormatter 2 | attr_accessor :data 3 | 4 | def initialize(location) 5 | @data = geodata_from(location) 6 | end 7 | 8 | def format 9 | location_is_valid?(data) ? data : nil 10 | end 11 | 12 | private 13 | def geodata_from(location) 14 | if location.is_a?(Geocoder::Result::Base) 15 | location 16 | else 17 | Geocoder.search(location).first 18 | end 19 | end 20 | 21 | def location_is_valid?(data) 22 | data && 23 | data.country_code == 'US' && 24 | data.latitude.nonzero? && 25 | data.longitude.nonzero? 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app/models/mayor.rb: -------------------------------------------------------------------------------- 1 | class Mayor < Person 2 | def self.for_location(location) 3 | location = LocationFormatter.new(location).format 4 | return where(id: []) unless location 5 | 6 | city = location.city 7 | return where(id: []) unless city 8 | 9 | # handle special case where mayor is on county as well 10 | any_of({ state: JurisdictionId.new(state: location.state_code, 11 | municipality: city).id }, 12 | { state: JurisdictionId.new(state: location.state_code, 13 | county: city).id }) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/models/metadatum/unaffiliated.rb: -------------------------------------------------------------------------------- 1 | # special case for people that are not known to be elected officials 2 | class Metadatum::Unaffiliated 3 | ABBREVIATION = "unaffiliated" 4 | 5 | # return Unaffiliated jurisidiction 6 | def self.find_or_create! 7 | Metadatum.where(abbreviation: ABBREVIATION).first || 8 | create_unaffiliated_metadatum 9 | end 10 | 11 | def self.create_unaffiliated_metadatum 12 | attributes = { abbreviation: ABBREVIATION, 13 | "_id" => "unaffiliated", 14 | chambers: { "lower" => { "name" => "Unspecified", "title" => "" } }, 15 | name: "Unaffiliated", 16 | legislature_name: "" 17 | } 18 | 19 | Metadatum.create! attributes 20 | end 21 | 22 | private_class_method :create_unaffiliated_metadatum 23 | end 24 | -------------------------------------------------------------------------------- /app/models/metadatum/us.rb: -------------------------------------------------------------------------------- 1 | # used for populating a new instance of Metadatum 2 | # for 'us' jurisdiction 3 | class Metadatum::Us 4 | ABBREVIATION = 'us' 5 | 6 | # return US jurisidiction 7 | def self.find_or_create! 8 | Metadatum.where(abbreviation: ABBREVIATION).first || 9 | create_us_metadatum 10 | end 11 | 12 | def self.create_us_metadatum 13 | attributes = { abbreviation: ABBREVIATION, 14 | chambers: { "upper" => { "name" => "Senate", "title" => "Senator" }, 15 | "lower" => { "name" => "House", "title" => "Representative" } }, 16 | name: "United States", 17 | legislature_name: "United States Congress" 18 | } 19 | 20 | Metadatum.create! attributes 21 | end 22 | 23 | private_class_method :create_us_metadatum 24 | end 25 | -------------------------------------------------------------------------------- /app/models/minutes_document.rb: -------------------------------------------------------------------------------- 1 | class MinutesDocument 2 | include Mongoid::Document 3 | 4 | embedded_in :meeting 5 | 6 | field :url, type: String 7 | field :full_text, type: String 8 | 9 | validates_presence_of :url 10 | end 11 | -------------------------------------------------------------------------------- /app/models/municipal_official.rb: -------------------------------------------------------------------------------- 1 | class MunicipalOfficial < Person 2 | def self.for_location(location) 3 | location = LocationFormatter.new(location).format 4 | return where(id: []) unless location 5 | 6 | where(state: JurisdictionId.new(state: location.state_code, 7 | municipality: location.city).id) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/models/president.rb: -------------------------------------------------------------------------------- 1 | class President < Person 2 | def self.for_location(location) 3 | location = LocationFormatter.new(location).format 4 | return where(id: []) unless location 5 | 6 | where(state: JurisdictionId.new(state: location.country_code).id) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/models/rating_group.rb: -------------------------------------------------------------------------------- 1 | # Project VoteSmart 2 | # 3 | # A special interest group can belong to multiple categories, so we would need 4 | # a HABTM association between the two. This information is not directly 5 | # available in the API. We should also verify if a special interest group can 6 | # ever assign a rating whose categories are outside its own categories. 7 | # 8 | # @see http://api.votesmart.org/docs/Rating.html 9 | class RatingGroup 10 | include Mongoid::Document 11 | 12 | # The special interest group's scorecards. 13 | has_many :rating_scorecards, foreign_key: 'sigId', primary_key: 'sigId' 14 | # The special interest group's ratings. 15 | has_many :ratings, foreign_key: 'sigId', primary_key: 'sigId' 16 | 17 | index(sigId: 1) 18 | 19 | field :parentId, type: String # always -1 20 | field :stateId, type: String # always "NA" 21 | field :name, type: String 22 | field :description, type: String 23 | field :address, type: String 24 | field :city, type: String 25 | field :state, type: String 26 | field :zip, type: String 27 | field :phone1, type: String 28 | field :phone2, type: String 29 | field :fax, type: String 30 | field :email, type: String 31 | field :url, type: String 32 | field :contactName, type: String 33 | end 34 | -------------------------------------------------------------------------------- /app/models/rating_scorecard.rb: -------------------------------------------------------------------------------- 1 | # Project VoteSmart 2 | # @see http://api.votesmart.org/docs/Rating.html 3 | class RatingScorecard 4 | include Mongoid::Document 5 | 6 | # The scorecard's special interest_group. 7 | belongs_to :rating_group, foreign_key: 'sigId', primary_key: 'sigId' 8 | # The scorecard's ratings. 9 | has_many :ratings, foreign_key: 'ratingId', primary_key: 'ratingId' 10 | 11 | index(ratingId: 1) 12 | index(sigId: 1) 13 | index(retrieved: 1) 14 | 15 | # A time span in the format `YYYY` or `YYYY-YYYY`, or the empty string. 16 | field :timespan, type: String 17 | # One of roughly 189 names for the scorecard. 18 | field :ratingName, type: String 19 | # One of roughly 105 templates to describe what the scorecard is about. 20 | field :ratingText, type: String 21 | 22 | # Fields from the special interest group. 23 | field :name, type: String 24 | field :description, type: String 25 | 26 | # When the scorecard's ratings were retrieved. 27 | field :retrieved, type: Time 28 | end 29 | -------------------------------------------------------------------------------- /app/models/registered_redirect.rb: -------------------------------------------------------------------------------- 1 | class RegisteredRedirect 2 | include Mongoid::Document 3 | include Mongoid::Timestamps 4 | 5 | field :from_url_pattern, type: String 6 | field :to_url_pattern, type: String 7 | field :status_code, type: Integer, default: 301 8 | 9 | validates_presence_of :from_url_pattern, :to_url_pattern 10 | 11 | # takes a request and returns last (latest) registered_redirect 12 | # that has a matching from_url_pattern 13 | # most complete match takes precedence 14 | def self.match(request) 15 | full_path = request.fullpath.downcase 16 | 17 | any_of({ from_url_pattern: full_path }, 18 | { from_url_pattern: /#{full_path}/i }) 19 | 20 | end 21 | 22 | # for now this simply returns to_url_pattern 23 | # but in the future it will handle more complex replacements 24 | def new_url_from(request) 25 | to_url_pattern 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app/models/state_legislator.rb: -------------------------------------------------------------------------------- 1 | require "legislator" 2 | require "legislator_finder" 3 | 4 | class StateLegislator < Person 5 | include Legislator 6 | extend LegislatorFinder 7 | end 8 | -------------------------------------------------------------------------------- /app/models/state_official.rb: -------------------------------------------------------------------------------- 1 | class StateOfficial < Person 2 | def self.for_location(location) 3 | location = LocationFormatter.new(location).format 4 | return where(id: []) unless location 5 | 6 | where(state: JurisdictionId.new(state: location.state_code).id) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/models/user_role.rb: -------------------------------------------------------------------------------- 1 | # rolify role model 2 | # we use UserRole to avoid name collision with person.roles 3 | class UserRole 4 | include Mongoid::Document 5 | include Mongoid::Timestamps 6 | 7 | has_and_belongs_to_many :users 8 | belongs_to :resource, :polymorphic => true 9 | 10 | field :name, :type => String 11 | 12 | validates :name, uniqueness: true, if: :global_role? 13 | 14 | index({ name: 1, 15 | resource_type: 1, 16 | resource_id:1 17 | }, 18 | { unique: true}) 19 | 20 | scopify 21 | 22 | def self.staff_members 23 | staff_member_role = where(name: "staff_member").first 24 | return [] unless staff_member_role 25 | 26 | staff_member_role.users 27 | end 28 | 29 | private 30 | def global_role? 31 | resource_type.blank? && resource_field.blank? & resource_id.blank? 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /app/models/vice_president.rb: -------------------------------------------------------------------------------- 1 | class VicePresident < Person 2 | def self.for_location(location) 3 | location = LocationFormatter.new(location).format 4 | return where(id: []) unless location 5 | 6 | where(state: JurisdictionId.new(state: location.country_code).id) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/models/vote.rb: -------------------------------------------------------------------------------- 1 | # Billy 2 | class Vote 3 | include Mongoid::Document 4 | 5 | belongs_to :metadatum, foreign_key: "state" 6 | belongs_to :bill 7 | 8 | index("yes_votes.leg_id" => 1) 9 | index("no_votes.leg_id" => 1) 10 | index("other_votes.leg_id" => 1) 11 | 12 | # Returns the people who voted. 13 | # 14 | # @return [Array] the people who voted 15 | # @note We do this because the OpenStates database is inconsistent. 16 | def people 17 | ids = [] 18 | %w(yes no other).each do |type| 19 | ids += read_attribute("#{type}_votes").map { |x| x["leg_id"] }.compact 20 | end 21 | if ids.empty? 22 | [] 23 | else 24 | Person.where(_id: { "$in" => ids }).to_a 25 | end 26 | end 27 | 28 | # Returns whether the vote has passed or failed 29 | # 30 | # @return [Boolean] the "passed" attribute value 31 | def passed? 32 | passed 33 | end 34 | 35 | # Whether and what the vote was for a given person 36 | # 37 | # @return [String] yes, no, other, or nil 38 | # returns first matching vote, as they should be unique 39 | def value_voted_by(person) 40 | %w(yes no other).each do |type| 41 | voters = read_attribute("#{type}_votes").map { |x| x["leg_id"] }.compact 42 | return type if voters.include?(person.id) 43 | end 44 | nil 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /app/services/democracy_map_governor_service.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | class DemocracyMapGovernorService 3 | def parsed_results_for_jurisdiction(abbreviation, options = {}) 4 | [governor_for(abbreviation)] 5 | end 6 | 7 | # @todo add options handling for fields requested in future 8 | # when supported 9 | def governor_for(state) 10 | result = JSON.parse(get(state)) 11 | data = parse_state_from(result["jurisdictions"]) 12 | data = data["elected_office"].select { |d| d["title"] == "Governor" }.first 13 | governor = data.merge({ "state" => state.downcase }) 14 | end 15 | 16 | private 17 | def base_url 18 | "http://api.democracymap.org/context?location=" 19 | end 20 | 21 | def get(location) 22 | wait = 1 23 | begin 24 | RestClient.get "#{base_url}#{location}", accept: :json 25 | rescue Errno::ECONNRESET, RestClient::ServerBrokeConnection 26 | wait *= 2 # exponential backoff 27 | sleep wait 28 | retry 29 | end 30 | end 31 | 32 | def parse_state_from(jurisdictions) 33 | state_matches = jurisdictions.select do |jurisdiction| 34 | jurisdiction["type"] == "government" && 35 | jurisdiction["type_name"] == "State" 36 | end 37 | state_matches.first 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /app/services/open_states_legislator_service.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require "sunlight_legislator_locator_base" 3 | 4 | # A wrapper for the Open States API. 5 | class OpenStatesLegislatorService 6 | # public interface is defined in mixin 7 | include SunlightLegislatorLocatorBase 8 | 9 | attr_accessor :key, :base_url, :legislators_url, :id_field 10 | 11 | def initialize 12 | @key = ENV['SUNLIGHT_API_KEY'] 13 | @base_url = "http://openstates.org/api/v1/" 14 | @legislators_url = "#{base_url}legislators/" 15 | @id_field = "id" 16 | end 17 | 18 | private 19 | def geo_url 20 | "#{legislators_url}geo/" 21 | end 22 | 23 | def params_for_location(data) 24 | { lat: data.latitude, 25 | long: data.longitude, 26 | apikey: key } 27 | end 28 | 29 | def format_abbreviation(abbreviation) 30 | abbreviation.downcase 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /app/services/sunlight_congress_legislator_service.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require "sunlight_legislator_locator_base" 3 | 4 | # A wrapper for the Sunlight Congress API. 5 | class SunlightCongressLegislatorService 6 | # public interface is defined in mixin 7 | include SunlightLegislatorLocatorBase 8 | 9 | attr_accessor :key, :base_url, :legislators_url, :id_field 10 | 11 | def initialize 12 | @key = ENV['SUNLIGHT_API_KEY'] 13 | @base_url = "https://congress.api.sunlightfoundation.com/" 14 | @legislators_url = "#{base_url}legislators/" 15 | @id_field = "bioguide_id" 16 | end 17 | 18 | private 19 | def api_parse(data) 20 | JSON.parse(data)['results'] 21 | end 22 | 23 | def geo_url 24 | "#{legislators_url}locate" 25 | end 26 | 27 | def params_for_location(data) 28 | { latitude: data.latitude, 29 | longitude: data.longitude, 30 | apikey: key } 31 | end 32 | 33 | def format_abbreviation(abbreviation) 34 | abbreviation.upcase 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /app/validators/user_email_matches_validator.rb: -------------------------------------------------------------------------------- 1 | class UserEmailMatchesValidator < ActiveModel::Validator 2 | def validate(record) 3 | unless record.user.email.downcase == record.person.email.downcase 4 | record.errors[:base] << "Email addresses must match" 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/views/answers/_featured.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | <% if featured.question.person.image? %> 5 | <%= cdn_image_tag(featured.question.person.image, size: "80x80", alt: "") %> 6 | <% end %> 7 |
8 |
9 | 10 | <%= link_to "Answered Question!", question_path(featured.question.state, featured.question, anchor: "answer") %> 11 | 12 | From 13 | 14 | <%= link_to "#{(featured.question.person.political_position_title || '') + ' '}#{featured.question.person.name}", 15 | person_path(featured.question.person.state, featured.question.person), 16 | anchor: "answer" %> 17 |
18 |

to "<%= featured.question.title -%>"

19 |
20 |
21 | -------------------------------------------------------------------------------- /app/views/answers/edit.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

Edit this Answer as <%= @answer.question.person.name %>

3 | <%= simple_form_for @answer, url: answer_path(@answer), html: { accept_charset: "utf-8" } do |f| %> 4 | <% @answer.errors.full_messages.each do |message| -%> 5 |

<%= message -%>

6 | <% end -%> 7 | 8 | <%= f.input :text, as: :text, label: false %> 9 | 10 |
<%= f.submit "Update", class: "cta-pill" %>
11 | <% end %> 12 |
13 | -------------------------------------------------------------------------------- /app/views/bills/_page.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
    3 | <%= render @bills %> 4 |
5 | 6 | <%= paginate @bills, outer_window: 1, params: {format: nil}, replace: '#page', scroll: 'section' %> 7 |
8 | -------------------------------------------------------------------------------- /app/views/bills/_questions.html.erb: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /app/views/bills/_sponsors.html.erb: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /app/views/bills/index.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'shared/navigation' %> 2 | 3 |
4 |
5 | Filter by:<%# @todo DM are these really the filters we're using? %> 6 | Date 7 | 8 | Recent Actions 9 | 10 | Most Viewed 11 | 12 | Key Votes 13 | 14 | 18 |
19 | 20 | <%= render partial: 'page' %> 21 |
22 | -------------------------------------------------------------------------------- /app/views/blurbs/_blurb.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | <%- if blurb.avatar_url? %> 5 | <%= cdn_image_tag(blurb.avatar_url, size: "60x60", alt: "") %> 6 | <%- end %> 7 |
8 |
9 | <%= blurb.headline -%> 10 |
11 |
12 | <%= raw(blurb.body) -%> 13 |
14 |
15 |
16 | -------------------------------------------------------------------------------- /app/views/blurbs/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= simple_form_for @blurb, html: { accept_charset: "utf-8" } do |f| %> 2 | <%= f.error_notification %> 3 | 4 | <%- if @blurb.errors.any? %> 5 |
6 | <%- @blurb.errors.full_messages.each do |message| %> 7 |

<%= message -%>

8 | <%- end %> 9 |
10 | <%- end %> 11 | 12 |
13 | <%- if @target_url %> 14 | <%= f.input :target_url, as: :hidden, input_html: { value: @target_url } %> 15 | <%- end %> 16 | <%= f.input :active, as: :radio_buttons %> 17 | <%= f.text_field :avatar_url, placeholder: raw("URL for avatar image") %> 18 | <%= f.text_area :headline, placeholder: raw("Headline"), maxlength: "100", rows: "1" %> 19 | <%= f.text_area :body, placeholder: raw("Short body, HTML allowed, but keep it simple and valid!"), rows: "1" %> 20 |
21 | 22 |
23 | <%= f.button :submit, class: "cta-pill" %> 24 |
25 | <% end %> 26 | -------------------------------------------------------------------------------- /app/views/blurbs/_managed_blurb.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 |
    3 | <%- if managed_blurb.target_url.present? %> 4 |
    <%= link_to managed_blurb.target_url, managed_blurb.target_url -%>
    5 | <%- end %> 6 | 7 | <%- if managed_blurb.active? %> 8 |
    Active
    9 | <%- end %> 10 | 11 |
    12 |
    13 | <%- if managed_blurb.avatar_url? %> 14 | <%= cdn_image_tag(managed_blurb.avatar_url, size: "60x60", alt: "") %> 15 | <%- end %> 16 |
    17 |
    <%= managed_blurb.headline %>
    18 |
    19 | <%= raw(managed_blurb.body) %> 20 |
    21 |
    22 |
    23 |
    24 | Actions: 25 |
      26 |
    • <%= link_to "Show", managed_blurb %>
    • 27 |
    • <%= link_to "Edit", edit_blurb_path(managed_blurb) %>
    • 28 |
    • <%= link_to "Destroy", managed_blurb, method: :delete, data: { confirm: "Are you sure?" } %>
    • 29 |
    30 |
    31 |
  • 32 | -------------------------------------------------------------------------------- /app/views/blurbs/edit.html.erb: -------------------------------------------------------------------------------- 1 |

    Editing blurb

    2 | 3 | <%= render "form" %> 4 | 5 |
    6 | <%= link_to "Show", @blurb %> | 7 | <%= link_to "Back", blurbs_path %> 8 |
    9 | -------------------------------------------------------------------------------- /app/views/blurbs/index.html.erb: -------------------------------------------------------------------------------- 1 |

    Blurbs

    2 | 3 | 7 | -------------------------------------------------------------------------------- /app/views/blurbs/new.html.erb: -------------------------------------------------------------------------------- 1 |

    New blurb

    2 | 3 | <%= render "form" %> 4 | 5 |
    6 | <%= link_to "Back", blurbs_path %> 7 |
    8 | -------------------------------------------------------------------------------- /app/views/blurbs/show.html.erb: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | <%- if @blurb.target_url.present? %> 4 |
    <%= link_to @blurb.target_url, @blurb.target_url -%>
    5 | <%- end %> 6 | 7 | <%- if @blurb.active? %> 8 | Active 9 | <%- end %> 10 | 11 |
    12 |
    13 | <%- if @blurb.avatar_url? %> 14 | <%= cdn_image_tag(@blurb.avatar_url, size: "60x60", alt: "") %> 15 | <%- end %> 16 |
    17 |
    <%= raw(@blurb.headline) -%>
    18 |
    19 | <%= raw(@blurb.body) %> 20 |
    21 |
    22 |
    23 |
    24 | Actions: 25 |
      26 |
    • <%= link_to "Edit", edit_blurb_path(@blurb) %>
    • 27 |
    • <%= link_to "Back", blurbs_path %>
    • 28 |
    29 |
    30 |
    31 | -------------------------------------------------------------------------------- /app/views/candidates/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= f.error_notification %> 2 | 3 |
    4 | <%= f.input :ocd_division_id, as: :hidden %> 5 | <%= f.input :current_office_holder_id, as: :hidden %> 6 | <%= f.input :state, as: :hidden, value: parent.abbreviation %> 7 | 8 | 9 | <%= f.text_field :twitter_id, placeholder: "Load from which twitter account?" %> 10 | 11 | 12 | <%= f.text_field :current_office_holder_name, placeholder: "Current office holder's name?" %> 13 | 14 | 15 | <%= f.text_field :running_for_position, placeholder: "Which office is the candidate running for?" %> 16 | 17 | 18 | <%= f.text_field :full_name, placeholder: "Full Name" %> 19 | 20 | 21 | <%= f.text_field :email, placeholder: "Email" %> 22 | 23 | 24 | <%= f.text_field :photo_url, placeholder: "URL for avatar image" %> 25 | 26 | 27 | <%= f.text_field :party, placeholder: "Party" %> 28 |
    29 | 30 |
    31 | <%= f.button :submit, class: "cta-pill" %> 32 |
    33 | -------------------------------------------------------------------------------- /app/views/candidates/_managed_candidate.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 |
    3 | <%- if managed_candidate.active? %> 4 |
    Active
    5 | <%- end %> 6 | 7 |
    8 |
    9 | <%- if managed_candidate.photo_url? %> 10 | <%= cdn_image_tag(managed_candidate.photo_url, size: "60x60", alt: "") %> 11 | <%- end %> 12 |
    13 |
    <%= managed_candidate.full_name %>
    14 |
    15 |
    16 |
    17 | Actions: 18 |
      19 | 20 |
    • <%= link_to "Edit", edit_candidate_path(parent, managed_candidate) %>
    • 21 |
    • <%= link_to "Destroy", candidate_path(parent, managed_candidate), method: :delete, data: { confirm: "Are you sure?" } %>
    • 22 |
    23 |
    24 |
  • 25 | -------------------------------------------------------------------------------- /app/views/candidates/edit.html.erb: -------------------------------------------------------------------------------- 1 |

    Editing candidate

    2 | 3 | <%= simple_form_for(@candidate, url: candidate_path(parent, @candidate)) do |f| %> 4 | <%= render partial: "form", locals: { f: f } %> 5 | <% end %> 6 | 7 |
    8 | <%= link_to "Show", candidate_path(parent, @candidate) %> | 9 | <%= link_to "Back", candidates_path(parent) %> 10 |
    11 | -------------------------------------------------------------------------------- /app/views/candidates/index.html.erb: -------------------------------------------------------------------------------- 1 |

    Candidates

    2 | 3 | 18 | -------------------------------------------------------------------------------- /app/views/candidates/new.html.erb: -------------------------------------------------------------------------------- 1 |

    New candidate

    2 | 3 | <%= simple_form_for resource do |f| %> 4 | <%= render partial: "form", locals: { f: f } %> 5 | <% end %> 6 | 7 |
    8 | <%= link_to "Back", candidates_path %> 9 |
    10 | -------------------------------------------------------------------------------- /app/views/candidates/show.html.erb: -------------------------------------------------------------------------------- 1 |

    <%= notice %>

    2 | 3 | 4 | <%= link_to 'Edit', edit_candidate_path(@candidate) %> | 5 | <%= link_to 'Back', candidates_path %> 6 | -------------------------------------------------------------------------------- /app/views/committees/_committee.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 |
    3 | <%= committee.name %> 4 |
    5 | 6 | 20 |
    21 |
  • 22 | -------------------------------------------------------------------------------- /app/views/devise/passwords/edit.html.erb: -------------------------------------------------------------------------------- 1 |

    Change your password

    2 | 3 | <%= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: {method: :put, id: 'edit_password'}) do |f| %> 4 | <%= devise_error_messages! %> 5 | <%= f.input :reset_password_token, as: :hidden %> 6 | <%= f.input :password %> 7 | <%= f.button :submit, 'Change my password' %> 8 | <% end %> 9 | 10 | <%= render 'devise/shared/links' %> 11 | -------------------------------------------------------------------------------- /app/views/devise/passwords/new.html.erb: -------------------------------------------------------------------------------- 1 |
    2 |

    Forgot your password?

    3 | 12 |
    13 | -------------------------------------------------------------------------------- /app/views/devise/sessions/new.html.erb: -------------------------------------------------------------------------------- 1 |
    2 |

    Sign in

    3 |
    4 | 5 | <%= simple_form_for(resource, as: resource_name, url: session_path(resource_name), html: {id: 'new_session'}) do |f| %> 6 | 7 |
    8 |
    9 |
    10 | <%= f.input :email, placeholder: 'jon@doe.com', label: 'email', required: false %> 11 |
    12 |
    13 | <%= f.input :password %> 14 |
    15 |
    16 |
    17 | 18 |
    19 | <%= f.input :remember_me, as: :hidden, input_html: {value: 1} %> 20 | <%= f.button :submit, 'Sign in', :class => 'cta-pill' %> 21 | <%= render 'devise/shared/links' %> 22 |
    23 | 24 | <% end %> 25 | -------------------------------------------------------------------------------- /app/views/devise/shared/_links.erb: -------------------------------------------------------------------------------- 1 |
      2 | <% if controller_name != 'sessions' %> 3 |
    • 4 | <%= link_to 'Sign in', new_session_path(resource_name) %> 5 |
    • 6 | <% end %> 7 | <% if devise_mapping.registerable? && controller_name != 'registrations' %> 8 |
    • 9 | <%= link_to 'Sign up', new_registration_path(resource_name) %> 10 |
    • 11 | <% end %> 12 | <% if devise_mapping.recoverable? && controller_name != 'passwords' %> 13 |
    • 14 | <%= link_to 'Forgot your password?', new_password_path(resource_name) %> 15 |
    • 16 | <% end %> 17 | <% if devise_mapping.omniauthable? %> 18 |
    • 19 | <% resource_class.omniauth_providers.each do |provider| %> 20 | <%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %> 21 | <% end %> 22 |
    • 23 | <% end %> 24 |
    -------------------------------------------------------------------------------- /app/views/identity_mailer/identity_needs_inspection.text.erb: -------------------------------------------------------------------------------- 1 | <%= @user.given_name -%> <%= @user.family_name -%> identity needs inspection. 2 | 3 | You can review details and verify or reject the identity here: 4 | 5 | <%= user_url(@user) -%> 6 | 7 | Thank you, 8 | The AskThem Team -------------------------------------------------------------------------------- /app/views/identity_mailer/identity_rejected.text.erb: -------------------------------------------------------------------------------- 1 | Thank you for requesting your account for verification by AskThem, <%= @user.given_name %> 2 | 3 | Unfortunately we could not verify your identity at this time. 4 | 5 | Thank you, 6 | The AskThem Team -------------------------------------------------------------------------------- /app/views/identity_mailer/identity_submitted.text.erb: -------------------------------------------------------------------------------- 1 | Thank you for requesting your account for verification by AskThem, <%= @user.given_name %> 2 | 3 | An AskThem staff member will review your request and get back to you. 4 | 5 | Thank you, 6 | The AskThem Team -------------------------------------------------------------------------------- /app/views/identity_mailer/identity_verified.text.erb: -------------------------------------------------------------------------------- 1 | Thank you for requesting your account for verification by AskThem, <%= @user.given_name %> 2 | 3 | An AskThem staff member has verified your identity. You can now answer questions from the following URL: 4 | 5 | <%= person_url(@person.state, @person.id) -%> 6 | 7 | Thank you, 8 | The AskThem Team -------------------------------------------------------------------------------- /app/views/kaminari/_first_page.html.erb: -------------------------------------------------------------------------------- 1 | <%# Link to the "First" page 2 | - available local variables 3 | url: url to the first page 4 | current_page: a page object for the currently displayed page 5 | total_pages: total number of pages 6 | per_page: number of items to fetch per page 7 | remote: data-remote 8 | -%> 9 | -------------------------------------------------------------------------------- /app/views/kaminari/_gap.html.erb: -------------------------------------------------------------------------------- 1 | <%# Non-link tag that stands for skipped pages... 2 | - available local variables 3 | current_page: a page object for the currently displayed page 4 | total_pages: total number of pages 5 | per_page: number of items to fetch per page 6 | remote: data-remote 7 | -%> 8 | <%= raw(t 'views.pagination.truncate') %> 9 | -------------------------------------------------------------------------------- /app/views/kaminari/_last_page.html.erb: -------------------------------------------------------------------------------- 1 | <%# Link to the "Last" page 2 | - available local variables 3 | url: url to the last page 4 | current_page: a page object for the currently displayed page 5 | total_pages: total number of pages 6 | per_page: number of items to fetch per page 7 | remote: data-remote 8 | -%> 9 | -------------------------------------------------------------------------------- /app/views/kaminari/_next_page.html.erb: -------------------------------------------------------------------------------- 1 | <%# Link to the "Next" page 2 | - available local variables 3 | url: url to the next page 4 | current_page: a page object for the currently displayed page 5 | total_pages: total number of pages 6 | per_page: number of items to fetch per page 7 | remote: data-remote 8 | -%> 9 | 10 | <%= link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, { 11 | 'rel' => 'next', 12 | 'remote' => remote, 13 | 'data-title' => title(page: current_page + 1), 14 | } %> 15 | 16 | -------------------------------------------------------------------------------- /app/views/kaminari/_page.html.erb: -------------------------------------------------------------------------------- 1 | <%# Link showing page number 2 | - available local variables 3 | page: a page object for "this" page 4 | url: url to this page 5 | current_page: a page object for the currently displayed page 6 | total_pages: total number of pages 7 | per_page: number of items to fetch per page 8 | remote: data-remote 9 | -%> 10 | 11 | <%= link_to_unless page.current?, page, url, { 12 | 'remote' => remote, 13 | 'rel' => page.next? ? 'next' : page.prev? ? 'prev' : nil, 14 | 'data-title' => title(page: page.number), 15 | } %> 16 | 17 | -------------------------------------------------------------------------------- /app/views/kaminari/_paginator.html.erb: -------------------------------------------------------------------------------- 1 | <%# The container tag 2 | - available local variables 3 | current_page: a page object for the currently displayed page 4 | total_pages: total number of pages 5 | per_page: number of items to fetch per page 6 | remote: data-remote 7 | paginator: the paginator that renders the pagination tags inside 8 | -%> 9 | <%= paginator.render do -%> 10 | 23 | <% end -%> 24 | -------------------------------------------------------------------------------- /app/views/kaminari/_prev_page.html.erb: -------------------------------------------------------------------------------- 1 | <%# Link to the "Previous" page 2 | - available local variables 3 | url: url to the previous page 4 | current_page: a page object for the currently displayed page 5 | total_pages: total number of pages 6 | per_page: number of items to fetch per page 7 | remote: data-remote 8 | -%> 9 | 10 | <%= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, { 11 | 'rel' => 'prev', 12 | 'remote' => remote, 13 | 'data-title' => title(page: current_page - 1), 14 | } %> 15 | 16 | -------------------------------------------------------------------------------- /app/views/key_votes/_key_vote.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 | @todo KeyVote 3 |
  • -------------------------------------------------------------------------------- /app/views/layouts/maintenance.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Maintenance 5 | 35 | 36 | 37 |
    38 |

    Maintenance

    39 |

    The system is down for <%= reason ? reason : "maintenance" %> as of <%= Time.now.strftime("%H:%M %Z") %>.

    40 |

    It'll be back <%= deadline ? deadline : "shortly" %>.

    41 | 42 |
    43 | 44 | 45 | -------------------------------------------------------------------------------- /app/views/meetings/_meeting.html.erb: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 4 | 8 | 9 |
    10 |
    <%= meeting.name %>
    11 |
    12 | <% if meeting.agenda %> 13 | <%= link_to 'Download', meeting.agenda.url, class: 'meeting-agenda-download' %> 14 | <% else %> 15 | - 16 | <% end %> 17 |
    18 |
    19 | <% if meeting.minutes_document %> 20 | <%= link_to 'Minutes', meeting.minutes_document.url %> 21 | <% else %> 22 | - 23 | <% end %> 24 |
    25 |
    26 | -------------------------------------------------------------------------------- /app/views/pages/_bills.html.erb: -------------------------------------------------------------------------------- 1 |
    2 |
      3 | <%= render @bills %> 4 |
    5 | 6 | <%= paginate @bills, outer_window: 1, params: {format: nil}, replace: '#page', scroll: '.nav_extras' %> 7 |
    8 | -------------------------------------------------------------------------------- /app/views/pages/_key_votes.html.erb: -------------------------------------------------------------------------------- 1 |
    2 |
      3 | <%= render @key_votes %> 4 |
    5 | 6 | <%= paginate @key_votes, outer_window: 1, params: {format: nil}, replace: '#page', scroll: '.nav_extras' %> 7 |
    8 | -------------------------------------------------------------------------------- /app/views/pages/_lower.html.erb: -------------------------------------------------------------------------------- 1 |
    2 |
      3 | <%= render @lower %> 4 |
    5 | 6 | <%= paginate @lower, outer_window: 1, params: {format: nil}, replace: '#page', scroll: '.nav_extras' %> 7 |
    8 | -------------------------------------------------------------------------------- /app/views/pages/_meetings.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | <% if @meetings.length > 0 %> 3 |
    4 |
    5 |

    Date

    6 |

    Name

    7 |

    Agenda

    8 |

    Minutes

    9 |
    10 | <%= render @meetings %> 11 |
    12 | <%= paginate @meetings, outer_window: 1, params: {format: nil}, replace: '#page', scroll: '.nav_extras' %> 13 | <% else %> 14 |

    No meetings found

    15 | <% end %> 16 |
    17 | -------------------------------------------------------------------------------- /app/views/pages/_people_for_location.html.erb: -------------------------------------------------------------------------------- 1 | 19 |   20 |
      21 | <%= render federal_people if federal_people %> 22 |
    23 | 27 | 31 | -------------------------------------------------------------------------------- /app/views/pages/_upper.html.erb: -------------------------------------------------------------------------------- 1 |
    2 |
      3 | <%# spell out arguments for subclasses of Person sake -%> 4 | <%= render partial: 'people/person', collection: @upper %> 5 |
    6 | 7 | <%= paginate @upper, outer_window: 1, params: {format: nil}, replace: '#page', scroll: '.nav_extras' %> 8 |
    9 | -------------------------------------------------------------------------------- /app/views/pages/channel.html.erb: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/views/pages/contact_info.csv.erb: -------------------------------------------------------------------------------- 1 | <%- headers = ["Jurisdiction", "Id", "Name", "Title and Details", "Email", "Phone", "Office Details", "Twitter", "Facebook", "Youtube", "Links"] -%> 2 | <%= CSV.generate_line headers %> 3 | <%- @people.each do |person| -%> 4 | <%- row = [person.metadatum.abbreviation, 5 | person.id, 6 | person.full_name, 7 | person_attributes(person, " - "), 8 | person.email.present? ? person.email : nil, 9 | person.read_attribute(:phone), 10 | csv_safe_office_details_for(person), 11 | person.read_attribute(:twitter_id), 12 | person.read_attribute(:facebook_id), 13 | person.read_attribute(:youtube_id), 14 | csv_safe_links_for(person)] -%> 15 | <%= CSV.generate_line row %> 16 | <%- end -%> 17 | -------------------------------------------------------------------------------- /app/views/pages/elected_signup.html.erb: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/views/pages/honestads.html.erb: -------------------------------------------------------------------------------- 1 |
    2 |

    HonestAds and AskThem

    3 | 20 |
    21 | -------------------------------------------------------------------------------- /app/views/pages/overview.js.erb: -------------------------------------------------------------------------------- 1 | <%= j render(@tab) %> -------------------------------------------------------------------------------- /app/views/pages/search.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | @todo: Bill, etc. search results 3 |
    -------------------------------------------------------------------------------- /app/views/pages/widget_builder.html.erb: -------------------------------------------------------------------------------- 1 |
    2 |

    AskThem Widget Builder

    3 | 9 | 10 |

    Note - advanced users can override the built-in styles of the widgets. If you have the know how, go for it!

    11 | 12 |
    13 | -------------------------------------------------------------------------------- /app/views/people/_bills.html.erb: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /app/views/people/_committees.html.erb: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /app/views/people/_questions.html.erb: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /app/views/people/_ratings.html.erb: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /app/views/people/_votes.html.erb: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /app/views/person_mailer/notify_staff_bad_person.text.erb: -------------------------------------------------------------------------------- 1 | Bad Person - There's something wrong with <%= @cached_official.full_name -%> 2 | 3 | We couldn't find a person that matches these details: 4 | 5 | 6 | <%= @cached_official.attributes %> 7 | 8 | 9 | Typical causes for non-match are use of a nickname or middle name rather than the official name we have for the official. 10 | 11 | If you have a link to who, in our data, should match this person, please pass it on to a developer so they can manually match this person. 12 | 13 | Thank you, 14 | The AskThem Team 15 | -------------------------------------------------------------------------------- /app/views/person_mailer/notify_staff_new_from_twitter.text.erb: -------------------------------------------------------------------------------- 1 | A person has been added to AskThem with the Twitter screen name <%= @screen_name %>. 2 | 3 | If no one has asked this person a question in 24 hours, they will be automatically deleted from the site. 4 | 5 | Here's a permalink to that person: <%= person_url(@person.state, @person.id) %> 6 | 7 | Thank you, 8 | The AskThem Team 9 | -------------------------------------------------------------------------------- /app/views/question_mailer/answered_for_author.text.erb: -------------------------------------------------------------------------------- 1 | Hi <%= @user.given_name -%>! 2 | 3 | Exciting News! We wanted to let you know that <%= @question.person.name -%> has replied to the question you submitted: 4 | 5 | <%= @question.title %> 6 | 7 | <%= question_url(@question.state, @question.id) %> 8 | 9 | Click above for the full response! 10 | 11 | Congratulations on the success of your question! We'll notify everyone that signed on and share your question-and-answer on our social media channels. 12 | 13 | Forward this email to friends or click on the question above and share on Facebook. 14 | 15 | Thank you, 16 | The AskThem Team 17 | -------------------------------------------------------------------------------- /app/views/question_mailer/answered_for_signer.text.erb: -------------------------------------------------------------------------------- 1 | Hi <%= @user.given_name -%>! 2 | 3 | Exciting news- we've received an answer to the question for <%= @question.person.name -%>: 4 | 5 | <%= @question.title %> 6 | 7 | <%= question_url(@question.state, @question.id) %> 8 | 9 | Click above for the full response! 10 | 11 | Thanks for signing on! 12 | 13 | Forward this email to friends or click on the question above and share on Facebook. 14 | 15 | Thank you, 16 | The AskThem Team 17 | -------------------------------------------------------------------------------- /app/views/question_mailer/email_person.text.erb: -------------------------------------------------------------------------------- 1 | A question asked of you by people on AskThem has reached <%= @question.signature_count %> signatures. 2 | 3 | Title 4 | <%= @question.title %> 5 | 6 | Topic 7 | <%= @question.subject %> 8 | 9 | Body 10 | <%= @question.body %> 11 | 12 | Here's a permalink to that question: <%= question_url(@question.state, @question.id) %> 13 | 14 | Thank you, 15 | The AskThem.io Team 16 | -------------------------------------------------------------------------------- /app/views/question_mailer/notify_staff_members_answered.text.erb: -------------------------------------------------------------------------------- 1 | Hi, 2 | 3 | A question to <%= @question.person.name -%> has been answered. 4 | 5 | <%= @question.title %> 6 | 7 | <%= question_url(@question.state, @question.id) %> 8 | 9 | Thank you, 10 | The AskThem Team 11 | -------------------------------------------------------------------------------- /app/views/question_mailer/notify_staff_question_at_threshold.text.erb: -------------------------------------------------------------------------------- 1 | A question has reached its delivery goal of <%= @question.signature_count %> signatures. 2 | 3 | Title 4 | <%= @question.title %> 5 | 6 | Topic 7 | <%= @question.subject %> 8 | 9 | Body 10 | <%= @question.body %> 11 | 12 | Here's a permalink to that question: <%= question_url(@question.state, @question.id) %> 13 | 14 | Thank you, 15 | The AskThem Team 16 | -------------------------------------------------------------------------------- /app/views/questions/_media.html.erb: -------------------------------------------------------------------------------- 1 | <%- if question.media_file_url.present? %> 2 | <%= question.media_file_url_html %> 3 | <%- end %> 4 | <%- if question.media.url.present? %> 5 | <%- if is_image?(question.media.url) %> 6 | <%= cdn_image_tag(question.media.url, class: "question-image") %> 7 | <%- else %> 8 | 9 | <%= cdn_video_tag(question.media.url, class: "question-video", controls: true) %> 10 | <%- end %> 11 | <%- end %> 12 | -------------------------------------------------------------------------------- /app/views/questions/_page.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | <% if @questions.any? -%> 3 |
      4 | <%= render @questions %> 5 |
    6 | <%= paginate @questions, outer_window: 1, params: { format: nil }, replace: "#page", scroll: "section" %> 7 | <% elsif !%w(need_answers have_answers need_signatures).include?(params[:action]) %> 8 |
    9 |

    Nobody has asked any questions yet!

    10 |

    Do you want to get the ball rolling?

    11 | <%= link_to "Ask a Question", new_question_path(@jurisdiction.abbreviation), class: "cta-pill" %> 12 |
    13 | <% end -%> 14 |
    15 | -------------------------------------------------------------------------------- /app/views/questions/edit.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | <%= form_for @question, url: question_path(@state_code, @question), validate: true, html: { accept_charset: "utf-8" } do |f| %> 3 | <% @question.errors.full_messages.each do |message| -%> 4 |

    <%= message -%>

    5 | <% end -%> 6 | 7 | <% locals = { jurisdiction: @jurisdiction, question: @question, person: @person, bill: @bill, relevant_steps: @relevant_steps, f: f } -%> 8 | 9 | <%= render partial: "content_step", locals: locals.merge({ step: "content" }) %> 10 | 11 |
    <%= f.submit "Update", class: "cta-pill" %>
    12 | <% end %> 13 |
    14 | -------------------------------------------------------------------------------- /app/views/ratings/_rating.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 | <%= rating.sentence(@person, @jurisdiction) %> 3 |
  • 4 | -------------------------------------------------------------------------------- /app/views/robots/show.text.erb: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | <%- @disallows.each do |disallow| %> 3 | Disallow: <%= disallow %> 4 | <%- end %> 5 | -------------------------------------------------------------------------------- /app/views/shared/_accept_terms.html.erb: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /app/views/shared/_banner.html.erb: -------------------------------------------------------------------------------- 1 | <%- if ENV["BANNER_HTML"].present? && session[:banner_viewed].blank? -%> 2 | 10 | <% session[:banner_viewed] = true %> 11 | <%- end %> 12 | -------------------------------------------------------------------------------- /app/views/shared/_chartbeat.html.erb: -------------------------------------------------------------------------------- 1 | <% if Rails.env.production? && ENV["CHARTBEAT_HOSTNAME"].present? -%> 2 | 18 | <% end -%> 19 | -------------------------------------------------------------------------------- /app/views/shared/_facebook_connect.html.erb: -------------------------------------------------------------------------------- 1 | <%- if ENV["FACEBOOK_APP_ID"].present? -%> 2 | 21 | <%- end %> 22 | -------------------------------------------------------------------------------- /app/views/shared/_google_analytics.html.erb: -------------------------------------------------------------------------------- 1 | <% if Rails.env.production? && ENV["GOOGLE_ANALYTICS_APP_ID"].present? -%> 2 | 12 | <% end -%> 13 | -------------------------------------------------------------------------------- /app/views/shared/_no_questions.html.erb: -------------------------------------------------------------------------------- 1 |
    2 |

    Ask one of the first questions in your area!

    3 | <%= generic_ask_question "Ask your own Question", class: "cta-pill" %> 4 |
    5 | -------------------------------------------------------------------------------- /app/views/shared/_optimizely.html.erb: -------------------------------------------------------------------------------- 1 | <%- if Rails.env.production? && ENV["OPTIMIZELY_FILENAME"].present? -%> 2 | 3 | <%- end %> 4 | -------------------------------------------------------------------------------- /app/views/shared/_partner_return_to.html.erb: -------------------------------------------------------------------------------- 1 | <%- info = session[:referring_partner_info] %> 2 | <%- if info && info[:name].present? %> 3 | <%- target_url = info[:return_url] || info[:url] %> 4 | <%- link_content = info[:name] %> 5 | <%- if info[:logo] %> 6 | <%- link_content = raw("\"#{info[:name]}\"") %> 7 | <%- end %> 8 | 9 |
    10 |
    return to
    <%= raw("#{link_content}") -%> 11 |
    12 | <%- end %> 13 | -------------------------------------------------------------------------------- /app/views/shared/_user.html.erb: -------------------------------------------------------------------------------- 1 | <% if user_signed_in? %> 2 |
  • <%= link_to "My Questions", user_path(current_user) %>
  • 3 |
  • <%= link_to "Settings", edit_user_registration_path %>
  • 4 |
  • <%= link_to "Sign out", destroy_user_session_path %>
  • 5 | <% if false %> 6 |
  • 7 | <%= link_to "#" do %><%# @todo ST make dropdown appear %> 8 | <%= current_user.alternate_name %> 9 | <% end %> 10 |
  • 11 | <% end %> 12 | <% else %> 13 |
  • <%= link_to "Sign up", new_user_registration_path %>
  • 14 |
  • <%= link_to "Login", new_user_session_path %>
  • 15 |
  • <%= link_to("Login with Facebook", 16 | user_omniauth_authorize_url(:facebook, 17 | protocol: Rails.env.production? ? "https://" : "http://"), 18 | class: "facebook-login") -%>
  • 19 | <% end %> 20 | -------------------------------------------------------------------------------- /app/views/signatures/_as_signer.html.erb: -------------------------------------------------------------------------------- 1 | <%- signature, signer = as_signer, as_signer.user %> 2 | 3 |

    4 | <%= link_to signers_description(signer), signer %> 5 | <%= distance_of_time_in_words_to_now(signature.created_at) %> ago 6 |

    7 | -------------------------------------------------------------------------------- /app/views/signatures/index.csv.erb: -------------------------------------------------------------------------------- 1 | <%- headers = ["First Name", "Last Name", "Email", "Zipcode"] -%> 2 | <%= CSV.generate_line headers -%> 3 | <%- @signers.each do |user| -%> 4 | <%- row = [user.given_name, user.family_name, user.email, user.postal_code] -%> 5 | <%= CSV.generate_line row -%> 6 | <%- end -%> 7 | -------------------------------------------------------------------------------- /app/views/subjects/_page.html.erb: -------------------------------------------------------------------------------- 1 |
    2 |
      3 | <%= render @bills %> 4 |
    5 | 6 | <%= paginate @bills, outer_window: 1, params: {format: nil}, replace: '#page', scroll: 'section' %> 7 |
    8 | -------------------------------------------------------------------------------- /app/views/subjects/index.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'shared/navigation' %> 2 | 3 |
    4 |
    5 |

    Issue Areas

    6 |
    7 | 8 |
      9 | <% @subjects.each do |subject| %> 10 |
    • 11 | <%= link_to subject, subject_path(@jurisdiction.abbreviation, subject.parameterize) %> 12 |
    • 13 | <% end %> 14 |
    15 |
    16 | -------------------------------------------------------------------------------- /app/views/subjects/show.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'shared/navigation' %> 2 | 3 |
    4 |
    5 |

    <%= @subject %>

    6 |
    7 | 8 | <%= render partial: 'page' %> 9 |
    10 | -------------------------------------------------------------------------------- /app/views/unknown/_unknown.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 |
    3 | <%= image_tag('placeholder.png', size: '60x60', alt: '') %> 4 |
    5 |
    6 |

    <%= unknown.name %>

    7 |
    8 |
  • 9 | -------------------------------------------------------------------------------- /app/views/users/_questions.html.erb: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /app/views/users/_signatures.html.erb: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /app/views/votes/_vote.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 | @todo https://github.com/sunlightlabs/billy/wiki/Votes-fields 3 |
  • 4 | -------------------------------------------------------------------------------- /app/workers/geocode_worker.rb: -------------------------------------------------------------------------------- 1 | class GeocodeWorker 2 | include Sidekiq::Worker 3 | 4 | def perform(id, class_name = "User") 5 | object = class_name.constantize.find(id) 6 | object.geocode 7 | object.save! if object.changed? 8 | rescue Mongoid::Errors::DocumentNotFound 9 | logger.info "#{class_name} : #{id} appears to have been deleted" 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/workers/person_check_photo_url_worker.rb: -------------------------------------------------------------------------------- 1 | class PersonCheckPhotoUrlWorker 2 | include Sidekiq::Worker 3 | 4 | attr_accessor :person 5 | 6 | def perform(id) 7 | self.person = Person.find(id.to_s) 8 | return unless person.photo_url.present? 9 | 10 | unless ImageLinkChecker.new(person.photo_url).accessible? 11 | person.archive_photo_url 12 | end 13 | 14 | rescue Mongoid::Errors::DocumentNotFound 15 | logger.info "Person: #{id} appears to have been deleted" 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/workers/question_answered_notifier_worker.rb: -------------------------------------------------------------------------------- 1 | class QuestionAnsweredNotifierWorker 2 | include Sidekiq::Worker 3 | 4 | attr_accessor :question 5 | 6 | def perform(id) 7 | self.question = Question.find(id) 8 | return unless question.answered? 9 | 10 | notify_everyone_interested 11 | rescue Mongoid::Errors::DocumentNotFound 12 | logger.info "Question: #{id} appears to have been deleted" 13 | end 14 | 15 | private 16 | def notify_everyone_interested 17 | # QuestionMailer.answered_for_author(question.user, question).deliver 18 | 19 | # question.signatures.collect(&:user).each do |user| 20 | # unless user = question.user 21 | # QuestionMailer.answered_for_signer(user, question).deliver 22 | # end 23 | # end 24 | 25 | QuestionMailer.notify_staff_members_answered(question).deliver 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app/workers/question_coordinates_worker.rb: -------------------------------------------------------------------------------- 1 | class QuestionCoordinatesWorker 2 | include Sidekiq::Worker 3 | 4 | # user may not have coordinates yet, try until they do 5 | def perform(id) 6 | question = Question.find(id) 7 | user = question.user 8 | 9 | if user && question.coordinates.blank? 10 | if user.coordinates.present? 11 | question.coordinates = user.coordinates 12 | question.save! 13 | else 14 | self.class.perform_in(10.minutes, id) 15 | end 16 | end 17 | 18 | rescue Mongoid::Errors::DocumentNotFound 19 | logger.info "Question: #{id} appears to have been deleted" 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/workers/unaffiliated_person_tidy_worker.rb: -------------------------------------------------------------------------------- 1 | class UnaffiliatedPersonTidyWorker 2 | include Sidekiq::Worker 3 | 4 | # tidy up unaffiliated people that don't have questions 5 | # meant to be scheduled at a given period after they are created 6 | def perform(id) 7 | person = Person.find(id) 8 | return if person.questions.any? || 9 | person.state != Metadatum::Unaffiliated::ABBREVIATION 10 | 11 | person.person_detail.destroy 12 | person.destroy 13 | 14 | rescue Mongoid::Errors::DocumentNotFound 15 | logger.info "Person: #{id} appears to have been deleted" 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/workers/user_set_local_jurisdiction_abbreviation_worker.rb: -------------------------------------------------------------------------------- 1 | class UserSetLocalJurisdictionAbbreviationWorker 2 | include Sidekiq::Worker 3 | 4 | attr_accessor :user 5 | 6 | def perform(id) 7 | user = User.find(id.to_s) 8 | options = set_options_from(user) 9 | 10 | return if options[:state].nil? 11 | 12 | user.local_jurisdiction_abbreviation = JurisdictionId.new(options).id 13 | user.save! 14 | 15 | rescue Mongoid::Errors::DocumentNotFound 16 | logger.info "User: #{id} appears to have been deleted" 17 | end 18 | 19 | private 20 | def set_options_from(user) 21 | state = user.region 22 | municipality = user.locality 23 | 24 | if user.coordinates && (state.blank? || municipality.blank?) 25 | geo = Geocoder.search(user.coordinates.reverse).first 26 | state = geo.state_code 27 | municipality = geo.city 28 | end 29 | 30 | { state: state, municipality: municipality } 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /app/workers/user_set_password_notice_worker.rb: -------------------------------------------------------------------------------- 1 | class UserSetPasswordNoticeWorker 2 | include Sidekiq::Worker 3 | 4 | attr_accessor :user 5 | 6 | def perform(id) 7 | self.user = User.find(id.to_s) 8 | 9 | if user.password_is_placeholder? && !user.email_is_disabled? 10 | notify_or_reschedule 11 | end 12 | 13 | rescue Mongoid::Errors::DocumentNotFound 14 | logger.info "User: #{id} appears to have been deleted" 15 | end 16 | 17 | private 18 | def notify_or_reschedule 19 | if !user.class.devise_modules.include?(:confirmable) || user.confirmed? 20 | user.send_reset_password_instructions 21 | user.password_is_placeholder = false 22 | user.save! 23 | else 24 | self.class.perform_in(60.minutes, user.id.to_s) 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run OpenGovernment::Application 5 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 5 | 6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 7 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | OpenGovernment::Application.initialize! 6 | -------------------------------------------------------------------------------- /config/initializers/airbrake.rb: -------------------------------------------------------------------------------- 1 | if ENV['AIRBRAKE_API_KEY'] 2 | Airbrake.configure do |config| 3 | config.api_key = ENV['AIRBRAKE_API_KEY'] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /config/initializers/carrierwave.rb: -------------------------------------------------------------------------------- 1 | CarrierWave.configure do |config| 2 | # To serve uploads in development, we must store files in the "public" directory. 3 | config.root = Rails.root.join(Rails.env.production? ? 'tmp' : 'public') 4 | config.cache_dir = 'uploads' 5 | if Rails.env.production? 6 | config.fog_credentials = { 7 | :provider => 'AWS', 8 | :aws_access_key_id => ENV['AWS_ACCESS_KEY_ID'], 9 | :aws_secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'], 10 | } 11 | config.fog_directory = ENV['AWS_DIRECTORY'] 12 | config.asset_host = "//#{ENV['AWS_DIRECTORY']}#{ENV['AWS_HOST_STUB']}" 13 | config.storage = :fog 14 | else 15 | config.storage = :file 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /config/initializers/client_side_validations.rb: -------------------------------------------------------------------------------- 1 | # ClientSideValidations Initializer 2 | 3 | # Uncomment to disable uniqueness validator, possible security issue 4 | # ClientSideValidations::Config.disabled_validators = [:uniqueness] 5 | 6 | # Uncomment to validate number format with current I18n locale 7 | # ClientSideValidations::Config.number_format_with_locale = true 8 | 9 | # Uncomment the following block if you want each input field to have the validation messages attached. 10 | ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| 11 | unless html_tag =~ /^