├── log └── .keep ├── app ├── mailers │ ├── .keep │ ├── application_mailer.rb │ └── alert_mailer.rb ├── models │ ├── .keep │ ├── concerns │ │ └── .keep │ ├── office.rb │ ├── bill.rb │ ├── application_record.rb │ ├── watch.rb │ ├── electorate.rb │ └── api_statistic.rb ├── assets │ ├── images │ │ ├── .keep │ │ ├── op-logo.png │ │ ├── ua-logo.png │ │ ├── civio-logo.png │ │ ├── crta-logo.png │ │ ├── data-logo.png │ │ ├── efa-logo.png │ │ ├── pmg-logo.png │ │ ├── mysociety-logo.png │ │ ├── open-forum-logo.png │ │ ├── open-north-logo.png │ │ ├── openpolis-logo.png │ │ ├── avatars │ │ │ ├── emmaaargh.jpg │ │ │ ├── hey_maze.jpg │ │ │ ├── sarah_wilson.jpg │ │ │ ├── daniel_ferguson.jpg │ │ │ └── alice_in_covid_land.jpg │ │ ├── regards-citoyens-logo.png │ │ ├── tvfy_general_social_card.png │ │ ├── theyvoteforyou_logo_200x200.jpg │ │ ├── theyvoteforyou_logo_600x600.jpg │ │ ├── check-green.svg │ │ ├── cross-red.svg │ │ └── generic-person.svg │ ├── javascripts │ │ ├── global.js │ │ ├── bootstrap.js │ │ ├── swag.js │ │ ├── policies.js │ │ ├── divisions.js │ │ └── application.js │ ├── stylesheets │ │ ├── global │ │ │ ├── _footer.scss │ │ │ ├── _history-list.scss │ │ │ ├── _tables.scss │ │ │ ├── _alerts.scss │ │ │ ├── _banners.scss │ │ │ ├── _history-notice.scss │ │ │ ├── _utilities.scss │ │ │ ├── _swag.scss │ │ │ ├── _social-share.scss │ │ │ └── _variables.scss │ │ ├── policies │ │ │ ├── _policies-new.scss │ │ │ ├── _policies.scss │ │ │ └── _policies-list.scss │ │ ├── members │ │ │ ├── _members.scss │ │ │ └── _member-list-compact.scss │ │ ├── divisions │ │ │ ├── _divisions.scss │ │ │ ├── _division-motion.scss │ │ │ └── _division-show.scss │ │ ├── people_distances │ │ │ └── _people_distances.scss │ │ └── users │ │ │ └── _welcome.scss │ └── config │ │ └── manifest.js ├── lib │ ├── assets │ │ └── .keep │ ├── house.rb │ ├── check_resource_exists.rb │ ├── templates │ │ └── erb │ │ │ └── scaffold │ │ │ └── _form.html.erb │ ├── data_loader │ │ └── debates_xml.rb │ ├── party.rb │ └── card_screenshotter │ │ └── policies.rb ├── controllers │ ├── concerns │ │ └── .keep │ ├── help_controller.rb │ ├── registrations_controller.rb │ ├── api │ │ └── v1 │ │ │ ├── policies_controller.rb │ │ │ ├── people_controller.rb │ │ │ ├── divisions_controller.rb │ │ │ └── application_controller.rb │ ├── users_controller.rb │ ├── admin │ │ └── application_controller.rb │ └── confirmations_controller.rb ├── helpers │ ├── help_helper.rb │ ├── home_helper.rb │ ├── people_helper.rb │ ├── electorates_helper.rb │ ├── api │ │ └── v1 │ │ │ ├── people_helper.rb │ │ │ ├── policies_helper.rb │ │ │ └── divisions_helper.rb │ ├── card_helper.rb │ ├── users_helper.rb │ └── votes_helper.rb ├── views │ ├── api │ │ └── v1 │ │ │ ├── offices │ │ │ └── _office.json.jbuilder │ │ │ ├── people │ │ │ ├── index.json.jbuilder │ │ │ ├── _person.json.jbuilder │ │ │ ├── _docs_index.md │ │ │ └── show.json.jbuilder │ │ │ ├── policies │ │ │ ├── index.json.jbuilder │ │ │ ├── _policy.json.jbuilder │ │ │ └── show.json.jbuilder │ │ │ ├── divisions │ │ │ ├── index.json.jbuilder │ │ │ ├── _division.json.jbuilder │ │ │ └── show.json.jbuilder │ │ │ ├── bills │ │ │ └── _bill.json.jbuilder │ │ │ ├── votes │ │ │ └── _vote.json.jbuilder │ │ │ └── members │ │ │ └── _member.json.jbuilder │ ├── help │ │ ├── faq │ │ │ ├── _rebellion.md │ │ │ ├── _summaries.md │ │ │ ├── _division.md │ │ │ ├── _decisions.md │ │ │ ├── _policies_license.md │ │ │ └── _rebel.md │ │ ├── style_guide.html.haml │ │ └── research.html.haml │ ├── alert_mailer │ │ ├── _policy_updated_subject.text.erb │ │ ├── policy_updated.text.erb │ │ └── policy_updated.html.haml │ ├── home │ │ ├── error500.html.haml │ │ ├── error404.html.haml │ │ ├── _panel1.md │ │ ├── _panel3.md │ │ ├── _panel2.md │ │ ├── _policies.html.haml │ │ ├── about.html.haml │ │ ├── _search_form.html.haml │ │ ├── history.html.haml │ │ └── _no_search_results.html.haml │ ├── people_distances │ │ ├── _comparison_all_same.html.haml │ │ ├── _comparison_all_different.html.haml │ │ ├── _comparison_different_and_same.html.haml │ │ ├── _policies_intro.html.haml │ │ ├── _comparison_block.html.haml │ │ ├── _member.html.haml │ │ ├── _summary_vote_numbers.html.haml │ │ └── _divisions_same.html.haml │ ├── policies │ │ ├── how_the_number_is_calculated │ │ │ ├── _cells.html.haml │ │ │ └── _not_enough.html.haml │ │ ├── _draft_warning.html.haml │ │ ├── _division_edit_instructions.html.haml │ │ ├── _not_a_crystal_ball_warning.html.haml │ │ ├── _new_policy_outro.md │ │ ├── _how_the_number_is_calculated.html.haml │ │ ├── history.html.haml │ │ ├── _policy.html.haml │ │ └── _vote_summary_table.html.haml │ ├── members │ │ ├── _interesting_votes.html.haml │ │ ├── friends.html.haml │ │ ├── member_not_found.html.haml │ │ ├── _recent_votes.html.haml │ │ ├── _summary.html.haml │ │ ├── _policy_comparisons_block.html.haml │ │ └── _policy_comparisons.html.haml │ ├── users │ │ ├── confirm.html.haml │ │ └── show.html.haml │ ├── divisions │ │ ├── _pagination.html.haml │ │ ├── _summary_whip_vote.html.haml │ │ ├── _summary_whip_absent.html.haml │ │ ├── _divisions.html.haml │ │ ├── _external_links.html.haml │ │ ├── _summary_whip.html.haml │ │ ├── _header.html.haml │ │ ├── index_with_member.html.haml │ │ └── _summary_table.html.haml │ ├── devise │ │ ├── mailer │ │ │ ├── confirmation_instructions.text.erb │ │ │ ├── reset_password_instructions.text.erb │ │ │ ├── confirmation_instructions.html.haml │ │ │ └── reset_password_instructions.html.haml │ │ ├── passwords │ │ │ ├── edit.html.haml │ │ │ └── new.html.haml │ │ ├── confirmations │ │ │ └── new.html.haml │ │ └── sessions │ │ │ └── new.html.haml │ ├── layouts │ │ ├── _bootstrap_flash.html.haml │ │ ├── _history_notice.html.haml │ │ ├── _history_list.html.haml │ │ └── card_layout.html.haml │ ├── application │ │ ├── _honeybadger_javascript.html.haml │ │ ├── _swag.html.haml │ │ ├── _plausible_analytics.html.haml │ │ ├── _social_share.html.haml │ │ └── _logged_in_user_menu.html.haml │ └── feeds │ │ └── mpdream_info.xml.builder ├── jobs │ ├── calculate_policy_person_distances_job.rb │ ├── alert_watches_job.rb │ └── application_job.rb └── policies │ ├── division_policy.rb │ ├── policy_policy.rb │ ├── policy_division_policy.rb │ └── application_policy.rb ├── lib └── tasks │ └── .keep ├── .ruby-version ├── vendor └── assets │ ├── javascripts │ └── .keep │ └── stylesheets │ ├── .keep │ └── bootstrap-accessibility.css ├── .hound.yml ├── .rspec ├── Procfile ├── bin ├── dev ├── rake ├── rails ├── brakeman ├── rubocop ├── rspec ├── yarn ├── pry ├── ri ├── haml ├── mina ├── racc ├── rdoc ├── sdoc ├── thor ├── tilt ├── cap ├── guard ├── ldiff ├── rackup ├── capify ├── coderay ├── foreman ├── launchy ├── listen ├── bootsnap ├── htmldiff ├── httparty ├── nokogiri ├── skylight ├── _guard-core ├── redcarpet ├── ruby-parse ├── sdoc-merge ├── sprockets ├── stackprof ├── ruby-rewrite ├── ruby_parse ├── honeybadger ├── mongrel_rpm ├── update ├── reverse_markdown ├── elastic_ruby_console ├── stackprof-flamegraph.pl ├── stackprof-gprof2dot.py └── ruby_parse_extract_error ├── Procfile.ansible ├── Procfile.production ├── public ├── googled564325686c043cb.html ├── icon.png ├── favicon.ico ├── apple-touch-icon-precomposed.png └── icon.svg ├── config ├── honeybadger.yml ├── database.travis.yml ├── skylight.yml.example ├── spring.rb ├── environment.rb ├── initializers │ ├── session_store.rb │ ├── mime_types.rb │ ├── mini_profiler.rb │ ├── elasticsearch.rb │ ├── devise_async.rb │ ├── application_controller_renderer.rb │ ├── invisible_captcha.rb │ ├── admin_access.rb │ ├── filter_parameter_logging.rb │ ├── flipper.rb │ ├── cors.rb │ ├── assets.rb │ ├── permissions_policy.rb │ ├── wrap_parameters.rb │ ├── backtrace_silencers.rb │ ├── inflections.rb │ └── markdown_handler.rb ├── deploy │ ├── ukraine_dev.rb │ ├── ukraine_production.rb │ ├── staging.rb │ ├── production.rb │ └── development.rb ├── boot.rb ├── cable.yml ├── database.yml.example └── credentials │ └── production.yml.enc ├── .github ├── FUNDING.yml ├── CODEOWNERS ├── dependabot.yml └── stale.yml ├── spec ├── factories │ ├── persons.rb │ ├── votes.rb │ ├── policy_divisions.rb │ ├── division_infos.rb │ ├── member_infos.rb │ ├── people_distances.rb │ ├── users.rb │ ├── wiki_motions.rb │ ├── policy_person_distances.rb │ ├── policies.rb │ ├── whips.rb │ ├── offices.rb │ ├── divisions.rb │ └── members.rb ├── devise │ └── regression │ │ ├── confirmation.txt │ │ └── reset.txt ├── requests │ └── help_controller_spec.rb ├── mailers │ └── regression │ │ └── alert_mailer │ │ ├── email1.txt │ │ └── email2.txt ├── fixtures │ └── static_pages │ │ └── feeds │ │ └── mpdream-info.xml__id=1.xml ├── models │ └── policy_division_spec.rb └── features │ └── user_profile_spec.rb ├── design_docs ├── TVFY General Social Card.ai └── principles.md ├── local_dev ├── roles │ ├── app │ │ ├── templates │ │ │ ├── settings.yml │ │ │ ├── secrets.yml │ │ │ └── database.yml │ │ └── vars │ │ │ └── main.yml │ ├── docker │ │ ├── templates │ │ │ └── docker.list │ │ └── vars │ │ │ └── main.yml │ └── ruby │ │ └── vars │ │ └── main.yml ├── playbook.yml └── ansible.cfg ├── config.ru ├── db └── migrate │ ├── 20140822005440_rename_pw_mp_table.rb │ ├── 20211223010947_add_admin_to_users.rb │ ├── 20220217035040_add_policies_name_unique_index.rb │ ├── 20140822032917_rename_pw_vote_table.rb │ ├── 20140829025542_drop_sort_orders_table.rb │ ├── 20141009090336_add_title_to_bills.rb │ ├── 20220124013958_drop_edit_date_in_wiki_motions.rb │ ├── 20140822032540_rename_pw_dyn_user_table.rb │ ├── 20140822041718_rename_pw_moffice_table.rb │ ├── 20140823223520_rename_mp_id_in_votes.rb │ ├── 20140825021413_rename_user_id_in_users.rb │ ├── 20220224001347_add_extra_large_image_url_to_people.rb │ ├── 20140822034125_rename_pw_cache_whip_table.rb │ ├── 20140822040612_rename_pw_division_table.rb │ ├── 20140827093105_remove_pw_cache_divwiki_table.rb │ ├── 20140822012602_rename_pw_dyn_dreammp_table.rb │ ├── 20140823231135_rename_dream_id_in_policies.rb │ ├── 20140825022650_rename_person_in_members.rb │ ├── 20140825023720_rename_person_in_offices.rb │ ├── 20140827031535_remove_user_name_from_users.rb │ ├── 20140822064958_rename_division_id_column.rb │ ├── 20140822070958_rename_mp_id_column_in_members.rb │ ├── 20140823230610_rename_moffice_id_in_offices.rb │ ├── 20220201015710_make_user_name_required_in_schema_to_match_model.rb │ ├── 20140822010234_rename_pw_cache_mpinfo_table.rb │ ├── 20140822041229_rename_pw_constituency_table.rb │ ├── 20140825022036_rename_wiki_id_in_wiki_motions.rb │ ├── 20140923072111_rename_real_name_to_name_in_users.rb │ ├── 20140822011111_rename_pw_dyn_dreamvote_table.rb │ ├── 20140822034625_rename_pw_dyn_wiki_motion_table.rb │ ├── 20140822035700_rename_pw_cache_divinfo_table.rb │ ├── 20140829021006_remove_vote_from_votes.rb │ ├── 20140917033854_add_object_changes_to_versions.rb │ ├── 20140923074703_remove_active_policy_id_from_users.rb │ ├── 20141008013017_remove_notes_from_divisions.rb │ ├── 20140822055520_rename_pw_vote_sortorder_table.rb │ ├── 20140829023041_rename_vote_without_tell_in_votes.rb │ ├── 20141001030502_change_policy_description_to_text.rb │ ├── 20140822081103_rename_mp_id_column_in_member_infos.rb │ ├── 20140824000144_rename_dream_id_in_policy_divisions.rb │ ├── 20140924013708_add_markdown_to_divisions.rb │ ├── 20141007052651_make_markdown_default_in_divisions.rb │ ├── 20141021033254_add_api_key_to_users.rb │ ├── 20140917033028_add_policy_id_to_versions.rb │ ├── 20141008012425_add_bill_to_divisions.rb │ ├── 20140822002749_rename_pw_cache_realreal_distance_table.rb │ ├── 20140825024918_rename_person_in_policy_member_distances.rb │ ├── 20140825025958_rename_policy_member_distances_table.rb │ ├── 20140616062909_change_password_to_legacy_password_on_users.rb │ ├── 20140825020429_rename_dream_id_in_policy_member_distances.rb │ ├── 20141018235020_add_division_id_to_versions.rb │ ├── 20140822012134_rename_pw_cache_dreamreal_distance_table.rb │ ├── 20141001075857_add_images_urls_to_people.rb │ ├── 20140907063906_add_further_index_to_divisions.rb │ ├── 20140823224359_rename_mp_ids_in_member_distances.rb │ ├── 20141121043312_create_watches.rb │ ├── 20140923073138_remove_unused_columns_in_users.rb │ ├── 20140823225659_make_cons_id_primary_key_in_electorates.rb │ ├── 20220305211148_remove_unused_columns_on_divisions.rb │ ├── 20141017005318_remove_limits_on_house_fields.rb │ ├── 20141021184859_create_api_statistics.rb │ ├── 20140828053926_rename_division_date_number_name_in_divisions.rb │ ├── 20140905062045_remove_limits_from_fields_on_offices.rb │ ├── 20140928235604_create_people.rb │ ├── 20220202004503_add_staff_option_to_users.rb │ ├── 20141001030631_change_division_binary_columns_to_text.rb │ ├── 20140828080040_remove_division_date_number_house_from_wiki_motions.rb │ ├── 20141008030623_multiple_bills_in_divisions.rb │ ├── 20140917011343_create_versions.rb │ ├── 20140828062935_add_division_id_to_policy_divisions.rb │ ├── 20220413041820_create_people_distances.rb │ ├── 20140828074700_add_division_id_to_wiki_motions.rb │ ├── 20150617030311_convert_tables_to_utf8_character_set.rb │ ├── 20140821075351_drop_unused_tables_in_rails.rb │ ├── 20140828071906_drop_division_date_number_house_in_policy_divisions.rb │ ├── 20140930212321_add_timestamps_to_all_tables.rb │ ├── 20211223050627_create_flipper_tables.rb │ ├── 20140822004101_add_primary_keys.rb │ ├── 20220421041242_drop_member_distances.rb │ ├── 20140828083134_add_vote_without_tell_to_votes.rb │ ├── 20220217004002_convert_users_text_fields_to_string.rb │ └── 20140623022321_add_confirmable_to_devise.rb ├── Rakefile └── Makefile /log/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.4.4 2 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/lib/assets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.hound.yml: -------------------------------------------------------------------------------- 1 | ruby: 2 | config_file: .rubocop.yml 3 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format Fuubar 3 | --profile 4 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec rails server 2 | mailcatcher: mailcatcher 3 | -------------------------------------------------------------------------------- /bin/dev: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | exec "./bin/rails", "server", *ARGV 3 | -------------------------------------------------------------------------------- /Procfile.ansible: -------------------------------------------------------------------------------- 1 | worker: bundle exec rake jobs:work RAILS_ENV=production 2 | -------------------------------------------------------------------------------- /Procfile.production: -------------------------------------------------------------------------------- 1 | worker: rvm . do bundle exec rake jobs:work RAILS_ENV=production 2 | -------------------------------------------------------------------------------- /public/googled564325686c043cb.html: -------------------------------------------------------------------------------- 1 | google-site-verification: googled564325686c043cb.html -------------------------------------------------------------------------------- /app/assets/javascripts/global.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | return $("img.lazy").lazyload(); 3 | }); 4 | -------------------------------------------------------------------------------- /app/helpers/help_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module HelpHelper 4 | end 5 | -------------------------------------------------------------------------------- /app/helpers/home_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module HomeHelper 4 | end 5 | -------------------------------------------------------------------------------- /public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/public/icon.png -------------------------------------------------------------------------------- /app/assets/stylesheets/global/_footer.scss: -------------------------------------------------------------------------------- 1 | @import "footer-main"; 2 | @import "author-projects"; 3 | -------------------------------------------------------------------------------- /app/helpers/people_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module PeopleHelper 4 | end 5 | -------------------------------------------------------------------------------- /config/honeybadger.yml: -------------------------------------------------------------------------------- 1 | --- 2 | api_key: "<%= Rails.application.credentials.honeybadger&.api_key %>" 3 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /app/assets/javascripts/bootstrap.js: -------------------------------------------------------------------------------- 1 | jQuery(function() { 2 | return $(".has-tooltip").tooltip(); 3 | }); 4 | -------------------------------------------------------------------------------- /app/helpers/electorates_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ElectoratesHelper 4 | end 5 | -------------------------------------------------------------------------------- /config/database.travis.yml: -------------------------------------------------------------------------------- 1 | test: 2 | adapter: mysql2 3 | database: publicwhip_test 4 | username: root 5 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative "../config/boot" 3 | require "rake" 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: ['https://www.oaf.org.au/donate/'] 4 | -------------------------------------------------------------------------------- /app/assets/images/op-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/op-logo.png -------------------------------------------------------------------------------- /app/assets/images/ua-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/ua-logo.png -------------------------------------------------------------------------------- /app/assets/stylesheets/global/_history-list.scss: -------------------------------------------------------------------------------- 1 | .change-policy-name ~ .change-action { 2 | margin-left: 1em; 3 | } 4 | -------------------------------------------------------------------------------- /app/views/api/v1/offices/_office.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.position office.position 4 | -------------------------------------------------------------------------------- /spec/factories/persons.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :person 5 | end 6 | -------------------------------------------------------------------------------- /app/assets/images/civio-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/civio-logo.png -------------------------------------------------------------------------------- /app/assets/images/crta-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/crta-logo.png -------------------------------------------------------------------------------- /app/assets/images/data-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/data-logo.png -------------------------------------------------------------------------------- /app/assets/images/efa-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/efa-logo.png -------------------------------------------------------------------------------- /app/assets/images/pmg-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/pmg-logo.png -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationMailer < ActionMailer::Base 4 | end 5 | -------------------------------------------------------------------------------- /app/models/office.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Office < ApplicationRecord 4 | belongs_to :person 5 | end 6 | -------------------------------------------------------------------------------- /config/skylight.yml.example: -------------------------------------------------------------------------------- 1 | --- 2 | # The authentication token for the application. 3 | authentication: xxxxxxxxxxxxxxxxxxxxx 4 | -------------------------------------------------------------------------------- /app/assets/images/mysociety-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/mysociety-logo.png -------------------------------------------------------------------------------- /app/assets/images/open-forum-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/open-forum-logo.png -------------------------------------------------------------------------------- /app/assets/images/open-north-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/open-north-logo.png -------------------------------------------------------------------------------- /app/assets/images/openpolis-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/openpolis-logo.png -------------------------------------------------------------------------------- /app/assets/javascripts/swag.js: -------------------------------------------------------------------------------- 1 | $('.alert.swag').on('closed.bs.alert', function () { 2 | document.cookie='tvfy_swag=false;Path=/' 3 | }) -------------------------------------------------------------------------------- /app/assets/stylesheets/global/_tables.scss: -------------------------------------------------------------------------------- 1 | th { 2 | font-weight: normal; 3 | } 4 | 5 | .rebel { 6 | color: $color-rebel; 7 | } 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/policies/_policies-new.scss: -------------------------------------------------------------------------------- 1 | #tips { 2 | ul { 3 | padding-left: 0; 4 | list-style: none; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /app/views/api/v1/people/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.array! @people, partial: "person", as: :person 4 | -------------------------------------------------------------------------------- /app/views/help/faq/_rebellion.md: -------------------------------------------------------------------------------- 1 | "Rebellion" figures record the number of rebel votes 2 | (see [What are “Rebel Voters”?](#rebel)). 3 | -------------------------------------------------------------------------------- /app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../javascripts .js 3 | //= link_directory ../stylesheets .css 4 | -------------------------------------------------------------------------------- /app/assets/images/avatars/emmaaargh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/avatars/emmaaargh.jpg -------------------------------------------------------------------------------- /app/assets/images/avatars/hey_maze.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/avatars/hey_maze.jpg -------------------------------------------------------------------------------- /app/assets/stylesheets/policies/_policies.scss: -------------------------------------------------------------------------------- 1 | @import "policies-list"; 2 | @import "policies-new"; 3 | @import "policy-voter-comparision"; 4 | -------------------------------------------------------------------------------- /app/models/bill.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Bill < ApplicationRecord 4 | has_and_belongs_to_many :divisions 5 | end 6 | -------------------------------------------------------------------------------- /app/views/api/v1/policies/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.array! @policies, partial: "policy", as: :policy 4 | -------------------------------------------------------------------------------- /design_docs/TVFY General Social Card.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/design_docs/TVFY General Social Card.ai -------------------------------------------------------------------------------- /public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /app/assets/images/avatars/sarah_wilson.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/avatars/sarah_wilson.jpg -------------------------------------------------------------------------------- /app/views/alert_mailer/_policy_updated_subject.text.erb: -------------------------------------------------------------------------------- 1 | Policy “<%= policy.name_with_for %>” updated on <%= Rails.configuration.project_name %> 2 | -------------------------------------------------------------------------------- /app/views/api/v1/divisions/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.array! @divisions, partial: "division", as: :division 4 | -------------------------------------------------------------------------------- /app/assets/images/regards-citoyens-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/regards-citoyens-logo.png -------------------------------------------------------------------------------- /config/spring.rb: -------------------------------------------------------------------------------- 1 | %w( 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ).each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /local_dev/roles/app/templates/settings.yml: -------------------------------------------------------------------------------- 1 | # Optionally change the address of the elasticsearch service 2 | elasticsearch_url: http://localhost:9200 3 | -------------------------------------------------------------------------------- /public/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/assets/images/avatars/daniel_ferguson.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/avatars/daniel_ferguson.jpg -------------------------------------------------------------------------------- /app/assets/images/tvfy_general_social_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/tvfy_general_social_card.png -------------------------------------------------------------------------------- /app/assets/stylesheets/members/_members.scss: -------------------------------------------------------------------------------- 1 | @import "members/member-show"; 2 | @import "members/member-list"; 3 | @import "members/member-list-compact"; 4 | -------------------------------------------------------------------------------- /app/assets/images/avatars/alice_in_covid_land.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/avatars/alice_in_covid_land.jpg -------------------------------------------------------------------------------- /app/assets/images/theyvoteforyou_logo_200x200.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/theyvoteforyou_logo_200x200.jpg -------------------------------------------------------------------------------- /app/assets/images/theyvoteforyou_logo_600x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openaustralia/theyvoteforyou/HEAD/app/assets/images/theyvoteforyou_logo_600x600.jpg -------------------------------------------------------------------------------- /app/helpers/api/v1/people_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | module PeopleHelper 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationRecord < ActiveRecord::Base 4 | self.abstract_class = true 5 | end 6 | -------------------------------------------------------------------------------- /spec/factories/votes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :vote do 5 | member 6 | division 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/helpers/api/v1/policies_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | module PoliciesHelper 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path("../config/application", __dir__) 3 | require_relative "../config/boot" 4 | require "rails/commands" 5 | -------------------------------------------------------------------------------- /local_dev/roles/app/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | docker_compose_dir: '{{ work_base_dir }}/docker-compose' 3 | docker_compose_path: '{{ docker_compose_dir }}/docker-compose.yml' -------------------------------------------------------------------------------- /app/helpers/api/v1/divisions_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | module DivisionsHelper 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/models/watch.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Watch < ApplicationRecord 4 | belongs_to :watchable, polymorphic: true 5 | belongs_to :user 6 | end 7 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /app/models/electorate.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # TODO: I think this is completely unused. Remove from schema 4 | class Electorate < ApplicationRecord 5 | end 6 | -------------------------------------------------------------------------------- /bin/brakeman: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "rubygems" 3 | require "bundler/setup" 4 | 5 | ARGV.unshift("--ensure-latest") 6 | 7 | load Gem.bin_path("brakeman", "brakeman") 8 | -------------------------------------------------------------------------------- /app/views/api/v1/bills/_bill.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.id bill.id 4 | json.official_id bill.official_id 5 | json.title bill.title 6 | json.url bill.url 7 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative "config/environment" 4 | 5 | run Rails.application 6 | Rails.application.load_server 7 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_publicwhip_session' 4 | -------------------------------------------------------------------------------- /app/views/api/v1/votes/_vote.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.vote vote.vote 4 | json.member do 5 | json.partial! "api/v1/members/member", member: vote.member 6 | end 7 | -------------------------------------------------------------------------------- /config/deploy/ukraine_dev.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | set :domain, "theyvoteforyou.org.au.dev" 4 | set :repository, "https://github.com/opora/publicwhip.git" 5 | set :branch, "develop" 6 | -------------------------------------------------------------------------------- /app/views/home/error500.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "We're sorry, but something went wrong" 2 | .page-header 3 | %h1= yield :title 4 | %p Try again and contact us if you're still having problems. 5 | -------------------------------------------------------------------------------- /app/views/people_distances/_comparison_all_same.html.haml: -------------------------------------------------------------------------------- 1 | = render "comparison_block", person_distance: person_distance, policies: policies, title: "Always voted the same way on", label: :"always-same" 2 | -------------------------------------------------------------------------------- /app/views/policies/how_the_number_is_calculated/_cells.html.haml: -------------------------------------------------------------------------------- 1 | %td= fraction_to_percentage_display(Distance.score(type)) 2 | %td= Distance.weights(type) 3 | %td= policy_person_distance.no_votes(type) 4 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/deploy/ukraine_production.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | set :domain, "li1413-108.members.linode.com" 4 | set :repository, "https://github.com/opora/publicwhip.git" 5 | set :branch, "develop" 6 | -------------------------------------------------------------------------------- /db/migrate/20140822005440_rename_pw_mp_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwMpTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_mp, :members 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20211223010947_add_admin_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddAdminToUsers < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :admin, :boolean, null: false, default: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20220217035040_add_policies_name_unique_index.rb: -------------------------------------------------------------------------------- 1 | class AddPoliciesNameUniqueIndex < ActiveRecord::Migration[6.0] 2 | def change 3 | add_index :policies, :name, unique: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /local_dev/playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | tasks: 4 | - import_role: 5 | name: docker 6 | - import_role: 7 | name: ruby 8 | - import_role: 9 | name: app 10 | -------------------------------------------------------------------------------- /app/assets/stylesheets/divisions/_divisions.scss: -------------------------------------------------------------------------------- 1 | @import "division-show"; 2 | @import "division-motion"; 3 | @import "division-votes-table"; 4 | @import "division-list"; 5 | @import "division-comparison-table"; 6 | -------------------------------------------------------------------------------- /app/views/members/_interesting_votes.html.haml: -------------------------------------------------------------------------------- 1 | = render "members/rebellious_divisions", member: member 2 | 3 | - if member.person.free_votes_with_whip > 0 4 | = render "members/free_divisions", member: member 5 | -------------------------------------------------------------------------------- /app/views/people_distances/_comparison_all_different.html.haml: -------------------------------------------------------------------------------- 1 | = render "comparison_block", person_distance: person_distance, policies: policies, title: "Always voted differently on", label: :"always-different" 2 | -------------------------------------------------------------------------------- /db/migrate/20140822032917_rename_pw_vote_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwVoteTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_vote, :votes 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140829025542_drop_sort_orders_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DropSortOrdersTable < ActiveRecord::Migration 4 | def change 5 | drop_table :vote_sortorders 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141009090336_add_title_to_bills.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTitleToBills < ActiveRecord::Migration 4 | def change 5 | add_column :bills, :title, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/factories/policy_divisions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :policy_division do 5 | policy 6 | division 7 | vote { "aye" } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/views/home/error404.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Sorry, that page wasn't found" 2 | .page-header 3 | %h1= yield :title 4 | %p Check the address and contact us if you still can't find what you were looking for. 5 | -------------------------------------------------------------------------------- /db/migrate/20220124013958_drop_edit_date_in_wiki_motions.rb: -------------------------------------------------------------------------------- 1 | class DropEditDateInWikiMotions < ActiveRecord::Migration[5.0] 2 | def change 3 | remove_column :wiki_motions, :edit_date, :datetime 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/views/people_distances/_comparison_different_and_same.html.haml: -------------------------------------------------------------------------------- 1 | = render "comparison_block", person_distance: person_distance, policies: policies, title: "Voted a mixture of the same and differently on", label: :mixture 2 | -------------------------------------------------------------------------------- /db/migrate/20140822032540_rename_pw_dyn_user_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwDynUserTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_dyn_user, :users 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140822041718_rename_pw_moffice_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwMofficeTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_moffice, :offices 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140823223520_rename_mp_id_in_votes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameMpIdInVotes < ActiveRecord::Migration 4 | def change 5 | rename_column :votes, :mp_id, :member_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140825021413_rename_user_id_in_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameUserIdInUsers < ActiveRecord::Migration 4 | def change 5 | rename_column :users, :user_id, :id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20220224001347_add_extra_large_image_url_to_people.rb: -------------------------------------------------------------------------------- 1 | class AddExtraLargeImageUrlToPeople < ActiveRecord::Migration[6.0] 2 | def change 3 | add_column :people, :extra_large_image_url, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This file is used to define code owners for this repository. 2 | # See https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners 3 | 4 | * @openaustralia/code-reviewers 5 | -------------------------------------------------------------------------------- /app/views/users/confirm.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, 'Confirm your email address' 2 | 3 | .single-message.thin-page 4 | %p.loud 5 | Great, now 6 | %strong check your inbox 7 | for your confirmation email. 8 | -------------------------------------------------------------------------------- /db/migrate/20140822034125_rename_pw_cache_whip_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwCacheWhipTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_cache_whip, :whips 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140822040612_rename_pw_division_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwDivisionTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_division, :divisions 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140827093105_remove_pw_cache_divwiki_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemovePwCacheDivwikiTable < ActiveRecord::Migration 4 | def change 5 | drop_table :pw_cache_divwiki 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 2 | 3 | require "bundler/setup" # Set up gems listed in the Gemfile. 4 | require "bootsnap/setup" # Speed up boot time by caching expensive operations. 5 | -------------------------------------------------------------------------------- /db/migrate/20140822012602_rename_pw_dyn_dreammp_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwDynDreammpTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_dyn_dreammp, :policies 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140823231135_rename_dream_id_in_policies.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameDreamIdInPolicies < ActiveRecord::Migration 4 | def change 5 | rename_column :policies, :dream_id, :id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140825022650_rename_person_in_members.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePersonInMembers < ActiveRecord::Migration 4 | def change 5 | rename_column :members, :person, :person_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140825023720_rename_person_in_offices.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePersonInOffices < ActiveRecord::Migration 4 | def change 5 | rename_column :offices, :person, :person_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140827031535_remove_user_name_from_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveUserNameFromUsers < ActiveRecord::Migration 4 | def change 5 | remove_column :users, :user_name, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/views/divisions/_pagination.html.haml: -------------------------------------------------------------------------------- 1 | %nav.index-pagination 2 | %ul.pagination 3 | - years.reverse.each do |year| 4 | = nav_link(year, { date: year }, "Divisions held in #{year}", (date_start && date_start.year == year)) 5 | -------------------------------------------------------------------------------- /db/migrate/20140822064958_rename_division_id_column.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameDivisionIdColumn < ActiveRecord::Migration 4 | def change 5 | rename_column :divisions, :division_id, :id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140822070958_rename_mp_id_column_in_members.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameMpIdColumnInMembers < ActiveRecord::Migration 4 | def change 5 | rename_column :members, :mp_id, :id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140823230610_rename_moffice_id_in_offices.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameMofficeIdInOffices < ActiveRecord::Migration 4 | def change 5 | rename_column :offices, :moffice_id, :id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20220201015710_make_user_name_required_in_schema_to_match_model.rb: -------------------------------------------------------------------------------- 1 | class MakeUserNameRequiredInSchemaToMatchModel < ActiveRecord::Migration[6.0] 2 | def change 3 | change_column_null :users, :name, false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20140822010234_rename_pw_cache_mpinfo_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwCacheMpinfoTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_cache_mpinfo, :member_infos 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140822041229_rename_pw_constituency_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwConstituencyTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_constituency, :electorates 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140825022036_rename_wiki_id_in_wiki_motions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameWikiIdInWikiMotions < ActiveRecord::Migration 4 | def change 5 | rename_column :wiki_motions, :wiki_id, :id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140923072111_rename_real_name_to_name_in_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameRealNameToNameInUsers < ActiveRecord::Migration 4 | def change 5 | rename_column :users, :real_name, :name 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/global/_alerts.scss: -------------------------------------------------------------------------------- 1 | .alert-container { 2 | .alert { 3 | margin-bottom: 0; 4 | border: 0; 5 | } 6 | } 7 | 8 | .alert-postnote { 9 | border-radius: 0; 10 | border-left: .5em solid $gray-lighter; 11 | } 12 | -------------------------------------------------------------------------------- /db/migrate/20140822011111_rename_pw_dyn_dreamvote_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwDynDreamvoteTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_dyn_dreamvote, :policy_divisions 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140822034625_rename_pw_dyn_wiki_motion_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwDynWikiMotionTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_dyn_wiki_motion, :wiki_motions 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140822035700_rename_pw_cache_divinfo_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwCacheDivinfoTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_cache_divinfo, :division_infos 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140829021006_remove_vote_from_votes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveVoteFromVotes < ActiveRecord::Migration 4 | def change 5 | remove_column :votes, :vote, :string, limit: 10, null: false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140917033854_add_object_changes_to_versions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddObjectChangesToVersions < ActiveRecord::Migration 4 | def change 5 | add_column :versions, :object_changes, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140923074703_remove_active_policy_id_from_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveActivePolicyIdFromUsers < ActiveRecord::Migration 4 | def change 5 | remove_columns :users, :active_policy_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141008013017_remove_notes_from_divisions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveNotesFromDivisions < ActiveRecord::Migration 4 | def change 5 | remove_column :divisions, :notes, :text, null: false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: test 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: publicwhip_production 11 | -------------------------------------------------------------------------------- /db/migrate/20140822055520_rename_pw_vote_sortorder_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwVoteSortorderTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_vote_sortorder, :vote_sortorders 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140829023041_rename_vote_without_tell_in_votes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameVoteWithoutTellInVotes < ActiveRecord::Migration 4 | def change 5 | rename_column :votes, :vote_without_tell, :vote 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141001030502_change_policy_description_to_text.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangePolicyDescriptionToText < ActiveRecord::Migration 4 | def change 5 | change_column :policies, :description, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/helpers/card_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module CardHelper 4 | def get_hostname(url) 5 | uri = URI(url) 6 | uri.hostname 7 | end 8 | 9 | def remove_slash(link) 10 | link.sub("//", "/") 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/views/people_distances/_policies_intro.html.haml: -------------------------------------------------------------------------------- 1 | %h2 How do their votes on policies compare? 2 | %p.compare-policies-intro 3 | Policies are groups of votes related to an issue. 4 | We only show policies where we have enough information on both people. 5 | -------------------------------------------------------------------------------- /config/initializers/mini_profiler.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Config for mini profiler 4 | # https://github.com/MiniProfiler/rack-mini-profiler#configuration-options 5 | # Rack::MiniProfiler.config.start_hidden = true if Rails.env.development? 6 | -------------------------------------------------------------------------------- /db/migrate/20140822081103_rename_mp_id_column_in_member_infos.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameMpIdColumnInMemberInfos < ActiveRecord::Migration 4 | def change 5 | rename_column :member_infos, :mp_id, :member_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140824000144_rename_dream_id_in_policy_divisions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameDreamIdInPolicyDivisions < ActiveRecord::Migration 4 | def change 5 | rename_column :policy_divisions, :dream_id, :policy_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140924013708_add_markdown_to_divisions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddMarkdownToDivisions < ActiveRecord::Migration 4 | def change 5 | add_column :divisions, :markdown, :boolean, null: false, default: false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /local_dev/roles/docker/templates/docker.list: -------------------------------------------------------------------------------- 1 | 2 | # {{ ansible_managed }} 3 | # Docker Ubuntu apt repo 4 | 5 | deb [arch={{ docker_ubuntu_apt_arch }} signed-by={{ docker_ubuntu_gpg_keyring_path }}] {{ docker_ubuntu_apt_url }} {{ docker_ubuntu_apt_dist }} stable 6 | -------------------------------------------------------------------------------- /app/lib/house.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class House 4 | class << self 5 | def australian 6 | %w[representatives senate] 7 | end 8 | 9 | def valid?(name) 10 | australian.include?(name) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/views/api/v1/policies/_policy.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.id policy.id 4 | json.name policy.name 5 | json.description policy.description 6 | json.provisional policy.provisional? 7 | json.last_edited_at policy.last_edited_at.iso8601 8 | -------------------------------------------------------------------------------- /config/initializers/elasticsearch.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # To reduce log noise 4 | Ethon.logger = Logger.new(nil) 5 | 6 | ENV["ELASTICSEARCH_URL"] = Rails.application.credentials.elasticsearch.url if Rails.application.credentials.elasticsearch&.url 7 | -------------------------------------------------------------------------------- /db/migrate/20141007052651_make_markdown_default_in_divisions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class MakeMarkdownDefaultInDivisions < ActiveRecord::Migration 4 | def change 5 | change_column :divisions, :markdown, :boolean, default: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141021033254_add_api_key_to_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddApiKeyToUsers < ActiveRecord::Migration 4 | def change 5 | add_column :users, :api_key, :string 6 | add_index :users, :api_key, unique: true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/devise/regression/confirmation.txt: -------------------------------------------------------------------------------- 1 | Matthew Landauer, you are one step away from creating your account on They Vote For You 2 | 3 | Please confirm your account email by clicking the link below: 4 | 5 | http://pw.org.au/users/confirmation?confirmation_token=abc123 6 | -------------------------------------------------------------------------------- /app/jobs/calculate_policy_person_distances_job.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CalculatePolicyPersonDistancesJob < ApplicationJob 4 | queue_as :default 5 | 6 | def perform(policy) 7 | policy.calculate_person_distances! 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/views/home/_panel1.md: -------------------------------------------------------------------------------- 1 | ## Discover & Share 2 | 3 | Discover how your [representatives in parliament](<%= members_path %>) vote on 4 | [issues you care about](<%= policies_path %>). You might be surprised by what you find. 5 | Share this with others and spread the word. 6 | -------------------------------------------------------------------------------- /config/deploy/staging.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | set :branch, :main 4 | set :deploy_to, "/srv/www/staging" 5 | 6 | role :app, %w[deploy@theyvoteforyou.org.au] 7 | role :web, %w[deploy@theyvoteforyou.org.au] 8 | role :db, %w[deploy@theyvoteforyou.org.au] 9 | -------------------------------------------------------------------------------- /db/migrate/20140917033028_add_policy_id_to_versions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPolicyIdToVersions < ActiveRecord::Migration 4 | def change 5 | add_column :versions, :policy_id, :integer 6 | add_index :versions, :policy_id 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20141008012425_add_bill_to_divisions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddBillToDivisions < ActiveRecord::Migration 4 | def change 5 | add_column :divisions, :bill_id, :string 6 | add_column :divisions, :bill_url, :text 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/help_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class HelpController < ApplicationController 4 | def faq; end 5 | 6 | def data; end 7 | 8 | def research; end 9 | 10 | def licencing; end 11 | 12 | def style_guide; end 13 | end 14 | -------------------------------------------------------------------------------- /config/deploy/production.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | set :branch, :main 4 | set :deploy_to, "/srv/www/production" 5 | 6 | role :app, %w[deploy@theyvoteforyou.org.au] 7 | role :web, %w[deploy@theyvoteforyou.org.au] 8 | role :db, %w[deploy@theyvoteforyou.org.au] 9 | -------------------------------------------------------------------------------- /db/migrate/20140822002749_rename_pw_cache_realreal_distance_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwCacheRealrealDistanceTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_cache_realreal_distance, :member_distances 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140825024918_rename_person_in_policy_member_distances.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePersonInPolicyMemberDistances < ActiveRecord::Migration 4 | def change 5 | rename_column :policy_member_distances, :person, :person_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140825025958_rename_policy_member_distances_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePolicyMemberDistancesTable < ActiveRecord::Migration 4 | def change 5 | rename_table :policy_member_distances, :policy_person_distances 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /local_dev/roles/app/templates/secrets.yml: -------------------------------------------------------------------------------- 1 | development: 2 | secret_key_base: '{{ rails_dev_secret_key_base }}' 3 | secret_key: '{{ rails_dev_secret_key }}' 4 | 5 | test: 6 | secret_key_base: '{{ rails_test_secret_key_base }}' 7 | secret_key: '{{ rails_test_secret_key }}' 8 | -------------------------------------------------------------------------------- /app/lib/check_resource_exists.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "net/http" 4 | 5 | class CheckResourceExists 6 | def self.call(url) 7 | uri = URI(url) 8 | res = Net::HTTP.get_response(uri) 9 | res.is_a? Net::HTTPSuccess 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20140616062909_change_password_to_legacy_password_on_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangePasswordToLegacyPasswordOnUsers < ActiveRecord::Migration 4 | def change 5 | rename_column :pw_dyn_user, :password, :legacy_password 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140825020429_rename_dream_id_in_policy_member_distances.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameDreamIdInPolicyMemberDistances < ActiveRecord::Migration 4 | def change 5 | rename_column :policy_member_distances, :dream_id, :policy_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141018235020_add_division_id_to_versions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddDivisionIdToVersions < ActiveRecord::Migration 4 | def change 5 | add_column :versions, :division_id, :integer 6 | add_index :versions, :division_id 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /config/initializers/devise_async.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Supported options: :resque, :sidekiq, :delayed_job, :queue_classic, :torquebox, :backburner 3 | # TODO: Re-enable devise_async once upgraded Devise to 4.x and Rails to 5.x 4 | # Devise::Async.backend = :delayed_job 5 | -------------------------------------------------------------------------------- /db/migrate/20140822012134_rename_pw_cache_dreamreal_distance_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePwCacheDreamrealDistanceTable < ActiveRecord::Migration 4 | def change 5 | rename_table :pw_cache_dreamreal_distance, :policy_member_distances 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141001075857_add_images_urls_to_people.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddImagesUrlsToPeople < ActiveRecord::Migration 4 | def change 5 | add_column :people, :small_image_url, :text 6 | add_column :people, :large_image_url, :text 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/views/home/_panel3.md: -------------------------------------------------------------------------------- 1 | ## Use the data 2 | 3 | This is a free and [open source](<%= help_licencing_path %>) public resource. Everything here can be reused in your own project. Use [our API](<%= help_data_path %>) to remix, play and tell your stories about how they vote to change our laws. 4 | -------------------------------------------------------------------------------- /config/deploy/development.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | set :branch, :main 4 | set :deploy_to, "/srv/www/production" 5 | 6 | role :app, %w[deploy@theyvoteforyou.org.au.test] 7 | role :web, %w[deploy@theyvoteforyou.org.au.test] 8 | role :db, %w[deploy@theyvoteforyou.org.au.test] 9 | -------------------------------------------------------------------------------- /local_dev/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | retry_files_enabled = False 3 | deprecation_warnings = True 4 | interpreter_python = /opt/ansible-venv/bin/python 5 | 6 | [privilege_escalation] 7 | become = True 8 | become_method = sudo 9 | become_user = vagrant 10 | become_ask_pass = False 11 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /config/initializers/invisible_captcha.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | InvisibleCaptcha.setup do |config| 4 | # Set this to true for development so a human can see 5 | # the honeypot field 6 | config.visual_honeypots = false 7 | config.timestamp_enabled = !Rails.env.test? 8 | end 9 | -------------------------------------------------------------------------------- /spec/factories/division_infos.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :division_info do 5 | division 6 | rebellions { 0 } 7 | tells { 0 } 8 | turnout { 0 } 9 | possible_turnout { 0 } 10 | aye_majority { 0 } 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/factories/member_infos.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :member_info do 5 | member 6 | rebellions { 0 } 7 | tells { 0 } 8 | votes_attended { 0 } 9 | votes_possible { 0 } 10 | aye_majority { 0 } 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20140907063906_add_further_index_to_divisions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddFurtherIndexToDivisions < ActiveRecord::Migration 4 | def change 5 | change_column :divisions, :clock_time, :string 6 | add_index :divisions, %i[id date clock_time] 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/views/home/_panel2.md: -------------------------------------------------------------------------------- 1 | ## Make it better 2 | 3 | People like you are making votes in Parliament easier to use by [summarising divisions](<%= help_research_path %>) and editing [policies](<%= policies_path %>), just like Wikipedia. Fix-up mistakes or add something new—if you see something, do something. 4 | -------------------------------------------------------------------------------- /bin/rubocop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "rubygems" 3 | require "bundler/setup" 4 | 5 | # explicit rubocop config increases performance slightly while avoiding config confusion. 6 | ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__)) 7 | 8 | load Gem.bin_path("rubocop", "rubocop") 9 | -------------------------------------------------------------------------------- /spec/factories/people_distances.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :people_distance do 5 | person1 factory: %i[person] 6 | person2 factory: %i[person] 7 | nvotessame { 0 } 8 | nvotesdiffer { 0 } 9 | distance_b { 0 } 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/views/api/v1/members/_member.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.id member.id 4 | json.person do 5 | json.id member.person_id 6 | end 7 | json.first_name member.first_name 8 | json.last_name member.last_name 9 | json.electorate member.electorate 10 | json.party member.party 11 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Add your own tasks in files placed in lib/tasks ending in .rake, 4 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 5 | 6 | require File.expand_path("config/application", __dir__) 7 | 8 | Publicwhip::Application.load_tasks 9 | -------------------------------------------------------------------------------- /app/views/devise/mailer/confirmation_instructions.text.erb: -------------------------------------------------------------------------------- 1 | <%= @resource.name %>, you are one step away from creating your account on <%= Rails.configuration.project_name %> 2 | 3 | Please confirm your account email by clicking the link below: 4 | 5 | <%= confirmation_url(@resource, confirmation_token: @token) %> 6 | -------------------------------------------------------------------------------- /db/migrate/20140823224359_rename_mp_ids_in_member_distances.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameMpIdsInMemberDistances < ActiveRecord::Migration 4 | def change 5 | rename_column :member_distances, :mp_id1, :member1_id 6 | rename_column :member_distances, :mp_id2, :member2_id 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20141121043312_create_watches.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateWatches < ActiveRecord::Migration 4 | def change 5 | create_table :watches do |t| 6 | t.integer :watchable_id 7 | t.string :watchable_type 8 | t.integer :user_id 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/jobs/alert_watches_job.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AlertWatchesJob < ApplicationJob 4 | queue_as :default 5 | 6 | def perform(policy, version) 7 | policy.watches.each do |watch| 8 | AlertMailer.policy_updated(policy, version, watch.user).deliver 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/views/policies/_draft_warning.html.haml: -------------------------------------------------------------------------------- 1 | - if policy.provisional? 2 | .row.alert.alert-danger{role: "alert"} 3 | %span.fi-alert 4 | %strong Warning! 5 | Don't share this. It's a 6 | %strong draft 7 | which means someone is still working on it and 8 | it may be 9 | %strong wildly innaccurate 10 | -------------------------------------------------------------------------------- /app/assets/stylesheets/global/_banners.scss: -------------------------------------------------------------------------------- 1 | .banner-heading, 2 | .banner-action { 3 | float: none; 4 | clear: both; 5 | 6 | @media (min-width: $screen-sm-min) { 7 | margin-left: auto; 8 | margin-right: auto; 9 | } 10 | } 11 | 12 | .banner-action { 13 | label { 14 | font-weight: normal; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /db/migrate/20140923073138_remove_unused_columns_in_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveUnusedColumnsInUsers < ActiveRecord::Migration 4 | def change 5 | remove_columns :users, :legacy_password, :remote_addr, :confirm_hash, :confirm_return_url, 6 | :is_confirmed, :reg_date 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/views/members/friends.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title do 2 | Compare 3 | = @member.name 4 | with someone else 5 | - set_meta_tags description: "See how #{@member.name} voted compared with other people" 6 | 7 | = render "member_page_header", member: @member 8 | = render "possible_friends", person: @member.person, all_friends: true 9 | -------------------------------------------------------------------------------- /app/controllers/registrations_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RegistrationsController < Devise::RegistrationsController 4 | invisible_captcha only: :create, honeypot: :title, scope: :user 5 | 6 | protected 7 | 8 | def after_inactive_sign_up_path_for(_resource) 9 | user_confirm_path 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/factories/users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :user do 5 | sequence(:email) { |n| "henare#{n}@oaf.org.au" } 6 | password { "password" } 7 | name { "Henare Degan" } 8 | 9 | factory :confirmed_user do 10 | confirmed_at { Time.zone.now } 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /config/initializers/admin_access.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Only admins can access flipper (the feature flag panel) 4 | class CanAccessFlipperUI 5 | def self.matches?(request) 6 | current_user = request.env["warden"].user 7 | current_user.present? && current_user.respond_to?(:admin?) && current_user.admin? 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20140823225659_make_cons_id_primary_key_in_electorates.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class MakeConsIdPrimaryKeyInElectorates < ActiveRecord::Migration 4 | def change 5 | remove_column :electorates, :id 6 | rename_column :electorates, :cons_id, :id 7 | change_column :electorates, :id, :primary_key 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/factories/wiki_motions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :wiki_motion do 5 | title { "An edited division" } 6 | description { "This division relates to all sorts of interesting things." } 7 | created_at { Time.zone.local(2014, 1, 1, 1, 1, 1) } 8 | user 9 | division 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationJob < ActiveJob::Base 4 | # Automatically retry jobs that encountered a deadlock 5 | # retry_on ActiveRecord::Deadlocked 6 | 7 | # Most jobs are safe to ignore if the underlying records are no longer available 8 | # discard_on ActiveJob::DeserializationError 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20220305211148_remove_unused_columns_on_divisions.rb: -------------------------------------------------------------------------------- 1 | class RemoveUnusedColumnsOnDivisions < ActiveRecord::Migration[6.0] 2 | def change 3 | remove_column :divisions, :valid, :boolean 4 | remove_column :divisions, :markdown, :boolean, default: true, null: false 5 | remove_column :divisions, :source_gid, :text, null: false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/devise/regression/reset.txt: -------------------------------------------------------------------------------- 1 | Matthew Landauer, someone has requested a link to change your password. You can do this through the link below. 2 | 3 | http://pw.org.au/users/password/edit?reset_password_token=abc123 4 | 5 | If you didn't request this, please ignore this email. 6 | 7 | Your password won't change until you access the link above and create a new one. 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/members/_member-list-compact.scss: -------------------------------------------------------------------------------- 1 | .member-list-compact { 2 | .member-item { 3 | @include clearfix; 4 | } 5 | 6 | .member-link { 7 | .policy-comparision-block & { 8 | color: $text-color; 9 | } 10 | } 11 | 12 | .member-photo { 13 | float: left; 14 | clear: left; 15 | margin-right: .5em; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/helpers/users_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module UsersHelper 4 | def name_with_badge(user) 5 | out = [] 6 | out << link_to_unless_current(user.name, user) 7 | if user.staff 8 | out << " " 9 | out << content_tag(:span, "staff", class: %w[label label-default staff]) 10 | end 11 | safe_join(out) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/factories/policy_person_distances.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :policy_person_distance do 5 | policy 6 | person 7 | nvotessame { 0 } 8 | nvotessamestrong { 0 } 9 | nvotesdiffer { 0 } 10 | nvotesdifferstrong { 0 } 11 | nvotesabsent { 0 } 12 | nvotesabsentstrong { 0 } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/controllers/api/v1/policies_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class PoliciesController < Api::V1::ApplicationController 6 | def index 7 | @policies = Policy.order(:id).all 8 | end 9 | 10 | def show 11 | @policy = Policy.find(params[:id]) 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20141017005318_remove_limits_on_house_fields.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveLimitsOnHouseFields < ActiveRecord::Migration 4 | def change 5 | change_column :divisions, :house, :string, limit: nil 6 | change_column :electorates, :house, :string, limit: nil 7 | change_column :members, :house, :string, limit: nil 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20141021184859_create_api_statistics.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateApiStatistics < ActiveRecord::Migration 4 | def change 5 | create_table :api_statistics do |t| 6 | t.string :ip_address 7 | t.text :query 8 | t.text :user_agent 9 | t.integer :user_id 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/controllers/api/v1/people_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class PeopleController < Api::V1::ApplicationController 6 | def index 7 | @people = Person.current.includes(:members) 8 | end 9 | 10 | def show 11 | @person = Person.find(params[:id]) 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/factories/policies.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :policy do 5 | sequence(:name) { |n| "the existence of test policies #{n}" } 6 | description { "there should be fabulous test policies" } 7 | private { 0 } 8 | user 9 | 10 | factory :provisional_policy do 11 | private { 2 } 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/requests/help_controller_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | # Compare results of rendering pages via rails and via the old php app 5 | 6 | describe HelpController, type: :request do 7 | include HTMLCompareHelper 8 | include_context "with fixtures" 9 | 10 | it "#research" do 11 | compare_static("/help/research") 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/views/members/member_not_found.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, 'Representative or Senator not found' 2 | %h1= yield :title 3 | 4 | No Representative or Senator found. If you entered a postcode, please make 5 | sure it is correct. Or you can 6 | = link_to "browse All Representatives", members_path(house: "representatives") 7 | or #{link_to "browse all Senators", members_path(house: "senate")}. 8 | -------------------------------------------------------------------------------- /db/migrate/20140828053926_rename_division_date_number_name_in_divisions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameDivisionDateNumberNameInDivisions < ActiveRecord::Migration 4 | def change 5 | rename_column :divisions, :division_date, :date 6 | rename_column :divisions, :division_number, :number 7 | rename_column :divisions, :division_name, :name 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20140905062045_remove_limits_from_fields_on_offices.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveLimitsFromFieldsOnOffices < ActiveRecord::Migration 4 | def change 5 | change_column :offices, :dept, :string, limit: nil 6 | change_column :offices, :position, :string, limit: nil 7 | change_column :offices, :responsibility, :string, limit: nil 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/views/devise/mailer/reset_password_instructions.text.erb: -------------------------------------------------------------------------------- 1 | <%= @resource.name %>, someone has requested a link to change your password. You can do this through the link below. 2 | 3 | <%= edit_password_url(@resource, reset_password_token: @token) %> 4 | 5 | If you didn't request this, please ignore this email. 6 | 7 | Your password won't change until you access the link above and create a new one. 8 | -------------------------------------------------------------------------------- /db/migrate/20140928235604_create_people.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreatePeople < ActiveRecord::Migration 4 | def change 5 | create_table :people, &:timestamps 6 | # Create all the people 7 | Person.reset_column_information 8 | Member.group(:person_id).pluck(:person_id).each do |person_id| 9 | Person.create!(id: person_id) 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20220202004503_add_staff_option_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddStaffOptionToUsers < ActiveRecord::Migration[6.0] 2 | def change 3 | # Used to show to the public whether a user is currently (or a past) staff member of the OpenAustralia Foundation 4 | # This is to add extra weight to edits made by those people 5 | add_column :users, :staff, :boolean, null: false, default: false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/factories/whips.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :whip do 5 | division 6 | sequence(:party) { |n| "Party #{n}" } 7 | aye_votes { 0 } 8 | aye_tells { 0 } 9 | no_votes { 0 } 10 | no_tells { 0 } 11 | both_votes { 0 } 12 | abstention_votes { 0 } 13 | possible_votes { 0 } 14 | whip_guess { "unknown" } 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/models/api_statistic.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApiStatistic < ApplicationRecord 4 | belongs_to :user 5 | 6 | def self.log(request) 7 | create!( 8 | user: User.find_by(api_key: request.query_parameters["key"]), 9 | ip_address: request.remote_ip, 10 | query: request.fullpath, 11 | user_agent: request.headers["User-Agent"] 12 | ) 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20141001030631_change_division_binary_columns_to_text.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangeDivisionBinaryColumnsToText < ActiveRecord::Migration 4 | def change 5 | change_column :divisions, :source_url, :text 6 | change_column :divisions, :debate_url, :text 7 | change_column :divisions, :motion, :text 8 | change_column :divisions, :notes, :text 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/views/divisions/_summary_whip_vote.html.haml: -------------------------------------------------------------------------------- 1 | %tr.member-row{class: member_row_class(vote, whip)} 2 | %th.cell-name 3 | = link_to vote.member.name, member_path_simple(vote.member) 4 | %span.text-muted.member-electorate= vote.member.electorate 5 | %small.post-title.text-muted= vote.member.party_name if whip.whipless? || whip.possible_votes == 1 6 | %td.cell-vote= vote_display vote.vote 7 | %td.cell-toggler 8 | -------------------------------------------------------------------------------- /app/views/layouts/_bootstrap_flash.html.haml: -------------------------------------------------------------------------------- 1 | - flash.each do |name, msg| 2 | - if msg.is_a?(String) 3 | %div{class: "alert-container alert-" + (name.to_s == "notice" ? "success" : "danger")} 4 | %div{class: "container alert alert-" + (name.to_s == "notice" ? "success" : "danger")} 5 | %button.close(type="button" data-dismiss="alert" aria-hidden="true") × 6 | %div{id: "flash_#{name}"}= msg 7 | -------------------------------------------------------------------------------- /spec/factories/offices.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :office do 5 | # TODO: Get rid of dept and responsibility in the schema 6 | dept { "" } 7 | responsibility { "" } 8 | position { "Minister for ponies" } 9 | # TODO: Make person_id null: false in the schema 10 | # We are pretending this has already been done here 11 | person 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/views/policies/_division_edit_instructions.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | To select votes for this policy, 3 | = link_to "search", search_path 4 | or 5 | = link_to "browse", divisions_path 6 | for divisions. On the page for each division you can choose how somebody 7 | supporting this policy would have voted. If you haven't edited a policy 8 | before please #{link_to "read about how policies work", help_faq_path(anchor: "policies")}. 9 | -------------------------------------------------------------------------------- /app/views/policies/_not_a_crystal_ball_warning.html.haml: -------------------------------------------------------------------------------- 1 | .row.alert.alert-warning{role: "alert"} 2 | %span.fi-flag 3 | %strong 4 | Be careful! 5 | Without a magic crystal ball, there's no way to predict with absolute certainty what representatives will do in future, no matter what they promise you now or how they voted in the past. 6 | Nonetheless, exploring how they voted before can help you decide who to support in an election. 7 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. 4 | # Use this to limit dissemination of sensitive information. 5 | # See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. 6 | Rails.application.config.filter_parameters += [:password] 7 | -------------------------------------------------------------------------------- /app/assets/stylesheets/global/_history-notice.scss: -------------------------------------------------------------------------------- 1 | .history-notice { 2 | padding: .2em 0; 3 | color: $gray; 4 | background-color: $gray-lighter; 5 | font-size: $font-size-supporting; 6 | 7 | @media (min-width: $screen-sm-min) { 8 | padding: .2em 0; 9 | font-size: $font-size-small; 10 | } 11 | 12 | p { 13 | margin-bottom: 0; 14 | } 15 | 16 | a { 17 | color: $gray; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/lib/templates/erb/scaffold/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%%= simple_form_for(@<%= singular_table_name %>) do |f| %> 2 | <%%= f.error_notification %> 3 | 4 |
5 | <%- attributes.each do |attribute| -%> 6 | <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %> 7 | <%- end -%> 8 |
9 | 10 |
11 | <%%= f.button :submit %> 12 |
13 | <%% end %> 14 | -------------------------------------------------------------------------------- /app/views/api/v1/people/_person.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.id person.id 4 | json.latest_member do 5 | json.id person.latest_member.id 6 | json.name do 7 | json.first person.latest_member.first_name 8 | json.last person.latest_member.last_name 9 | end 10 | json.electorate person.latest_member.electorate 11 | json.house person.latest_member.house 12 | json.party person.latest_member.party 13 | end 14 | -------------------------------------------------------------------------------- /app/views/help/faq/_summaries.md: -------------------------------------------------------------------------------- 1 | When you click on a link for a [division](/divisions), you will be taken to a summary that 2 | will either contain an edited description of the division or a message letting you know that one needs to written. 3 | 4 | Currently, the divisions with edited summaries are those that are relevant to one of 5 | the [Policies](/policies). See our [Research](/help/research) page to find out more about how the 6 | summaries are edited. 7 | -------------------------------------------------------------------------------- /db/migrate/20140828080040_remove_division_date_number_house_from_wiki_motions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveDivisionDateNumberHouseFromWikiMotions < ActiveRecord::Migration 4 | def change 5 | remove_column :wiki_motions, :division_date, :date, null: false 6 | remove_column :wiki_motions, :division_number, :integer, null: false 7 | remove_column :wiki_motions, :house, :string, limit: 8, null: false 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20141008030623_multiple_bills_in_divisions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class MultipleBillsInDivisions < ActiveRecord::Migration 4 | def change 5 | remove_column :divisions, :bill_id, :string 6 | remove_column :divisions, :bill_url, :text 7 | create_table :bills do |t| 8 | t.string :official_id 9 | t.text :url 10 | t.timestamps 11 | end 12 | create_join_table :divisions, :bills 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/views/application/_honeybadger_javascript.html.haml: -------------------------------------------------------------------------------- 1 | - if Rails.application.credentials.honeybadger&.javascript_api_key 2 | = javascript_include_tag "//js.honeybadger.io/v3.0/honeybadger.min.js" 3 | -# We're using a different API key for the js front end to what's used by the backend 4 | :javascript 5 | Honeybadger.configure({ 6 | apiKey: '#{Rails.application.credentials.honeybadger.javascript_api_key}', 7 | environment: '#{Rails.env}' 8 | }); 9 | -------------------------------------------------------------------------------- /app/views/policies/_new_policy_outro.md: -------------------------------------------------------------------------------- 1 | After a policy is created you will be able to associate it with divisions and select how a supporter of the policy would have voted. <%= inline_project_name %> compares the real votes of MPs to your selections and calculates the voting record for the policy. [Find out more about the process](/help/faq#policies). 2 | 3 | Remember, all policies are public. They are a shared resource to be edited and updated by anyone (like Wikipedia). 4 | -------------------------------------------------------------------------------- /config/initializers/flipper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Flipper::UI.configure do |config| 4 | config.descriptions_source = lambda do |_keys| 5 | # This should be a complete list of all features being currently used in the codebase 6 | { 7 | } 8 | end 9 | 10 | # Defaults to false. Set to true to show feature descriptions on the list 11 | # page as well as the view page. 12 | config.show_feature_description_in_list = true 13 | end 14 | -------------------------------------------------------------------------------- /app/lib/data_loader/debates_xml.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DataLoader 4 | class DebatesXml 5 | def initialize(xml_document, house) 6 | @xml_document = xml_document 7 | raise "Debate data missing" unless @xml_document.at(:debates) 8 | 9 | @house = house 10 | end 11 | 12 | def divisions 13 | @xml_document.search(:division).map { |division| DivisionXml.new(division, @house) } 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /config/database.yml.example: -------------------------------------------------------------------------------- 1 | # Copy this to database.yml and edit 2 | 3 | development: 4 | adapter: mysql2 5 | database: pw 6 | username: pw 7 | password: 8 | 9 | # Warning: The database defined as "test" will be erased and 10 | # re-generated from your development database when you run "rake". 11 | # Do not set this db to the same as development or production. 12 | test: 13 | adapter: mysql2 14 | database: pw_test 15 | username: pw_test 16 | password: 17 | -------------------------------------------------------------------------------- /app/views/divisions/_summary_whip_absent.html.haml: -------------------------------------------------------------------------------- 1 | %tr.member-row{class: [('collapse party-member-row' unless whip.whipless? || whip.possible_votes == 1), ('member-row-' + whip.party.parameterize)]} 2 | %th.cell-name 3 | = link_to member.name, member_path_simple(member) 4 | %span.text-muted.member-electorate= member.electorate 5 | %small.post-title.text-muted= member.party_name if whip.whipless? || whip.possible_votes == 1 6 | %td.cell-vote Absent 7 | %td.cell-toggler 8 | -------------------------------------------------------------------------------- /bin/rspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # This file was generated by Bundler. 5 | # 6 | # The application 'rspec' is installed as part of a gem, and 7 | # this file is here to facilitate running it. 8 | # 9 | 10 | require "pathname" 11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 12 | Pathname.new(__FILE__).realpath) 13 | 14 | require "rubygems" 15 | require "bundler/setup" 16 | 17 | load Gem.bin_path("rspec-core", "rspec") 18 | -------------------------------------------------------------------------------- /app/views/divisions/_divisions.html.haml: -------------------------------------------------------------------------------- 1 | - if divisions.to_a.empty? 2 | - if members.count == 1 3 | %p 4 | No votes listed as 5 | = member_type_party_place_sentence(members.first) 6 | - else 7 | %p No votes listed 8 | 9 | - else 10 | %ol.divisions-list.list-unstyled{class: active_house_for_list_class(house)} 11 | - divisions.each do |division| 12 | = render partial: 'divisions/division', locals: {members: members, house: house, division: division} 13 | -------------------------------------------------------------------------------- /app/views/home/_policies.html.haml: -------------------------------------------------------------------------------- 1 | - # Refactor: this is identical to a partial in policies, execept for the header level 2 | %ul.list-unstyled 3 | - policies.each do |policy| 4 | %li 5 | %h3 6 | = link_to capitalise_initial_character(policy.name_with_for), policy 7 | %small 8 | = pluralize(policy.divisions.count, "division") 9 | - if policy.unedited_motions_count != 0 10 | %em= "(#{policy.unedited_motions_count} unedited)" 11 | -------------------------------------------------------------------------------- /app/views/home/about.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "About" 2 | - set_meta_tags description: default_meta_description 3 | 4 | - content_for :header do 5 | .section-header.clearfix 6 | .page-header.container 7 | %h1= yield :title 8 | %p.lead 9 | Forget what politicians say. What truly matters is what they do. And what they do is vote, to write our laws which affect us all. 10 | 11 | .row 12 | .col-md-8 13 | = render "about" 14 | -------------------------------------------------------------------------------- /app/helpers/votes_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module VotesHelper 4 | def vote_words(vote) 5 | if vote 6 | if vote.rebellion? 7 | "voted #{vote_display(vote.vote)}, rebelling against the #{vote.party_name}" 8 | elsif vote.free_vote? 9 | "voted #{vote_display(vote.vote)} in this free vote" 10 | else 11 | "voted #{vote_display(vote.vote)}" 12 | end 13 | else 14 | "was absent" 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/assets/stylesheets/policies/_policies-list.scss: -------------------------------------------------------------------------------- 1 | .policies-list { 2 | .policy-title { 3 | font-weight: normal; 4 | padding-left: 0; 5 | } 6 | 7 | .policy-subscriber-count { 8 | padding-left: 0; 9 | margin-bottom: 0; 10 | } 11 | 12 | .policy-data { 13 | margin-top: 0; 14 | } 15 | 16 | .policy-edit-notice, .object-secondary .policy-subscriber-count { 17 | &:before { 18 | content: "\00a0\25CF\00a0"; 19 | color: #aaa; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/views/policies/_how_the_number_is_calculated.html.haml: -------------------------------------------------------------------------------- 1 | %section.page-section#ratioexpl 2 | %h2 3 | How 4 | "#{policy_agreement_summary(policy_person_distance)}" 5 | is worked out 6 | 7 | - if policy_person_distance.category == :not_enough 8 | = render "policies/how_the_number_is_calculated/not_enough", policy_person_distance: policy_person_distance 9 | - else 10 | = render "policies/how_the_number_is_calculated/other", policy_person_distance: policy_person_distance 11 | -------------------------------------------------------------------------------- /db/migrate/20140917011343_create_versions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateVersions < ActiveRecord::Migration 4 | def change 5 | create_table :versions do |t| 6 | t.string :item_type, null: false 7 | t.integer :item_id, null: false 8 | t.string :event, null: false 9 | t.string :whodunnit 10 | t.text :object 11 | t.datetime :created_at 12 | end 13 | add_index :versions, %i[item_type item_id] 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/views/api/v1/divisions/_division.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.id division.id 4 | json.house division.house 5 | json.name division.name 6 | json.date division.date 7 | json.number division.number 8 | json.clock_time(division.clock_time&.strip) 9 | json.aye_votes division.aye_votes 10 | json.no_votes division.no_votes 11 | json.possible_turnout division.division_info.possible_turnout 12 | json.rebellions division.division_info.rebellions 13 | json.edited division.edited? 14 | -------------------------------------------------------------------------------- /app/views/divisions/_external_links.html.haml: -------------------------------------------------------------------------------- 1 | %nav.division-external-links.page-section 2 | %h2.h5 External links 3 | %ul.list-unstyled.object-list-compact 4 | %li.object-item= link_to "Debate in Parliament", division.debate_url, title: "Links to debate shown at www.openaustralia.org" 5 | %li.object-item= link_to "Hansard source", division.source_url, title: "The original record of vote as reported by Hansard" 6 | - division.bills.each do |bill| 7 | %li.object-item= link_to bill.title, bill.url 8 | -------------------------------------------------------------------------------- /local_dev/roles/docker/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | docker_ubuntu_gpg_url: 'https://download.docker.com/linux/ubuntu/gpg' 3 | docker_ubuntu_gpg_text_path: '/tmp/docker-archive-keyring.gpg' 4 | docker_ubuntu_gpg_keyring_path: '/usr/share/keyrings/docker-archive-keyring.gpg' 5 | docker_ubuntu_apt_url: 'https://download.docker.com/linux/ubuntu' 6 | docker_ubuntu_apt_arch: 'amd64' # {{ ansible_architecture | lower }} - this gives 'x86_64', which is not valid 7 | docker_ubuntu_apt_dist: '{{ ansible_distribution_release | lower }}' 8 | -------------------------------------------------------------------------------- /app/views/help/faq/_division.md: -------------------------------------------------------------------------------- 1 | A division is a formal vote on a motion in the House of Representatives or the Senate. A motion is 2 | a formal proposal put to the House or Senate to take action of some kind. 3 | 4 | When a division is called on a particular motion, Members of Parliament (MPs) in the House of 5 | Representatives or Senators in the Senate divide themselves into two groups: one that votes 6 | Yes and one that votes No. Each political party has whips who try to persuade their members 7 | to vote along party lines. 8 | -------------------------------------------------------------------------------- /app/views/home/_search_form.html.haml: -------------------------------------------------------------------------------- 1 | %form.form-inline.search{action: search_path, name: "pw"} 2 | .input-group.col-sm-12.col-md-8.col-lg-7 3 | %label.sr-only{for: "query"} Search 4 | %input.form-control#query{type: "search", autosave: "#{Rails.configuration.project_name}", autofocus: (params[:query].blank? ? true : false), maxlength: "256", name: "query", value: "#{params[:query] if !params[:query].blank?}"}/ 5 | .input-group-btn 6 | %input.btn.btn-primary{name: "button", type: "submit", value: "Search"}/ 7 | -------------------------------------------------------------------------------- /app/views/help/style_guide.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Style Guide" 2 | - set_meta_tags description: "A guide to the style to use when contributing to #{Rails.configuration.project_name}." 3 | 4 | 5 | - content_for :header do 6 | .section-header.clearfix 7 | .page-header.container 8 | %h1= yield :title 9 | %p.lead #{inline_project_name} is for everyone. It should be easy for everyone to find out how their MP votes in Parliament. 10 | 11 | .row 12 | .col-md-8 13 | =render "help/style_guide_copy" 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | init-submodules: 3 | git submodule update --init --recursive 4 | 5 | install-ruby: 6 | rbenv install < .ruby-version 7 | 8 | deploy-production: 9 | bundle exec cap production deploy 10 | deploy-staging: 11 | bundle exec cap staging deploy 12 | 13 | dev-services-up: 14 | COMPOSE_PROJECT_NAME=theyvoteforyou-dev docker compose -f docker-stack/dev/docker-compose.yml up --build -d 15 | test-services-up: 16 | COMPOSE_PROJECT_NAME=theyvoteforyou-test docker compose -f docker-stack/test/docker-compose.yml up --build -d 17 | -------------------------------------------------------------------------------- /app/assets/images/check-green.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /app/views/help/faq/_decisions.md: -------------------------------------------------------------------------------- 1 | <%= inline_project_name %> is concerned with the voting patterns of politicians, which means it is limited to 2 | formal votes (known as divisions, see [What is a division?](#division)). This is because 3 | politicians’ names and how they voted are only recorded in the official record of Parliament 4 | (known as the Hansard) when a division occurs. 5 | 6 | Unfortunately, most decisions in Parliament are not made by division 7 | (see [When does a division occur?](#division-occur)) and so do not appear on this site. 8 | -------------------------------------------------------------------------------- /app/views/help/research.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Parliamentary Research" 2 | - set_meta_tags description: "A guide on how to contribute to #{Rails.configuration.project_name} by researching policies and divisions." 3 | 4 | - content_for :header do 5 | .section-header.clearfix 6 | .page-header.container 7 | %h1= yield :title 8 | %p.lead 9 | A guide on how to contribute to #{inline_project_name} by researching policies and divisions. 10 | 11 | .row 12 | .col-md-8 13 | = render "help/research_copy" 14 | -------------------------------------------------------------------------------- /config/initializers/cors.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Avoid CORS issues when API is called from the frontend app. 4 | # Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin Ajax requests. 5 | 6 | # Read more: https://github.com/cyu/rack-cors 7 | 8 | Rails.application.config.middleware.insert_before 0, Rack::Cors do 9 | allow do 10 | origins "*" 11 | # Only allow GET requests on the API 12 | resource "*", headers: :any, methods: [:get] 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/factories/divisions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :division do 5 | date { Date.new(2014, 1, 1) } 6 | sequence(:number) { |n| n } 7 | house { "representatives" } 8 | name { "Some division" } 9 | motion { "I move that this division be very, very interesting" } 10 | source_url { "http://parlinfo.aph.gov.au/foobar" } 11 | debate_url { "http://parlinfo.aph.gov.au/bazbar" } 12 | debate_gid { "uk.org.publicwhip/representatives/2014-01-1.1.1" } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/mailers/regression/alert_mailer/email1.txt: -------------------------------------------------------------------------------- 1 | For red being a nice colour 2 | http://pw.org.au/policies/50 3 | 4 | Created policy “red being a nice colour” with description “there should be fabulous test policies”. 5 | 6 | By Wibble at 12:00AM - 01 Jan 2020 7 | http://pw.org.au/users/200 8 | 9 | ------------------------------------------------------ 10 | 11 | Visit the policy page to unsubscribe from this policy: 12 | http://pw.org.au/policies/50 13 | 14 | View all your subscriptions: 15 | http://pw.org.au/users/100/subscriptions 16 | -------------------------------------------------------------------------------- /app/views/members/_recent_votes.html.haml: -------------------------------------------------------------------------------- 1 | %section.page-section#recent-votes 2 | %h2 Recent Votes 3 | 4 | %p 5 | Recent votes in parliament that this 6 | = member_type(member.house) 7 | could have attended. 8 | 9 | - member.person.members.order(entered_house: :desc).each do |member| 10 | = render "divisions/divisions", members: [member], divisions: member.divisions_they_could_have_attended.limit(3), house: nil 11 | 12 | =link_to "View all votes", member_divisions_path_simple(member), class: 'btn btn-default btn-sm' 13 | -------------------------------------------------------------------------------- /app/mailers/alert_mailer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AlertMailer < ApplicationMailer 4 | default from: "#{Rails.configuration.project_name} <#{Rails.configuration.contact_email}>" 5 | layout "email" 6 | helper PoliciesHelper, DivisionsHelper, PathHelper 7 | 8 | def policy_updated(policy, version, user) 9 | @policy = policy 10 | @version = version 11 | @user = user 12 | 13 | mail to: user.email, subject: render_to_string(partial: "policy_updated_subject", locals: { policy: @policy }).strip 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/views/help/faq/_policies_license.md: -------------------------------------------------------------------------------- 1 | Policy information is licensed under the [Creative Commons Attribution 4.0 International](http://creativecommons.org/licenses/by/4.0/) license. 2 | This allows the information to be used and shared by anyone as long as they attribute its source. 3 | This ensures its widest possible use. 4 | 5 | Anyone who contributes to the creation or editing of a policy is also agreeing to their contribution 6 | being licensed under the [Creative Commons Attribution 4.0 International](http://creativecommons.org/licenses/by/4.0/) license. 7 | -------------------------------------------------------------------------------- /app/views/users/show.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, @user.name 2 | 3 | %h2 4 | - if @you 5 | Your recent contributions 6 | - else 7 | Recent contributions by 8 | = @user.name 9 | 10 | - if !@you && @user.staff 11 | %p 12 | = @user.name 13 | is an OpenAustralia Foundation staff member 14 | 15 | - if @history.empty? 16 | %p No contributions… yet :) 17 | - else 18 | = render partial: "layouts/history_list", locals: { policy: @policy, history: @history } 19 | 20 | %p See other #{link_to 'recent changes', history_path}. 21 | -------------------------------------------------------------------------------- /spec/mailers/regression/alert_mailer/email2.txt: -------------------------------------------------------------------------------- 1 | For red being a nice colour 2 | http://pw.org.au/policies/50 3 | 4 | Changed text on related division: An edited division 5 | http://pw.org.au/divisions/representatives/2014-01-01/1 6 | 7 | By Wibble at 01:01AM - 01 Jan 2014 8 | http://pw.org.au/users/200 9 | 10 | ------------------------------------------------------ 11 | 12 | Visit the policy page to unsubscribe from this policy: 13 | http://pw.org.au/policies/50 14 | 15 | View all your subscriptions: 16 | http://pw.org.au/users/100/subscriptions 17 | -------------------------------------------------------------------------------- /app/assets/images/cross-red.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/views/members/_summary.html.haml: -------------------------------------------------------------------------------- 1 | %p.member-description 2 | - if !member.person.current_offices.empty? 3 | = member.name 4 | is 5 | -# TODO: The UK uses extra Offices data like department so this will need to be expanded 6 | %span.role= member.person.current_offices.map{|o| content_tag(:em, o.position) }.to_sentence(two_words_connector: ", and ").html_safe + "." 7 | 8 | - # TODO: add back in the rebellion and attendance rate for previous membership. 9 | - if member.person.members.size > 1 10 | = member_history_sentence(member) 11 | -------------------------------------------------------------------------------- /app/views/people_distances/_comparison_block.html.haml: -------------------------------------------------------------------------------- 1 | - unless policies.empty? 2 | .policy-comparision-block.col-md-7{class: "compare-#{label}"} 3 | .row 4 | %h3.policy-comparision-position.col-xs-9= title 5 | .row 6 | %ul.policy-comparision-list.object-list-compact.list-unstyled.col-xs-12 7 | - policies.each do |policy| 8 | %li.policy-comparision-policy.object-item 9 | = link_to capitalise_initial_character(policy.name), compare_member_policy_path_simple(person_distance, policy), class: "policy-title" 10 | -------------------------------------------------------------------------------- /app/views/application/_swag.html.haml: -------------------------------------------------------------------------------- 1 | -# TODO: Make buy experience work without leaving the site 2 | - unless cookies[:tvfy_swag] == "false" 3 | = link_to "https://swag.theyvoteforyou.org.au/products/short-sleeve-t-shirt" do 4 | .swag.alert.fade.in 5 | %button.close{"aria-label": "Close", "data-dismiss": "alert", type: "button"} 6 | %span{"aria-hidden": "true"} × 7 | = image_tag "tshirt.svg" 8 | .swag-text 9 | Because nothing says "I care about being informed" like a killer t-shirt. 10 | %strong Get it now! 11 | 12 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = "1.0" 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in the app/assets 11 | # folder are already added. 12 | Rails.application.config.assets.precompile += %w( email.css ) 13 | -------------------------------------------------------------------------------- /app/views/devise/passwords/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, 'Change your password' 2 | 3 | %h2= yield :title 4 | 5 | = form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| 6 | = devise_error_messages! 7 | = f.hidden_field :reset_password_token 8 | .form-group 9 | = f.label :password, "New password" 10 | = f.password_field :password, autofocus: true, autocomplete: "off", class: "form-control" 11 | 12 | = f.submit "Change my password", class: "btn btn-default" 13 | = render "devise/shared/links" 14 | -------------------------------------------------------------------------------- /app/views/people_distances/_member.html.haml: -------------------------------------------------------------------------------- 1 | - if member.show_large_image? 2 | = link_to member_path_simple(member), class: "pull-left" do 3 | = image_tag(member.large_image_url, alt: "Photo of #{member.name}", size: member.large_image_size, class: "media-object photo") 4 | .media-body 5 | %h2.media-heading 6 | %span.fn= link_to_unless_current member.name, member_path_simple(member) 7 | %p.member-role.lead 8 | = member_type_party_place_sentence(member) 9 | %span.member-period 10 | = formatted_date_range(member.date_range, format: :short) 11 | -------------------------------------------------------------------------------- /config/initializers/permissions_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide HTTP permissions policy. For further 4 | # information see: https://developers.google.com/web/updates/2018/06/feature-policy 5 | 6 | # Rails.application.config.permissions_policy do |policy| 7 | # policy.camera :none 8 | # policy.gyroscope :none 9 | # policy.microphone :none 10 | # policy.usb :none 11 | # policy.fullscreen :self 12 | # policy.payment :self, "https://secure.example.com" 13 | # end 14 | -------------------------------------------------------------------------------- /local_dev/roles/ruby/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ruby_rbenv_git_url: 'https://github.com/rbenv/rbenv.git' 3 | ruby_rbenv_path: '/home/vagrant/.rbenv' 4 | ruby_rbenv_plugins_path: '{{ ruby_rbenv_path }}/plugins' 5 | 6 | ruby_rbenv_bash_path: '/home/vagrant/.bashrc' 7 | 8 | ruby_rbenv_build_git_url: 'https://github.com/rbenv/ruby-build.git' 9 | ruby_rbenv_build_path: '{{ ruby_rbenv_plugins_path }}/ruby-build' 10 | 11 | ruby_rbenv_doctor_url: 'https://github.com/rbenv/rbenv-installer/raw/HEAD/bin/rbenv-doctor' 12 | ruby_rbenv_doctor_path: '/home/vagrant/rbenv-doctor.sh' 13 | -------------------------------------------------------------------------------- /db/migrate/20140828062935_add_division_id_to_policy_divisions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddDivisionIdToPolicyDivisions < ActiveRecord::Migration 4 | def change 5 | add_column :policy_divisions, :division_id, :integer 6 | PolicyDivision.reset_column_information 7 | PolicyDivision.all.find_each do |pd| 8 | division = Division.find_by!(date: pd.read_attribute(:division_date), number: pd.read_attribute(:division_number), house: pd.read_attribute(:house)) 9 | pd.update!(division_id: division.id) 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/assets/images/generic-person.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /db/migrate/20220413041820_create_people_distances.rb: -------------------------------------------------------------------------------- 1 | class CreatePeopleDistances < ActiveRecord::Migration[6.0] 2 | def change 3 | create_table :people_distances do |t| 4 | t.integer :person1_id, null: false 5 | t.integer :person2_id, null: false 6 | t.integer :nvotessame, null: false 7 | t.integer :nvotesdiffer, null: false 8 | t.float :distance_b, null: false 9 | t.timestamps 10 | 11 | t.index :person1_id 12 | t.index :person2_id 13 | t.index [:person1_id, :person2_id], unique: true 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: bundler # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /app/assets/stylesheets/people_distances/_people_distances.scss: -------------------------------------------------------------------------------- 1 | .policy-comparision-block { 2 | &.compare-always-same { 3 | border-top-color: $color-for3; 4 | color: $color-for3; 5 | } 6 | 7 | &.compare-mixture { 8 | border-top-color: $color-mixed-position; 9 | color: $color-mixed-position; 10 | } 11 | 12 | &.compare-always-different { 13 | border-top-color: $color-against3; 14 | color: $color-against3; 15 | } 16 | } 17 | 18 | .compare-policies-intro { 19 | margin-bottom: 2em; 20 | } 21 | 22 | .btn.compare-others { 23 | margin-bottom: 2em; 24 | } 25 | -------------------------------------------------------------------------------- /app/views/home/history.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, 'Recent edits' 2 | - set_meta_tags description: "Recent edits to divisions and policies by the #{Rails.configuration.project_name} community." 3 | - content_for :header do 4 | .section-header.clearfix 5 | .page-header.container 6 | %h1 All edits made in the last week 7 | 8 | - if @history.empty? 9 | %p None yet… you can kick things off and see your name here by #{link_to "summarising divisions", help_research_path}. 10 | - else 11 | = render partial: "layouts/history_list", locals: { policy: @policy, history: @history } 12 | -------------------------------------------------------------------------------- /spec/fixtures/static_pages/feeds/mpdream-info.xml__id=1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code 7 | # by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'". 8 | Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"] 9 | -------------------------------------------------------------------------------- /db/migrate/20140828074700_add_division_id_to_wiki_motions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddDivisionIdToWikiMotions < ActiveRecord::Migration 4 | def change 5 | add_column :wiki_motions, :division_id, :integer 6 | add_index :wiki_motions, :division_id 7 | WikiMotion.reset_column_information 8 | WikiMotion.all.find_each do |w| 9 | division = Division.find_by!(date: w.division_date, number: w.division_number, house: w.house) 10 | # I don't want callbacks called 11 | w.update_attribute(:division_id, division.id) 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/assets/javascripts/policies.js: -------------------------------------------------------------------------------- 1 | // Place all the behaviors and hooks related to the matching controller here. 2 | // All this logic will automatically be available in application.js. 3 | 4 | $(function() { 5 | $(".policy-name, .policy-comparision-position").widowFix({ 6 | letterLimit: 10, 7 | prevLimit: 11 8 | }); 9 | if ((typeof changeSubscribeButtons !== "undefined" && changeSubscribeButtons !== null) && document.getElementsByClassName("subscribe-button-form-unsubscribe").length > 0) { 10 | return changeSubscribeButtons("Subscribed", "subscribe-button-active"); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /app/assets/stylesheets/global/_utilities.scss: -------------------------------------------------------------------------------- 1 | .lazy { 2 | display: none !important; 3 | 4 | .has-js & { 5 | display: inherit !important; 6 | } 7 | } 8 | 9 | /** 10 | * Breakpoint definition for JS - see https://github.com/JoshBarr/on-media-query 11 | * used by onmediaquery.js 12 | */ 13 | 14 | body:after { 15 | display: none; 16 | 17 | content: 'small'; 18 | 19 | @media (min-width: $screen-md-min) { 20 | content: 'wide'; 21 | } 22 | } 23 | 24 | html { 25 | font-family: 'small'; 26 | 27 | @media (min-width: $screen-md-min) { 28 | font-family: 'wide'; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/views/divisions/_summary_whip.html.haml: -------------------------------------------------------------------------------- 1 | = render 'summary_whip_header', whip: whip 2 | 3 | -# Show members in this party that are present in this division 4 | - votes.select {|vote| vote.member.party == whip.party}.each do |vote| 5 | = render 'summary_whip_vote', vote: vote, whip: whip 6 | 7 | - # TODO: Order by minority within party (e.g. rebels first) then majority, then absent 8 | -# Show members in this party that are absent in this division 9 | - members_vote_null.select {|member| member.party == whip.party}.each do |member| 10 | = render 'summary_whip_absent', member: member, whip: whip 11 | -------------------------------------------------------------------------------- /db/migrate/20150617030311_convert_tables_to_utf8_character_set.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ConvertTablesToUtf8CharacterSet < ActiveRecord::Migration 4 | def up 5 | ActiveRecord::Base.connection.tables.each do |table_name| 6 | ActiveRecord::Base.connection.execute "ALTER TABLE #{table_name} CONVERT TO CHARACTER SET utf8" 7 | end 8 | end 9 | 10 | def down 11 | ActiveRecord::Base.connection.tables.each do |table_name| 12 | ActiveRecord::Base.connection.execute "ALTER TABLE #{table_name} CONVERT TO CHARACTER SET latin1" 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /bin/yarn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_ROOT = File.expand_path('..', __dir__) 3 | Dir.chdir(APP_ROOT) do 4 | yarn = ENV["PATH"].split(File::PATH_SEPARATOR). 5 | select { |dir| File.expand_path(dir) != __dir__ }. 6 | product(["yarn", "yarn.cmd", "yarn.ps1"]). 7 | map { |dir, file| File.expand_path(file, dir) }. 8 | find { |file| File.executable?(file) } 9 | 10 | if yarn 11 | exec yarn, *ARGV 12 | else 13 | $stderr.puts "Yarn executable was not detected in the system." 14 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" 15 | exit 1 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/factories/members.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :member do 5 | gid { "uk.org.publicwhip/lord/100156" } 6 | source_gid { "" } 7 | first_name { "Christine" } 8 | last_name { "Milne" } 9 | sequence(:title) { |n| "Title #{n}" } 10 | constituency { "Newtown" } 11 | party { "Australian Greens" } 12 | house { "representatives" } 13 | entered_house { "2005-07-01" } 14 | left_house { "9999-12-31" } 15 | entered_reason { "general_election" } 16 | left_reason { "still_in_office" } 17 | person 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/assets/javascripts/divisions.js: -------------------------------------------------------------------------------- 1 | // Place all the behaviors and hooks related to the matching controller here. 2 | // All this logic will automatically be available in application.js. 3 | 4 | $(function() { 5 | $("form.edit_division a#preview_link").on("shown.bs.tab", function(e) { 6 | return $("#preview").html(marked($("#edit textarea").val())); 7 | }); 8 | $(".division-title").widowFix({ 9 | letterLimit: 10, 10 | prevLimit: 11 11 | }); 12 | return $(".voter-table-toggle-members").click(function() { 13 | return $(this).toggleClass("voter-table-toggle-members-active"); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /app/views/divisions/_header.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title do 2 | = truncate(division.name, length: 180) 3 | 4 | .page-header.division-header.row 5 | %nav.header-actions.col-md-1.col-lg-2 6 | - if policy(division).edit? 7 | = link_to "Edit", edit_division_path_simple(division), title: "Change title and summary of this division", class: "link-division-edit btn btn-default btn-xs" 8 | 9 | %h1.division-title.col-md-11.col-lg-10.long-title 10 | %small.pre-title= division_date_and_time(division) + " – " + division.house_name 11 | = link_to_unless_current yield(:title), division_path_simple(division) 12 | -------------------------------------------------------------------------------- /app/views/layouts/_history_notice.html.haml: -------------------------------------------------------------------------------- 1 | .history-notice 2 | %p.container 3 | -if division 4 | = link_to "Division last edited #{relative_time division.wiki_motion.created_at}", history_division_path_simple(division), title: "View the edit history of this division." 5 | -elsif policy 6 | = link_to "Policy last edited #{time_ago_in_words(policy.last_edited_at)} ago", history_policy_path(policy), title: "View the edit history of this policy." 7 | by 8 | -if division 9 | = name_with_badge(division.wiki_motion.user) 10 | -elsif policy 11 | = name_with_badge(policy.last_edited_by) 12 | -------------------------------------------------------------------------------- /app/views/application/_plausible_analytics.html.haml: -------------------------------------------------------------------------------- 1 | - if Rails.env.production? 2 | -# plausible.io analytics 3 | -# In planningalerts.org.au we implemented a thing where the pageview path was given as a rails route path effectively bundling all 4 | -# similar pages together. We can't do that here yet because the implementation in planningalerts requires request.route_uri_pattern 5 | -# which is only available from rails 7.1. So, for the time being just do the simple thing 6 | -# TODO: Upgrade to rails 7.1 or above 7 | = javascript_include_tag "/js/script.outbound-links.js", defer: true, data: {domain: "theyvoteforyou.org.au"} 8 | -------------------------------------------------------------------------------- /app/views/feeds/mpdream_info.xml.builder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | xml.instruct! :xml, version: "1.0", encoding: "ISO-8859-1" 4 | xml.publicwhip do 5 | @policy_person_distances.each do |pmd| 6 | xml.memberinfo("id" => "uk.org.publicwhip/member/#{pmd['member_id']}", 7 | "public_whip_dreammp#{@policy.id}_distance" => number_with_precision(pmd["distance_a"], precision: 99, strip_insignificant_zeros: true), 8 | "public_whip_dreammp#{@policy.id}_both_voted" => pmd["both_voted"], 9 | "public_whip_dreammp#{@policy.id}_absent" => pmd["absent"]) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20140821075351_drop_unused_tables_in_rails.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DropUnusedTablesInRails < ActiveRecord::Migration 4 | def change 5 | drop_table :pw_cache_attendrank_today 6 | drop_table :pw_cache_divdiv_distance 7 | drop_table :pw_cache_dreaminfo 8 | drop_table :pw_cache_partyinfo 9 | drop_table :pw_cache_rebelrank_today 10 | drop_table :pw_candidate 11 | drop_table :pw_dyn_aggregate_dreammp 12 | drop_table :pw_dyn_auditlog 13 | drop_table :pw_dyn_newsletter 14 | drop_table :pw_dyn_newsletters_sent 15 | drop_table :pw_logincoming 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/views/devise/mailer/confirmation_instructions.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :subject, "Confirm your email address" 2 | 3 | %tr 4 | %td.content-block 5 | #{@resource.name}, you are one step away from creating your account on 6 | %em= Rails.configuration.project_name 7 | %tr 8 | %td.content-block 9 | Please confirm your email address by clicking the link below 10 | %tr 11 | %td.content-block 12 | = link_to "Confirm email address", confirmation_url(@resource, confirmation_token: @token), class: "btn-primary" 13 | %tr 14 | %td.content-block 15 | — The 16 | %em= Rails.configuration.project_name 17 | team 18 | -------------------------------------------------------------------------------- /local_dev/roles/app/templates/database.yml: -------------------------------------------------------------------------------- 1 | # Database connections 2 | 3 | development: 4 | adapter: mysql2 5 | pool: 5 6 | host: '127.0.0.1' 7 | port: 3306 8 | database: pw 9 | username: root 10 | password: '{{ mysql_root_password }}' 11 | 12 | # Warning: The database defined as "test" will be erased and 13 | # re-generated from your development database when you run "rake". 14 | # Do not set this db to the same as development or production. 15 | test: 16 | adapter: mysql2 17 | pool: 5 18 | host: '127.0.0.1' 19 | port: 3306 20 | database: pw_test 21 | username: root 22 | password: '{{ mysql_root_password }}' 23 | -------------------------------------------------------------------------------- /app/views/api/v1/people/_docs_index.md: -------------------------------------------------------------------------------- 1 | <% if current_user %> 2 |
GET <%= link_to api_v1_people_url(format: "json", key: current_user.api_key), api_v1_people_url(format: "json", key: current_user.api_key) %>
3 | <% else %> 4 |
GET <%= api_v1_people_url(format: "json", key: "foo").gsub("foo", "[api_key]") %>
5 | <% end %> 6 | 7 | This returns basic information about each person who is currently a member of parliament. It 8 | includes their name, electorate, party and whether they are in the House of Representatives or the 9 | Senate. 10 | 11 | To get more detailed information about a person use the `id` to do the following: 12 | -------------------------------------------------------------------------------- /app/views/divisions/index_with_member.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title do 2 | Voting Record — 3 | = @member.full_name2 4 | - set_meta_tags description: "A list of all votes in parliament that #{@member.full_name_no_electorate} could have attended." 5 | 6 | = render "members/member_page_header", member: @member 7 | 8 | %h2#divisions 9 | Divisions 10 | %small #{divisions_period(@date_range, @date_start)} 11 | 12 | %p Divisions #{@member.full_name_no_electorate} could have attended. 13 | 14 | = render "divisions", members: [@member], divisions: @divisions, house: @house 15 | = render "pagination", years: @years, date_start: @date_start 16 | -------------------------------------------------------------------------------- /app/views/home/_no_search_results.html.haml: -------------------------------------------------------------------------------- 1 | - if postcode 2 | %h2 3 | Postcode 4 | %strong= postcode 5 | not found 6 | 7 | %p Sorry, we couldn't find that postcode. 8 | %p 9 | If you’re sure this postcode exists please 10 | = mail_to Rails.configuration.contact_email, "contact us" 11 | to let us know. 12 | - else 13 | %h2 No results found 14 | %p 15 | Sorry, we couldn't find any people, policies or divisions relevant to your search term 16 | %strong “#{params[:query]}”. 17 | %p 18 | Suggestions: 19 | 20 | %ul 21 | %li check the spelling 22 | %li try some more general or alternate terms 23 | -------------------------------------------------------------------------------- /db/migrate/20140828071906_drop_division_date_number_house_in_policy_divisions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DropDivisionDateNumberHouseInPolicyDivisions < ActiveRecord::Migration 4 | def change 5 | remove_index :policy_divisions, name: "division_date_2" 6 | add_index :policy_divisions, %i[division_id policy_id], unique: true 7 | add_index :policy_divisions, :division_id 8 | remove_column :policy_divisions, :division_date, :date, null: false 9 | remove_column :policy_divisions, :division_number, :integer, null: false 10 | remove_column :policy_divisions, :house, :string, limit: 8, null: false 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/views/alert_mailer/policy_updated.text.erb: -------------------------------------------------------------------------------- 1 | <%= capitalise_initial_character(@policy.name_with_for) %> 2 | <%= policy_url(@policy) %> 3 | 4 | <% if @version.kind_of?(WikiMotion) %> 5 | Changed text on related division: <%= @version.division.name %> 6 | <%= division_url_simple(@version.division) %> 7 | <% else %> 8 | <%= version_sentence_text(@version) %> 9 | <% end %> 10 | 11 | <%= version_attribution_text(@version) %> 12 | 13 | ------------------------------------------------------ 14 | 15 | Visit the policy page to unsubscribe from this policy: 16 | <%= policy_url(@policy) %> 17 | 18 | View all your subscriptions: 19 | <%= user_subscriptions_url(@user) %> 20 | -------------------------------------------------------------------------------- /app/assets/stylesheets/users/_welcome.scss: -------------------------------------------------------------------------------- 1 | .welcome { 2 | text-align: center; 3 | 4 | .subscriptions-list-intro { 5 | @media (max-width: $screen-md-max) { 6 | text-align: left; 7 | } 8 | } 9 | 10 | .subscriptions-list { 11 | text-align: left; 12 | 13 | @media (min-width: $screen-sm-min) { 14 | margin-top: 30px; 15 | } 16 | } 17 | } 18 | 19 | .welcome-intro { 20 | text-align: center; 21 | 22 | @media (min-width: $screen-xs-min) { 23 | margin-bottom: 30px; 24 | } 25 | 26 | @media (min-width: $screen-md-min) { 27 | margin-top: 60px; 28 | } 29 | } 30 | 31 | .staff.label { 32 | padding-top: 0.5em; 33 | } 34 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class UsersController < ApplicationController 4 | before_action :authenticate_user!, only: %i[subscriptions welcome] 5 | 6 | def show 7 | @user = User.find(params[:id]) 8 | @you = current_user && @user == current_user 9 | @history = @user.recent_changes(20) 10 | end 11 | 12 | def subscriptions 13 | @user = User.find(params[:id]) 14 | end 15 | 16 | def confirm 17 | # Remove Devise flash 18 | flash.delete(:notice) 19 | end 20 | 21 | def welcome 22 | @policies = current_user.unwatched_policies.published.sample(3) 23 | flash.delete(:notice) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /db/migrate/20140930212321_add_timestamps_to_all_tables.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTimestampsToAllTables < ActiveRecord::Migration 4 | def change 5 | add_timestamps :division_infos 6 | add_timestamps :divisions 7 | add_timestamps :electorates 8 | add_timestamps :member_distances 9 | add_timestamps :member_infos 10 | add_timestamps :members 11 | add_timestamps :offices 12 | add_timestamps :policies 13 | add_timestamps :policy_divisions 14 | add_timestamps :policy_person_distances 15 | add_timestamps :users 16 | add_timestamps :votes 17 | add_timestamps :whips 18 | add_timestamps :wiki_motions 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /app/assets/stylesheets/global/_swag.scss: -------------------------------------------------------------------------------- 1 | .swag { 2 | background-color: #101c37; 3 | color: white; 4 | padding: 10px; 5 | text-align: center; 6 | font-size: 20px; 7 | line-height: 26px; 8 | margin-bottom: 0; 9 | border: 0; 10 | border-radius: 0; 11 | :hover { 12 | text-decoration: underline; 13 | } 14 | 15 | .swag-text { 16 | text-align: left; 17 | display: inline-block; 18 | max-width: 280px; 19 | vertical-align: middle; 20 | } 21 | 22 | button.close { 23 | color: white; 24 | opacity: 0.8; 25 | :hover, :focus { 26 | // TODO: Do something designed rather than fairly arbitrary 27 | opacity: 0.6; 28 | } 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /app/lib/party.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Party 4 | attr_accessor :name 5 | 6 | def initialize(params) 7 | @name = params[:name] 8 | end 9 | 10 | def long_name 11 | case name 12 | when "SPK" 13 | "Speaker" 14 | when "CWM" 15 | "Deputy Speaker" 16 | when "PRES" 17 | "President" 18 | when "DPRES" 19 | "Deputy President" 20 | else 21 | name 22 | end 23 | end 24 | 25 | # Does this party not have a whip? 26 | def whipless? 27 | %w[XB Other None SPK CWM DCWM PRES DPRES].include?(name) || 28 | name[0..2] == "Ind" 29 | end 30 | 31 | def subject_to_whip? 32 | !whipless? 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /app/views/layouts/_history_list.html.haml: -------------------------------------------------------------------------------- 1 | %ul.row.list-unstyled 2 | - history.each do |version| 3 | %li.object-item 4 | - if version.kind_of?(WikiMotion) 5 | %p 6 | Changed text on 7 | = link_to version.division.name, division_path_simple(version.division) 8 | 9 | - else 10 | - if !policy 11 | %p.change-policy-name 12 | On policy 13 | = link_to version_policy(version).name, version_policy(version) 14 | 15 | = version_sentence(version) 16 | 17 | %p.small.object-primary.text-muted 18 | = name_with_badge(version_author(version)) 19 | = time_ago_in_words(version.created_at) 20 | ago 21 | -------------------------------------------------------------------------------- /app/views/devise/passwords/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, 'Password reset' 2 | 3 | .thin-page 4 | %h1.long-title= yield :title 5 | 6 | %p Enter your email and we’ll send you intructions to reset your password 7 | 8 | = form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| 9 | = devise_error_messages! 10 | .form-group 11 | = f.label :email 12 | = f.email_field :email, autofocus: true, class: "form-control", required: "required" 13 | 14 | = f.submit "Reset password", class: "btn btn-primary btn-wide" 15 | 16 | %ul.form-secondary.nav.nav-pills 17 | %li= link_to 'Back to log in', new_user_session_path, class: "btn-xs" 18 | -------------------------------------------------------------------------------- /app/views/layouts/card_layout.html.haml: -------------------------------------------------------------------------------- 1 | 2 | !!! 5 3 | %html.no-js(lang="en") 4 | %head 5 | %meta(charset="utf-8") 6 | %meta(name="viewport" content="width=device-width, initial-scale=1") 7 | %meta{:name => "robots", :content => "noindex"} 8 | %title 9 | - if content_for? :title 10 | = yield :title 11 | = "— #{Rails.configuration.project_name}" 12 | - else 13 | #{Rails.configuration.project_name} — How does your MP vote? 14 | 15 | = stylesheet_link_tag "//code.cdn.mozilla.net/fonts/fira.css" 16 | = stylesheet_link_tag "application" 17 | 18 | = csrf_meta_tag 19 | = display_meta_tags 20 | %body{class: "social_media_cards"} 21 | = yield -------------------------------------------------------------------------------- /app/policies/division_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DivisionPolicy < ApplicationPolicy 4 | def update? 5 | user&.staff? 6 | end 7 | 8 | # NOTE: Up to Pundit v2.3.1, the inheritance was declared as 9 | # `Scope < Scope` rather than `Scope < ApplicationPolicy::Scope`. 10 | # In most cases the behavior will be identical, but if updating existing 11 | # code, beware of possible changes to the ancestors: 12 | # https://gist.github.com/Burgestrand/4b4bc22f31c8a95c425fc0e30d7ef1f5 13 | 14 | class Scope < ApplicationPolicy::Scope 15 | # NOTE: Be explicit about which records you allow access to! 16 | # def resolve 17 | # scope.all 18 | # end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /db/migrate/20211223050627_create_flipper_tables.rb: -------------------------------------------------------------------------------- 1 | class CreateFlipperTables < ActiveRecord::Migration[5.0] 2 | def self.up 3 | create_table :flipper_features do |t| 4 | t.string :key, null: false 5 | t.timestamps null: false 6 | end 7 | add_index :flipper_features, :key, unique: true 8 | 9 | create_table :flipper_gates do |t| 10 | t.string :feature_key, null: false 11 | t.string :key, null: false 12 | t.string :value 13 | t.timestamps null: false 14 | end 15 | add_index :flipper_gates, [:feature_key, :key, :value], unique: true 16 | end 17 | 18 | def self.down 19 | drop_table :flipper_gates 20 | drop_table :flipper_features 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/views/api/v1/divisions/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.partial! "division", division: @division 4 | 5 | # Extra information that isn't in the summary 6 | json.summary @division.motion 7 | json.votes @division.votes.order(:vote).includes(:member), partial: "api/v1/votes/vote", as: :vote 8 | 9 | json.policy_divisions do 10 | json.array! @division.policy_divisions.includes(:policy) do |pd| 11 | json.policy do 12 | json.partial! "api/v1/policies/policy", policy: pd.policy 13 | end 14 | json.vote PolicyDivision.vote_without_strong(pd.vote) 15 | json.strong pd.strong_vote? 16 | end 17 | end 18 | 19 | json.bills @division.bills, partial: "api/v1/bills/bill", as: :bill 20 | -------------------------------------------------------------------------------- /db/migrate/20140822004101_add_primary_keys.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPrimaryKeys < ActiveRecord::Migration 4 | def change 5 | add_column :member_distances, :id, :primary_key 6 | add_column :pw_cache_divinfo, :id, :primary_key 7 | add_column :pw_cache_divwiki, :id, :primary_key 8 | add_column :pw_cache_dreamreal_distance, :id, :primary_key 9 | add_column :pw_cache_mpinfo, :id, :primary_key 10 | add_column :pw_cache_whip, :id, :primary_key 11 | add_column :pw_constituency, :id, :primary_key 12 | add_column :pw_dyn_dreamvote, :id, :primary_key 13 | add_column :pw_vote, :id, :primary_key 14 | add_column :pw_vote_sortorder, :id, :primary_key 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/assets/stylesheets/divisions/_division-motion.scss: -------------------------------------------------------------------------------- 1 | .division-edit-notice.page-section { 2 | margin-top: 1em; 3 | 4 | @media (min-width: $screen-sm-min) { 5 | margin-top: 0; 6 | } 7 | } 8 | 9 | .motion-source-info { 10 | border-top: 1px solid #E7E7E7; 11 | } 12 | 13 | .division-outcome-summary { 14 | &.division-outcome-passed { 15 | color: $color-vote-for; 16 | } 17 | 18 | &.division-outcome-not-passed { 19 | color: $color-vote-against; 20 | } 21 | } 22 | 23 | .motion-title, 24 | .motion-title + .division-edit-link, 25 | .division-outcome-summary, 26 | .division-outcome-score { 27 | display: inline-block; 28 | } 29 | 30 | .motion-title + .division-edit-link { 31 | margin-left: 1em; 32 | } 33 | -------------------------------------------------------------------------------- /app/controllers/api/v1/divisions_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class DivisionsController < Api::V1::ApplicationController 6 | def index 7 | @divisions = Division.order(date: :desc, house: :desc, number: :desc).includes(:wiki_motions, :whips, :division_info).limit(100) 8 | @divisions = @divisions.where(date: (params[:start_date])..) if params[:start_date] 9 | @divisions = @divisions.where(date: ..(params[:end_date])) if params[:end_date] 10 | @divisions = @divisions.where(house: params[:house]) if params[:house] 11 | end 12 | 13 | def show 14 | @division = Division.find(params[:id]) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, "\\1en" 8 | # inflect.singular /^(ox)en/i, "\\1" 9 | # inflect.irregular "person", "people" 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym "RESTful" 16 | # end 17 | -------------------------------------------------------------------------------- /app/assets/stylesheets/global/_social-share.scss: -------------------------------------------------------------------------------- 1 | %inline-icon { 2 | margin-right: 3px; 3 | display: inline-block; 4 | font-size: 24px; 5 | vertical-align: middle; 6 | } 7 | 8 | .social-share { 9 | z-index: 1; 10 | ul { 11 | display: inline; 12 | } 13 | } 14 | 15 | .social-share-heading { 16 | margin: 0 10px 0 0; 17 | display: inline-block; 18 | color: #aaa; 19 | } 20 | 21 | .share-link { 22 | margin-left: 2px; 23 | color: #888; 24 | 25 | i { 26 | @extend %inline-icon; 27 | color: #aaa; 28 | 29 | &.fi-social-facebook { 30 | padding: 0 0 2px 0; 31 | } 32 | } 33 | 34 | &:hover, 35 | &:focus { 36 | text-decoration: none; 37 | i { 38 | color: inherit; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /config/initializers/markdown_handler.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "redcarpet" 4 | 5 | class BootstrapTableRenderer < Redcarpet::Render::HTML 6 | def table(header, body) 7 | "#{header}#{body}
" 8 | end 9 | end 10 | 11 | module MarkdownHandler 12 | def self.erb 13 | @erb ||= ActionView::Template.registered_template_handler(:erb) 14 | end 15 | 16 | def self.call(template, source) 17 | compiled_source = erb.call(template, source) 18 | "Redcarpet::Markdown.new(BootstrapTableRenderer, tables: true).render(begin;#{compiled_source};end.to_s).html_safe" 19 | end 20 | end 21 | 22 | ActionView::Template.register_template_handler :md, MarkdownHandler 23 | -------------------------------------------------------------------------------- /app/views/devise/mailer/reset_password_instructions.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :subject, "Reset your password" 2 | 3 | %tr 4 | %td.content-block 5 | #{@resource.name}, someone has requested a link to change your password. 6 | You can do this through the link below. 7 | %tr 8 | %td.content-block 9 | = link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token), class: "btn-primary" 10 | %tr 11 | %td.content-block 12 | If you didn't request this, please ignore this email. 13 | %tr 14 | %td.content-block 15 | Your password won't change until you access the link above and create a new one. 16 | %tr 17 | %td.content-block 18 | — The 19 | %em= Rails.configuration.project_name 20 | team 21 | -------------------------------------------------------------------------------- /app/views/application/_social_share.html.haml: -------------------------------------------------------------------------------- 1 | %aside.social-share 2 | %h2.social-share-heading.small 3 | Share 4 | 5 | -# TODO: The visual layout of this is pretty awfull right now. The icons and the text are not vertically center aligned as they should be 6 | %ul.list-inline.small 7 | %li 8 | = link_to "https://www.facebook.com/sharer/sharer.php?u=#{request.original_url}&t=", title: "Share on Facebook", class: 'share-link share-link-facebook' do 9 | %i.fa-brands.fa-facebook 10 | Facebook 11 | 12 | %li 13 | = link_to "https://bsky.app/intent/compose?text=#{request.original_url}", title: "Share on Bluesky", class: 'share-link share-link-bluesky' do 14 | %i.fa-brands.fa-bluesky 15 | Bluesky 16 | 17 | -------------------------------------------------------------------------------- /db/migrate/20220421041242_drop_member_distances.rb: -------------------------------------------------------------------------------- 1 | class DropMemberDistances < ActiveRecord::Migration[6.0] 2 | def change 3 | drop_table :member_distances do |t| 4 | t.integer :member1_id, null: false 5 | t.integer :member2_id, null: false 6 | t.integer :nvotessame 7 | t.integer :nvotesdiffer 8 | t.integer :nvotesabsent 9 | t.float :distance_a, limit: 24 10 | t.float :distance_b, limit: 24 11 | t.datetime :created_at 12 | t.datetime :updated_at 13 | t.index [:member1_id, :member2_id], name: "mp_id1_2", unique: true, using: :btree 14 | t.index [:member1_id], name: "mp_id1", using: :btree 15 | t.index [:member2_id], name: "mp_id2", using: :btree 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/policies/policy_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class PolicyPolicy < ApplicationPolicy 4 | def create? 5 | user&.staff? 6 | end 7 | 8 | def update? 9 | user&.staff? 10 | end 11 | 12 | # NOTE: Up to Pundit v2.3.1, the inheritance was declared as 13 | # `Scope < Scope` rather than `Scope < ApplicationPolicy::Scope`. 14 | # In most cases the behavior will be identical, but if updating existing 15 | # code, beware of possible changes to the ancestors: 16 | # https://gist.github.com/Burgestrand/4b4bc22f31c8a95c425fc0e30d7ef1f5 17 | 18 | class Scope < ApplicationPolicy::Scope 19 | # NOTE: Be explicit about which records you allow access to! 20 | # def resolve 21 | # scope.all 22 | # end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /app/views/application/_logged_in_user_menu.html.haml: -------------------------------------------------------------------------------- 1 | %li.dropdown 2 | %a.dropdown-toggle(href="#" data-toggle="dropdown") 3 | = current_user.name 4 | %ul.dropdown-menu(role="menu") 5 | %li= link_to "Your page", current_user 6 | %li= link_to "Your subscriptions", user_subscriptions_path(current_user) 7 | %li= link_to "Edit profile", edit_user_registration_path 8 | - if current_user.admin? 9 | %li.divider 10 | %li= link_to "Admin panel", admin_root_path 11 | %li= link_to "Admin for feature flags", admin_flipper_path 12 | %li.divider 13 | %li= link_to "Logout", destroy_user_session_path, title: "Make your browser forget that you are logged into #{Rails.configuration.project_name} as #{current_user.name}", method: :delete 14 | -------------------------------------------------------------------------------- /app/controllers/api/v1/application_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class ApplicationController < ::ApplicationController 6 | before_action :require_key 7 | after_action :log_api_request 8 | 9 | private 10 | 11 | def require_key 12 | # Not every user has the api_key set. So explicitly handle the nil case 13 | user = User.find_by(api_key: params[:key]) if params[:key] 14 | render json: { error: "You need a valid api key. Sign up for an account on #{Rails.configuration.project_name} to get one." }, status: :unauthorized if user.nil? 15 | end 16 | 17 | def log_api_request 18 | ApiStatistic.log(request) 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/views/members/_policy_comparisons_block.html.haml: -------------------------------------------------------------------------------- 1 | - unless distances.empty? 2 | .policy-comparision-block.col-md-7{class: "position-#{label}"} 3 | .row 4 | %h3.policy-comparision-position.col-xs-9= title 5 | .row 6 | %ul.policy-comparision-list.object-list-compact.list-unstyled.col-xs-12 7 | - distances.sort_by{ |ppd| ppd.policy.name.downcase }.each do |ppd| 8 | %li.policy-comparision-policy.object-item 9 | = link_to capitalise_initial_character(ppd.policy.name), member_policy_path_simple(member, ppd.policy), class: 'policy-title' 10 | =link_to "Something not right?", help_faq_path(anchor: 'stance'), title: "Is this information inaccurate? Find out how you can improve it.", class: 'policy-correction-notice small' 11 | -------------------------------------------------------------------------------- /db/migrate/20140828083134_add_vote_without_tell_to_votes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddVoteWithoutTellToVotes < ActiveRecord::Migration 4 | def change 5 | add_column :votes, :vote_without_tell, :string, limit: 10 6 | add_index :votes, :vote_without_tell 7 | add_column :votes, :teller, :boolean, null: false, default: false 8 | add_index :votes, :teller 9 | Vote.reset_column_information 10 | Vote.all.find_each do |vote| 11 | case vote.vote 12 | when "tellaye" 13 | vote.update!(vote_without_tell: "aye", teller: true) 14 | when "tellno" 15 | vote.update!(vote_without_tell: "no", teller: true) 16 | else 17 | vote.update!(vote_without_tell: vote.vote) 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/views/policies/history.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title do 2 | Recent history: 3 | = capitalise_initial_character(@policy.name_with_for) 4 | - set_meta_tags description: "Recent changes made to the “#{@policy.name_with_for}” policy." 5 | 6 | .page-header.row 7 | %nav.header-actions.col-md-3 8 | - if policy(@policy).edit? 9 | =link_to_if(@policy, "Edit", edit_policy_path(@policy), title: "Change title and definition of policy", class: "btn btn-default btn-xs") 10 | - if policy(Policy).new? 11 | =link_to "New policy", new_policy_path, class: "link-policy-new btn btn-primary btn-xs" 12 | -# TODO This title is just a stop-gap. Make it not suck. 13 | %h1.col-md-9= yield :title 14 | 15 | = render partial: "layouts/history_list", locals: { policy: @policy, history: @history } 16 | -------------------------------------------------------------------------------- /app/views/api/v1/people/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.partial! "person", person: @person 4 | 5 | # Extra information that's not on the index action 6 | 7 | json.rebellions @person.rebellions 8 | json.votes_attended @person.votes_attended 9 | json.votes_possible @person.votes_possible 10 | 11 | json.offices @person.current_offices, partial: "api/v1/offices/office", as: :office 12 | 13 | json.policy_comparisons do 14 | json.array! @person.policy_person_distances.includes(:policy).published.order(:distance_a) do |ppd| 15 | json.policy do 16 | json.partial! "api/v1/policies/policy", policy: ppd.policy 17 | end 18 | json.agreement number_with_precision(ppd.agreement_fraction * 100, precision: 2, significant: true) 19 | json.voted ppd.voted? 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /config/credentials/production.yml.enc: -------------------------------------------------------------------------------- 1 | IJZeuZl94FpCwg0Nn/oZF9Ss+NXt0BTFR742gvRT4gFuLrhQcbiO17zXqmwclEzB5YPkXsDbIQQbyzZWVTLZr9oVhOvI7F3xAt/mb1vupIjH0FS+raubBQqjgBsWECFNHCdZepn+kG1cE1UwMFSbcapnJdMymEo6tUFEsHqgpgoM7BKnIkvz2Wu7apwoBgFkyb6rr9ToJRaSnWHnJbAY6AVFVlu+/s0kbRCf12UlEpm5ZVsdFynkzxQfGGgGu24rpoT456cj9tUBXSA9r9PE4TFz/mgcBZtqWuTe6t70v7MphZfGEmQaTWyDbYNCPQ5iezhwSSYm7G3fJUMTZz2lYSNDt8cIxFQDW9E6a3QXGtUa7O3wGEhWfaIy6FueR/rs71hBOeo+In/pBTLKXCHTbn1qULUM4wZ0d7eZgb8GAnbYdrlh3ZjitKuvVvm4GgKVGhtCUYHudGqmszOvy+u+gQRJiPN4OWQpk1CaCMBIesl84T2D27PW9yLXkTAyTD1p4Qco2tFxSbRFcIdzIJtTDQXgYT/FrsOvgaE8HCwETlnC0tQWlEjsX2b7MgDFeJqib8zD6qmfTpsoyJxWEHFyDEFvWC9vEZCmGGMAy9HiT0wrg2HjfVqOByRi3O8Q1WKLYj6SglhLYOsQ0dc4BqHYSdCuFA/q9EPpqPjwSh618ZtnXgLTTN1xZbsINttujYK95m9h9Mlf5N3I9eizcmZAK4hNHGXhC/eqz1/WlF58iBCDwx/xlczInf2n6xXsgyJBymI=--FGDdt3DgeKYGu6wm--kTZnQ56Sd/SjK/fc8NMjFw== -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bootstrap-accessibility.css: -------------------------------------------------------------------------------- 1 | .btn:focus{outline:dotted 2px #000}div.active:focus{outline:dotted 1px #000}a:focus{outline:dotted 1px #000}.close:hover,.close:focus{outline:dotted 1px #000}.nav>li>a:hover,.nav>li>a:focus{outline:dotted 1px #000}.carousel-inner>.item{position:absolute;top:-999999em;display:block;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left}.carousel-inner>.active{top:0}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{position:relative}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.alert-success{color:#2d4821}.alert-info{color:#214c62}.alert-warning{color:#6c4a00;background-color:#f9f1c6}.alert-danger{color:#d2322d}.alert-danger:hover{color:#a82824} 2 | -------------------------------------------------------------------------------- /app/assets/stylesheets/divisions/_division-show.scss: -------------------------------------------------------------------------------- 1 | .motion { 2 | padding: 0; 3 | } 4 | 5 | .division-external-links { 6 | width: 100%; 7 | clear: left; 8 | 9 | @include make-md-column(7); 10 | padding: 0; 11 | 12 | .motion-edited + & { 13 | @media (max-width: $screen-sm-max) { 14 | padding: 0; 15 | } 16 | 17 | @media (min-width: $screen-md-min) { 18 | float: right !important; 19 | clear: right; 20 | } 21 | 22 | // @include make-lg-column-offset(8); 23 | @include make-md-column(4); 24 | @include make-lg-column(4); 25 | } 26 | 27 | h2:first-child { 28 | margin-top: 46px; 29 | margin-bottom: 0; 30 | } 31 | 32 | .object-item { 33 | padding-right: 0; 34 | padding-left: 0; 35 | 36 | a { 37 | display: block; 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /design_docs/principles.md: -------------------------------------------------------------------------------- 1 | # Design Principles 2 | 3 | Ideas that guide decision making on this project. 4 | 5 | 1. *Focus on enabling actions that citizens want to take and access to the knowledge that they are looking for*. Reduce the cost of them taking action. The action is the important bit. Citizens don't need to understand the bureaucracy in order to use and access government. 6 | 7 | 2. Assume people are *smart & busy*—present the important information up front and put detail within reach. 8 | 9 | 3. Strive for *universal accessibility*. 10 | 11 | 4. Design and implement with *Progressive Enhancement*. 12 | 13 | 5. *Create change by doing*. Implement ideas quickly and assess—don't be frozen by documentation and proposal. 14 | 15 | 6. *Maintainability* is crucial, this project should last and evolve long into the future. 16 | -------------------------------------------------------------------------------- /spec/models/policy_division_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | 5 | describe PolicyDivision do 6 | describe "#vote" do 7 | it { expect(described_class.new(policy: Policy.new, division: Division.new)).not_to be_valid } 8 | it { expect(described_class.new(policy: Policy.new, division: Division.new, vote: "aye3")).to be_valid } 9 | it { expect(described_class.new(policy: Policy.new, division: Division.new, vote: "aye")).to be_valid } 10 | it { expect(described_class.new(policy: Policy.new, division: Division.new, vote: "no")).to be_valid } 11 | it { expect(described_class.new(policy: Policy.new, division: Division.new, vote: "no3")).to be_valid } 12 | it { expect(described_class.new(policy: Policy.new, division: Division.new, vote: "bottom")).not_to be_valid } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/policies/policy_division_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class PolicyDivisionPolicy < ApplicationPolicy 4 | def create? 5 | user&.staff? 6 | end 7 | 8 | def update? 9 | user&.staff? 10 | end 11 | 12 | def destroy? 13 | user&.staff? 14 | end 15 | 16 | # NOTE: Up to Pundit v2.3.1, the inheritance was declared as 17 | # `Scope < Scope` rather than `Scope < ApplicationPolicy::Scope`. 18 | # In most cases the behavior will be identical, but if updating existing 19 | # code, beware of possible changes to the ancestors: 20 | # https://gist.github.com/Burgestrand/4b4bc22f31c8a95c425fc0e30d7ef1f5 21 | 22 | class Scope < ApplicationPolicy::Scope 23 | # NOTE: Be explicit about which records you allow access to! 24 | # def resolve 25 | # scope.all 26 | # end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /db/migrate/20220217004002_convert_users_text_fields_to_string.rb: -------------------------------------------------------------------------------- 1 | class ConvertUsersTextFieldsToString < ActiveRecord::Migration[6.0] 2 | def up 3 | # Temporary columns to hold truncated values 4 | add_column :users, :temp_name, :string, null: false 5 | add_column :users, :temp_email, :string 6 | 7 | # There's only spam accounts that have long names or emails. So we can just chop them off 8 | User.find_each do |user| 9 | user.update!(temp_name: user.name[0..254], temp_email: user.email&.[](0..254)) 10 | end 11 | 12 | remove_column :users, :name 13 | rename_column :users, :temp_name, :name 14 | 15 | remove_column :users, :email 16 | rename_column :users, :temp_email, :email 17 | end 18 | 19 | def down 20 | change_column :users, :name, :text, null: false 21 | change_column :users, :email, :text 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/views/members/_policy_comparisons.html.haml: -------------------------------------------------------------------------------- 1 | %section.page-section#voting-stace 2 | %h2 How do they vote? 3 | 4 | - if member.person.policy_person_distances.empty? 5 | %ul 6 | %li 7 | No policies match this person's votes. You can 8 | = link_to "edit or make a policy", policies_path 9 | that will appear here. 10 | - else 11 | - distances = member.person.policy_person_distances.published.includes(:policy) 12 | - PolicyPersonDistance.all_categories.each do |c| 13 | = render "policy_comparisons_block", member: member, distances: distances.select{ |d| d.category == c }, title: category_words_sentence(c).capitalize, label: c.to_s 14 | 15 | %p.small.text-muted 16 | Please note that #{link_to "our voting records start in #{formatted_month(Division.date_earliest_division)}", help_faq_path(anchor: "timeperiod"), class: 'text-muted'}. 17 | -------------------------------------------------------------------------------- /app/policies/application_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationPolicy 4 | attr_reader :user, :record 5 | 6 | def initialize(user, record) 7 | @user = user 8 | @record = record 9 | end 10 | 11 | def index? 12 | false 13 | end 14 | 15 | def show? 16 | false 17 | end 18 | 19 | def create? 20 | false 21 | end 22 | 23 | def new? 24 | create? 25 | end 26 | 27 | def update? 28 | false 29 | end 30 | 31 | def edit? 32 | update? 33 | end 34 | 35 | def destroy? 36 | false 37 | end 38 | 39 | class Scope 40 | def initialize(user, scope) 41 | @user = user 42 | @scope = scope 43 | end 44 | 45 | def resolve 46 | raise NoMethodError, "You must define #resolve in #{self.class}" 47 | end 48 | 49 | private 50 | 51 | attr_reader :user, :scope 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /app/views/policies/_policy.html.haml: -------------------------------------------------------------------------------- 1 | %li 2 | = link_to policy, class: 'object-item panel-link row' do 3 | %article 4 | %h2.policy-title.object-heading.panel-link-title.col-md-7 5 | = capitalise_initial_character(policy.name) 6 | 7 | %p.policy-data.object-secondary 8 | %span 9 | = pluralize(policy.divisions.count, "division") 10 | - if policy.unedited_motions_count != 0 11 | %em= "(#{policy.unedited_motions_count} unedited)" 12 | %small.policy-edit-notice.text-muted 13 | edited #{time_ago_in_words(policy.last_edited_at)} ago 14 | %small.policy-subscriber-count.text-muted.hidden-md.hidden-lg 15 | = pluralize(policy.watches.count, "subscriber") 16 | 17 | %p.policy-subscriber-count.visible-md.visible-lg.col-md-7.text-muted.small 18 | = pluralize(policy.watches.count, "subscriber") 19 | -------------------------------------------------------------------------------- /app/views/devise/confirmations/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, 'Resend email confirmation' 2 | 3 | .thin-page 4 | %h1.long-title= yield :title 5 | 6 | %p We’ll send you an email to confirm address 7 | 8 | = simple_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| 9 | - if f.error :confirmation_token 10 | .alert.alert-danger= "Confirmation token is invalid. Enter your email and we'll send you another confirmation." 11 | - else 12 | = f.error_notification 13 | 14 | .form-group= f.input :email, as: :email, autofocus: true, hint: "Enter your email address", hint_html: {class: 'small hint-block-intime'} 15 | 16 | = f.button :submit, "Resend confirmation", class: "btn btn-primary btn-wide" 17 | 18 | %ul.form-secondary.nav.nav-pills 19 | %li= link_to 'Back to Log in', new_user_session_path, class: "btn-xs" 20 | -------------------------------------------------------------------------------- /app/views/alert_mailer/policy_updated.html.haml: -------------------------------------------------------------------------------- 1 | %h1.unstyled-heading 2 | %strong 3 | = link_to capitalise_initial_character(@policy.name_with_for), policy_url(@policy), class: "heading-object-link" 4 | 5 | - if @version.kind_of?(WikiMotion) 6 | %p 7 | Changed text on related division 8 | = link_to @version.division.name, division_url_simple(@version.division) 9 | - else 10 | = version_sentence(@version) 11 | 12 | %p.small.object-primary 13 | = link_to version_author(@version).name, version_author(@version) 14 | %span.text-muted.small 15 | = @version.created_at.strftime("%l:%M%p - %d %b %Y") 16 | 17 | %br 18 | 19 | .text-muted 20 | %p.small 21 | Visit the 22 | = link_to "policy page", policy_url(@policy), class: "small" 23 | to unsubscribe from this policy. 24 | %p.small 25 | = link_to "View all your subscriptions.", user_subscriptions_url(@user), class: "small" 26 | -------------------------------------------------------------------------------- /bin/pry: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'pry' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("pry", "pry") 30 | -------------------------------------------------------------------------------- /bin/ri: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'ri' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("rdoc", "ri") 30 | -------------------------------------------------------------------------------- /bin/haml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'haml' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("haml", "haml") 30 | -------------------------------------------------------------------------------- /bin/mina: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'mina' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("mina", "mina") 30 | -------------------------------------------------------------------------------- /bin/racc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'racc' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("racc", "racc") 30 | -------------------------------------------------------------------------------- /bin/rdoc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'rdoc' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("rdoc", "rdoc") 30 | -------------------------------------------------------------------------------- /bin/sdoc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'sdoc' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("sdoc", "sdoc") 30 | -------------------------------------------------------------------------------- /bin/thor: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'thor' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("thor", "thor") 30 | -------------------------------------------------------------------------------- /bin/tilt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'tilt' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("tilt", "tilt") 30 | -------------------------------------------------------------------------------- /bin/cap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'cap' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("capistrano", "cap") 30 | -------------------------------------------------------------------------------- /bin/guard: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'guard' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("guard", "guard") 30 | -------------------------------------------------------------------------------- /bin/ldiff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'ldiff' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("diff-lcs", "ldiff") 30 | -------------------------------------------------------------------------------- /bin/rackup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'rackup' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("rack", "rackup") 30 | -------------------------------------------------------------------------------- /app/assets/stylesheets/global/_variables.scss: -------------------------------------------------------------------------------- 1 | // Typography 2 | $font-family-base: "Fira Sans", sans-serif; 3 | $font-size-base: 18px; 4 | $line-height-base: 1.6; 5 | 6 | $font-size-supporting: 14px; 7 | 8 | $grid-float-breakpoint: 60em; 9 | 10 | // Colours 11 | // http://color.hailpixel.com/#FFEA8A,FFF2B8,C64E39,B15D4E,94716B,767676,467043,3E7939,308A28, 12 | 13 | $text-color: #444444; 14 | 15 | $color-lemon: #ffea8a; 16 | $color-lemon-light: #fff2b8; 17 | 18 | $color-orange: #ffbb43; 19 | 20 | $color-blue: #428bca; 21 | $color-blue-dark: #274486; 22 | 23 | $brand-primary: $color-blue; 24 | 25 | $color-for3: #308A28; 26 | $color-for2: #3E7939; 27 | $color-for1: #467043; 28 | $color-mixed-position: #767676; 29 | $color-against1: #94716B; 30 | $color-against2: #B15D4E; 31 | $color-against3: #C64E39; 32 | 33 | $color-vote-against: $color-against3; 34 | $color-vote-for: $color-for3; 35 | $color-rebel: $color-against3; 36 | -------------------------------------------------------------------------------- /bin/capify: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'capify' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("capistrano", "capify") 30 | -------------------------------------------------------------------------------- /bin/coderay: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'coderay' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("coderay", "coderay") 30 | -------------------------------------------------------------------------------- /bin/foreman: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'foreman' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("foreman", "foreman") 30 | -------------------------------------------------------------------------------- /bin/launchy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'launchy' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("launchy", "launchy") 30 | -------------------------------------------------------------------------------- /bin/listen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'listen' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("listen", "listen") 30 | -------------------------------------------------------------------------------- /app/lib/card_screenshotter/policies.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module CardScreenshotter 4 | class Policies 5 | class << self 6 | include Rails.application.routes.url_helpers 7 | include PathHelper 8 | 9 | def run 10 | screenshotter = CardScreenshotter::Utils.new 11 | policies = Policy.all 12 | progress = ProgressBar.create(total: policies.count, format: "%t: |%B| %E %a") 13 | policies.each do |policy| 14 | screenshotter.screenshot_and_save(url(policy), save_path(policy)) 15 | progress.increment 16 | end 17 | screenshotter.close_driver! 18 | end 19 | 20 | def url(policy) 21 | policy_url(policy, ActionMailer::Base.default_url_options.merge(card: true)) 22 | end 23 | 24 | def save_path(policy) 25 | "public/cards#{policy_path(policy)}.png" 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /bin/bootsnap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'bootsnap' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("bootsnap", "bootsnap") 30 | -------------------------------------------------------------------------------- /bin/htmldiff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'htmldiff' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("diff-lcs", "htmldiff") 30 | -------------------------------------------------------------------------------- /bin/httparty: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'httparty' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("httparty", "httparty") 30 | -------------------------------------------------------------------------------- /bin/nokogiri: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'nokogiri' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("nokogiri", "nokogiri") 30 | -------------------------------------------------------------------------------- /bin/skylight: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'skylight' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("skylight", "skylight") 30 | -------------------------------------------------------------------------------- /db/migrate/20140623022321_add_confirmable_to_devise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddConfirmableToDevise < ActiveRecord::Migration 4 | def self.up 5 | add_column :pw_dyn_user, :confirmation_token, :string 6 | add_column :pw_dyn_user, :confirmed_at, :datetime 7 | add_column :pw_dyn_user, :confirmation_sent_at, :datetime 8 | add_column :pw_dyn_user, :unconfirmed_email, :string 9 | add_index :pw_dyn_user, :confirmation_token, unique: true 10 | 11 | # Temporarily use old table name 12 | user_table_name = User.table_name 13 | User.table_name = "pw_dyn_user" 14 | # Update existing records 15 | User.update_all(confirmed_at: Time.now) 16 | # Reset table name 17 | User.table_name = user_table_name 18 | end 19 | 20 | def self.down 21 | remove_columns :pw_dyn_user, :confirmation_token, :confirmed_at, :confirmation_sent_at, :unconfirmed_email 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/controllers/admin/application_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # All Administrate controllers inherit from this 4 | # `Administrate::ApplicationController`, making it the ideal place to put 5 | # authentication logic or other before_actions. 6 | # 7 | # If you want to add pagination or other controller-level concerns, 8 | # you're free to overwrite the RESTful controller actions. 9 | module Admin 10 | class ApplicationController < Administrate::ApplicationController 11 | before_action :authenticate_admin 12 | 13 | def authenticate_admin 14 | authenticate_user! 15 | render plain: "Not authorised", status: :forbidden unless current_user.admin? 16 | end 17 | 18 | # Override this value to specify the number of elements to display at a time 19 | # on index pages. Defaults to 20. 20 | # def records_per_page 21 | # params[:per_page] || 20 22 | # end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /app/controllers/confirmations_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ConfirmationsController < Devise::ConfirmationsController 4 | # Override Devise to automatically sign in the user 5 | # GET /resource/confirmation?confirmation_token=abcdef 6 | def show 7 | self.resource = resource_class.confirm_by_token(params[:confirmation_token]) 8 | yield resource if block_given? 9 | 10 | if resource.errors.empty? 11 | set_flash_message(:notice, :confirmed) if is_flashing_format? 12 | 13 | # Was this likely an email change or a new sign up? 14 | if signed_in?(resource_name) 15 | redirect_to signed_in_root_path(resource) 16 | else 17 | sign_in(resource_name, resource) 18 | redirect_to user_welcome_path 19 | end 20 | else 21 | respond_with_navigational(resource.errors, status: :unprocessable_entity) { render :new } 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /bin/_guard-core: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application '_guard-core' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("guard", "_guard-core") 30 | -------------------------------------------------------------------------------- /bin/redcarpet: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'redcarpet' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("redcarpet", "redcarpet") 30 | -------------------------------------------------------------------------------- /bin/ruby-parse: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'ruby-parse' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("parser", "ruby-parse") 30 | -------------------------------------------------------------------------------- /bin/sdoc-merge: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'sdoc-merge' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("sdoc", "sdoc-merge") 30 | -------------------------------------------------------------------------------- /bin/sprockets: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'sprockets' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("sprockets", "sprockets") 30 | -------------------------------------------------------------------------------- /bin/stackprof: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'stackprof' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("stackprof", "stackprof") 30 | -------------------------------------------------------------------------------- /bin/ruby-rewrite: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'ruby-rewrite' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("parser", "ruby-rewrite") 30 | -------------------------------------------------------------------------------- /bin/ruby_parse: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'ruby_parse' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("ruby_parser", "ruby_parse") 30 | -------------------------------------------------------------------------------- /bin/honeybadger: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'honeybadger' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("honeybadger", "honeybadger") 30 | -------------------------------------------------------------------------------- /bin/mongrel_rpm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'mongrel_rpm' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("newrelic_rpm", "mongrel_rpm") 30 | -------------------------------------------------------------------------------- /app/views/devise/sessions/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Log in" 2 | 3 | .thin-page 4 | %h1.long-title= yield :title 5 | 6 | = simple_form_for(resource, as: resource_name, url: session_path(resource_name), html: {class: "login-form"}) do |f| 7 | = f.error_notification 8 | 9 | .form-group= f.input :email, as: :email, autofocus: true 10 | .form-group= f.input :password 11 | 12 | - if devise_mapping.rememberable? 13 | .checkbox 14 | %label 15 | = f.check_box :remember_me 16 | Remember me 17 | 18 | = f.submit "Log in", class: "btn btn-primary btn-wide" 19 | 20 | %ul.form-secondary.nav.nav-pills 21 | %li= link_to 'Sign up for a new account', new_registration_path(resource_name), class: "btn-xs" 22 | %li= link_to 'Forgotten your password?', new_password_path(resource_name), class: "btn-xs" 23 | %li= link_to 'Resend confirmation', new_user_confirmation_path, class: 'btn-xs' 24 | -------------------------------------------------------------------------------- /app/views/divisions/_summary_table.html.haml: -------------------------------------------------------------------------------- 1 | %table.table 2 | %colgroup.column-name{span: 1} 3 | %colgroup.column-vote{span: 1} 4 | %colgroup.column-toggler{span: 1} 5 | %thead 6 | %tr 7 | %th Party 8 | %th.cell-vote Votes 9 | %th.cell-toggler 10 | %tbody 11 | - whips.each do |whip| 12 | = render 'summary_whip', whip: whip, votes: votes, members_vote_null: members_vote_null 13 | 14 | %tr 15 | %th.whip 16 | Totals 17 | %small.post-title.text-muted= '(' + fraction_to_percentage_display(division.attendance_fraction) + ' turnout)' 18 | %td.cell-vote 19 | %span{class: aye_vote_total_class(division)} 20 | = division.aye_votes_including_tells 21 | = vote_display "aye" 22 | – 23 | %span{class: no_vote_total_class(division)} 24 | = division.no_votes_including_tells 25 | = vote_display "no" 26 | %td.cell-toggler 27 | -------------------------------------------------------------------------------- /app/views/people_distances/_summary_vote_numbers.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | - if person_distance.nvotesdiffer > person_distance.nvotessame 3 | = succeed "." do 4 | In divisions they have voted differently 5 | = number_of_times(person_distance.nvotesdiffer) 6 | = succeed "." do 7 | - if person_distance.nvotessame.zero? 8 | They have 9 | %strong never voted the same 10 | - else 11 | They have only voted 12 | %strong= "the same #{number_of_times(person_distance.nvotessame)}" 13 | - else 14 | = succeed "." do 15 | In divisions they have voted the same 16 | = number_of_times(person_distance.nvotessame) 17 | = succeed "." do 18 | - if person_distance.nvotesdiffer.zero? 19 | They have 20 | %strong never voted differently 21 | - else 22 | They have only voted 23 | %strong= "differently #{number_of_times(person_distance.nvotesdiffer)}" 24 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 180 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because there has been no 14 | activity on it for about six months. If you want to keep it open please make a comment 15 | and explain why this issue is still relevant. Otherwise it will be 16 | automatically closed in a week. Thank you! 17 | # Comment to post when closing a stale issue. Set to `false` to disable 18 | closeComment: false 19 | # Limit the number of actions per hour, from 1-30. Default is 30 20 | limitPerRun: 1 21 | -------------------------------------------------------------------------------- /app/views/policies/_vote_summary_table.html.haml: -------------------------------------------------------------------------------- 1 | %table.table.divisions-table 2 | %thead 3 | %tr 4 | %th Division 5 | - people.each do |person| 6 | %th= person.name 7 | %th.policyvotehead Supporters vote 8 | %tbody 9 | - if policy_divisions.empty? 10 | %tr 11 | %td{colspan: 7} no votes listed 12 | - else 13 | - policy_divisions.each do |pd| 14 | %tr 15 | %td 16 | %h3.division-title.h4 17 | %small.pre-title= division_date_and_time(pd.division) + " – " + pd.division.house_name 18 | = link_to(pd.division.name, division_path_simple(pd.division)) 19 | - people.each do |person| 20 | %td.division-member-vote{data: {member: "#{person.name}"}} 21 | = vote_display(pd.division.vote_for_person(person)) 22 | %td.division-policy-vote 23 | = vote_display(PolicyDivision.vote_without_strong(pd.vote)) 24 | -------------------------------------------------------------------------------- /app/views/policies/how_the_number_is_calculated/_not_enough.html.haml: -------------------------------------------------------------------------------- 1 | - if policy_person_distance.number_of_votes.zero? 2 | %p 3 | Normally a person's votes count towards a score which is used to work out a simple 4 | phrase to summarise their position on a policy. However in this case 5 | = policy_person_distance.person.name 6 | was absent during all divisions for this policy. So, it's impossible to say anything concrete. 7 | - else 8 | %p 9 | = policy_person_distance.person.name 10 | has only voted once on this policy and it wasn't on a "strong" vote. So it's not possible to draw a clear conclusion about their position. 11 | %p 12 | This could be because there were simply not many relevant divisions (formal votes) during the time they've been in parliament (most votes 13 | happen on "the voices", so we simply have no decent record) or they were absent for votes that could have contributed to 14 | their voting record. 15 | -------------------------------------------------------------------------------- /bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | include FileUtils 4 | 5 | # path to your application root. 6 | APP_ROOT = File.expand_path('..', __dir__) 7 | 8 | def system!(*args) 9 | system(*args) || abort("\n== Command #{args} failed ==") 10 | end 11 | 12 | chdir APP_ROOT do 13 | # This script is a way to update your development environment automatically. 14 | # Add necessary update steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | # Install JavaScript dependencies if using Yarn 21 | # system('bin/yarn') 22 | 23 | puts "\n== Updating database ==" 24 | system! 'bin/rails db:migrate' 25 | 26 | puts "\n== Removing old logs and tempfiles ==" 27 | system! 'bin/rails log:clear tmp:clear' 28 | 29 | puts "\n== Restarting application server ==" 30 | system! 'bin/rails restart' 31 | end 32 | -------------------------------------------------------------------------------- /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 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 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require jquery 14 | //= require bootstrap-sprockets 15 | //= require jquery_ujs 16 | //= require marked 17 | //= require jquery.widowFix-1.3.2 18 | //= require jquery.lazyload 19 | //= require bootstrap-accessibility 20 | //= require modernizr_custom 21 | //= require bootstrap-select 22 | //= require_tree . 23 | -------------------------------------------------------------------------------- /app/views/api/v1/policies/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.partial! "policy", policy: @policy 4 | 5 | # More detailed information 6 | json.policy_divisions do 7 | json.array! @policy.policy_divisions.includes(division: %i[wiki_motions whips division_info]) do |pd| 8 | json.division do 9 | json.partial! "api/v1/divisions/division", division: pd.division 10 | end 11 | json.vote PolicyDivision.vote_without_strong(pd.vote) 12 | json.strong pd.strong_vote? 13 | end 14 | end 15 | 16 | json.people_comparisons do 17 | json.array! @policy.policy_person_distances.includes(person: :members).order(:distance_a) do |ppd| 18 | json.person do 19 | json.partial! "api/v1/people/person", person: ppd.person 20 | end 21 | json.agreement number_with_precision(ppd.agreement_fraction * 100, precision: 2, significant: true) 22 | json.voted ppd.voted? 23 | json.category ppd.category 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /app/views/help/faq/_rebel.md: -------------------------------------------------------------------------------- 1 | An MP or Senator rebels by voting against the 2 | [party whip](https://peo.gov.au/understand-our-parliament/parliament-and-its-people/people-in-parliament/party-whip/). This is known as 3 | [crossing the floor](https://peo.gov.au/understand-our-parliament/how-parliament-works/parliament-at-work/crossing-the-floor/). 4 | 5 | Currently in the Australian Federal Parliament MPs and Senators nearly always vote along party lines. 6 | 7 | Labor party members are not allowed to rebel. In the Liberal party 8 | backbenchers are officially allowed to rebel but this is becoming increasingly uncommon in practise. 9 | 10 | For more on the rules of the different political parties around rebellions see this 2002 Issues Brief from the Parliamentary library "[Free Votes in Australian and some Overseas Parliaments](http://www.aph.gov.au/About_Parliament/Parliamentary_Departments/Parliamentary_Library/Publications_Archive/CIB/cib0203/03CIB01#votes)" 11 | -------------------------------------------------------------------------------- /bin/reverse_markdown: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'reverse_markdown' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("reverse_markdown", "reverse_markdown") 30 | -------------------------------------------------------------------------------- /bin/elastic_ruby_console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'elastic_ruby_console' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("elasticsearch", "elastic_ruby_console") 30 | -------------------------------------------------------------------------------- /spec/features/user_profile_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | 5 | describe "User profile", type: :feature do 6 | before do 7 | create(:member) 8 | end 9 | 10 | let(:user) { create(:user, confirmed_at: Time.zone.now) } 11 | 12 | it "changing name without changing password" do 13 | visit "/" 14 | click_on "Log in" 15 | within "#new_user" do 16 | fill_in "Email", with: user.email 17 | fill_in "Password", with: user.password 18 | click_on "Log in" 19 | end 20 | expect(page).to have_content "Welcome!" 21 | click_on "Edit profile" 22 | within "#edit_user" do 23 | fill_in "Username", with: "Henare Degan, Esquire" 24 | fill_in "Current password", with: user.password 25 | end 26 | click_on "Update" 27 | expect(page).to have_content "You updated your account successfully." 28 | expect(user.reload.name).to eql "Henare Degan, Esquire" 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /app/views/people_distances/_divisions_same.html.haml: -------------------------------------------------------------------------------- 1 | - if person_distance.nvotessame.positive? 2 | %section.page-section 3 | %h2 Divisions in which they voted the same 4 | = render "summary_vote_numbers", person_distance: @person_distance 5 | %ol.divisions-list.list-unstyled{class: active_house_for_list_class(nil)} 6 | - person_distance.divisions_same.order(date: :desc, clock_time: :desc, name: :asc).each do |division| 7 | -# Doing this terrible hack because some divisions (e.g. representatives/2018-12-04/1) have votes for Julia Bank attached to the wrong member. The votes are attached to the member before she changed party and became independent. 8 | - member1 = person_distance.person1.members.find {|m| !m.division_vote(division).nil? } 9 | - member2 = person_distance.person2.members.find {|m| !m.division_vote(division).nil? } 10 | = render 'divisions/division', members: [member1, member2], house: nil, division: division 11 | -------------------------------------------------------------------------------- /bin/stackprof-flamegraph.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'stackprof-flamegraph.pl' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("stackprof", "stackprof-flamegraph.pl") 30 | -------------------------------------------------------------------------------- /bin/stackprof-gprof2dot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'stackprof-gprof2dot.py' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("stackprof", "stackprof-gprof2dot.py") 30 | -------------------------------------------------------------------------------- /bin/ruby_parse_extract_error: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'ruby_parse_extract_error' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("ruby_parser", "ruby_parse_extract_error") 30 | --------------------------------------------------------------------------------