├── log └── .keep ├── app ├── mailers │ └── .keep ├── models │ ├── .keep │ ├── concerns │ │ └── .keep │ ├── outcome.rb │ ├── superintendent.rb │ ├── rank.rb │ ├── complaint.rb │ ├── authority.rb │ ├── category.rb │ ├── case_rule_count.rb │ ├── defendant.rb │ ├── board_member_vote.rb │ ├── rule.rb │ ├── term.rb │ ├── case_rule.rb │ ├── vote.rb │ ├── minority_opinion.rb │ ├── user.rb │ └── board_member.rb ├── assets │ ├── images │ │ ├── .keep │ │ ├── icon.png │ │ ├── logo.png │ │ ├── facebook.png │ │ ├── favicon.ico │ │ ├── favicon.png │ │ ├── twitter.png │ │ ├── logo-reverse.png │ │ ├── board-members │ │ │ ├── rita-fry.jpg │ │ │ ├── placeholder.jpg │ │ │ ├── arthur-j-smith.jpg │ │ │ ├── george-vlecich.jpg │ │ │ ├── ghian-foreman.jpg │ │ │ ├── michael-eaddy.jpg │ │ │ ├── patricia-bobb.jpg │ │ │ ├── scott-j-davis.jpg │ │ │ ├── william-conlon.jpg │ │ │ ├── elisa-rodriguez.jpg │ │ │ ├── melissa-ballate.jpg │ │ │ ├── susan-l-mckeever.jpg │ │ │ ├── victor-gonzales.jpg │ │ │ ├── william-kirkling.jpg │ │ │ ├── demetrius-e-carney.jpg │ │ │ ├── phyllis-l-apelbaum.jpg │ │ │ ├── rev-johnny-l-miller.jpg │ │ │ └── rhoda-davis-sweeney.jpg │ │ ├── fallback │ │ │ ├── nil_board_image.jpg │ │ │ └── thumb_nil_board_image.jpg │ │ └── board_member │ │ │ └── image │ │ │ └── 23 │ │ │ ├── P1090535.JPG │ │ │ └── thumb_P1090535.JPG │ └── stylesheets │ │ ├── terms.scss │ │ ├── admin.css.scss │ │ ├── users.css.scss │ │ ├── extranet │ │ ├── rules.scss │ │ ├── case_files.scss │ │ ├── minority_opinions.scss │ │ └── minority_opinion_votes.scss │ │ ├── application.css │ │ ├── actiontext.scss │ │ └── reset.css ├── views │ ├── extranet │ │ ├── cases │ │ │ ├── _ │ │ │ ├── new.html.erb │ │ │ ├── edit.html.erb │ │ │ ├── _form_case_rule_counts.html.erb │ │ │ ├── index.csv.erb │ │ │ ├── _case_rule_count_fields.html.erb │ │ │ ├── _form_case_rules.html.erb │ │ │ ├── _form_defendant.html.erb │ │ │ ├── _defendant_fields.html.erb │ │ │ ├── _board_member_vote_fields.erb │ │ │ ├── show.html.erb │ │ │ ├── _case_rule_fields.html.erb │ │ │ └── index.html.erb │ │ ├── rules │ │ │ ├── show.html.erb │ │ │ ├── create.html.erb │ │ │ ├── update.html.erb │ │ │ ├── destroy.html.erb │ │ │ ├── new.html.erb │ │ │ ├── edit.html.erb │ │ │ ├── index.html.erb │ │ │ └── _form.html.erb │ │ ├── board_members │ │ │ ├── show.html.erb │ │ │ ├── create.html.erb │ │ │ ├── destroy.html.erb │ │ │ ├── update.html.erb │ │ │ ├── new.html.erb │ │ │ ├── edit.html.erb │ │ │ ├── index.html.erb │ │ │ └── _form.html.erb │ │ └── superintendents │ │ │ ├── new.html.erb │ │ │ ├── edit.html.erb │ │ │ ├── index.html.erb │ │ │ └── _form.html.erb │ ├── fields │ │ └── password_field │ │ │ ├── _index.html.erb │ │ │ ├── _show.html.erb │ │ │ └── _form.html.erb │ ├── users │ │ ├── show.html.erb │ │ ├── new.html.erb │ │ └── index.html.erb │ ├── board │ │ ├── new.html.erb │ │ ├── _member_cases.html.erb │ │ ├── _vote_list.html.erb │ │ ├── _member.html.erb │ │ ├── index.html.erb │ │ ├── responsibilities.html.erb │ │ ├── show.html.erb │ │ └── _list.html.erb │ ├── devise │ │ ├── mailer │ │ │ ├── password_change.html.erb │ │ │ ├── confirmation_instructions.html.erb │ │ │ ├── unlock_instructions.html.erb │ │ │ └── reset_password_instructions.html.erb │ │ ├── unlocks │ │ │ └── new.html.erb │ │ ├── passwords │ │ │ ├── new.html.erb │ │ │ └── edit.html.erb │ │ ├── confirmations │ │ │ └── new.html.erb │ │ ├── sessions │ │ │ └── new.html.erb │ │ ├── registrations │ │ │ ├── new.html.erb │ │ │ └── edit.html.erb │ │ └── shared │ │ │ └── _links.html.erb │ ├── rakes │ │ ├── mailer │ │ │ ├── password_change.html.erb │ │ │ ├── confirmation_instructions.html.erb │ │ │ ├── unlock_instructions.html.erb │ │ │ └── reset_password_instructions.html.erb │ │ ├── unlocks │ │ │ └── new.html.erb │ │ ├── passwords │ │ │ ├── new.html.erb │ │ │ └── edit.html.erb │ │ ├── confirmations │ │ │ └── new.html.erb │ │ ├── sessions │ │ │ └── new.html.erb │ │ ├── registrations │ │ │ ├── new.html.erb │ │ │ └── edit.html.erb │ │ └── shared │ │ │ └── _links.html.erb │ ├── layouts │ │ ├── _footer.html.erb │ │ └── _home_intro.html.erb │ ├── cases │ │ ├── _case.html.erb │ │ └── index.html.erb │ ├── active_storage │ │ └── blobs │ │ │ └── _blob.html.erb │ ├── static_pages │ │ └── feedback.html.erb │ ├── rules │ │ └── index.html.erb │ ├── welcome │ │ └── index.html.erb │ └── analytics │ │ └── index.html.erb ├── controllers │ ├── concerns │ │ └── .keep │ ├── admin_controller.rb │ ├── rules_controller.rb │ ├── static_pages_controller.rb │ ├── application_controller.rb │ ├── extranet │ │ ├── application_controller.rb │ │ ├── terms_controller.rb │ │ ├── minority_opinions_controller.rb │ │ ├── case_files_controller.rb │ │ ├── superintendents_controller.rb │ │ ├── rules_controller.rb │ │ └── board_members_controller.rb │ ├── registrations_controller.rb │ ├── welcome_controller.rb │ ├── users_controller.rb │ ├── cases_controller.rb │ ├── analytics_controller.rb │ └── board_controller.rb ├── helpers │ ├── admin_helper.rb │ ├── terms_helper.rb │ ├── users_helper.rb │ ├── welcome_helper.rb │ ├── extranet │ │ ├── rules_helper.rb │ │ ├── case_files_helper.rb │ │ ├── minority_opinions_helper.rb │ │ └── minority_opinion_votes_helper.rb │ └── application_helper.rb ├── javascript │ └── packs │ │ ├── search.js │ │ ├── terms.coffee │ │ ├── admin.js.coffee │ │ ├── users.js.coffee │ │ ├── extranet │ │ ├── rules.coffee │ │ ├── case_files.coffee │ │ ├── minority_opinions.coffee │ │ ├── minority_opinion_votes.coffee │ │ └── board_member.js │ │ ├── table-scroll.js │ │ ├── users.js │ │ ├── case.js │ │ ├── board-members-voting-history.js │ │ ├── home.js │ │ ├── rules.js │ │ ├── policeboard.js │ │ ├── application.js │ │ └── responsive-init.js └── uploaders │ ├── image_uploader.rb │ └── case_file_uploader.rb ├── lib ├── assets │ ├── .keep │ ├── cases.xlsx │ ├── rules.xlsx │ ├── raw-data.xlsx │ ├── case-rules.xlsx │ ├── archive │ │ ├── cases.xlsx │ │ ├── case-rules.xlsx │ │ └── board-member-votes.xlsx │ ├── board-members.xlsx │ ├── superintendents.xlsx │ ├── board-member-terms.xlsx │ └── board-member-votes.xlsx ├── tasks │ ├── .keep │ └── kill_postgres_connections.rake └── templates │ └── erb │ └── scaffold │ └── _form.html.erb ├── .ruby-gemset ├── .ruby-version ├── .browserslistrc ├── vendor └── assets │ ├── javascripts │ ├── .keep │ └── jquery.readyselector.js │ └── stylesheets │ └── .keep ├── Procfile ├── .postcssrc.yml ├── public ├── intro-bg.jpg ├── robots.txt ├── 500.html ├── 422.html └── 404.html ├── .ebextensions ├── 05_node_install.config ├── 02app.config ├── 04_yarn.config ├── 01setup_swap.config └── 03_files.config ├── bin ├── rake ├── bundle ├── rails ├── webpack ├── webpack-dev-server ├── spring ├── yarn ├── update └── setup ├── logfile ├── config ├── environment.rb ├── initializers │ ├── session_store.rb │ ├── mime_types.rb │ ├── filter_parameter_logging.rb │ ├── application_controller_renderer.rb │ ├── cookies_serializer.rb │ ├── twitter.rb │ ├── backtrace_silencers.rb │ ├── postgresql_database_tasks.old │ ├── wrap_parameters.rb │ ├── inflections.rb │ ├── assets.rb │ ├── fog.rb │ ├── content_security_policy.rb │ ├── new_framework_defaults_5_2.rb │ └── new_framework_defaults_6_0.rb ├── webpack │ ├── test.js │ ├── production.js │ ├── loaders │ │ ├── jquery.js │ │ ├── datatables.js │ │ └── sparkline.js │ ├── development.js │ └── environment.js ├── boot.rb ├── spring.rb ├── tinymce.yml ├── locales │ ├── simple_form.en.yml │ └── en.yml ├── routes.rb ├── secrets.yml ├── application.rb ├── storage.yml ├── puma.rb ├── environments │ ├── test.rb │ └── development.rb └── webpacker.yml ├── config.ru ├── db ├── migrate │ ├── 20160601164054_add_files_to_cases.rb │ ├── 20160705151922_add_is_open_to_cases.rb │ ├── 20160613120827_add_is_active_to_case.rb │ ├── 20180329175930_add_category_to_cases.rb │ ├── 20150413052034_add_rank_to_defendant.rb │ ├── 20160523201643_add_image_to_board_members.rb │ ├── 20180411045332_add_appealed_to_cases.rb │ ├── 20160613164548_add_majority_decision_to_case.rb │ ├── 20171212190548_add_minority_opinion_to_cases.rb │ ├── 20201007191242_add_investigated_by_to_cases.rb │ ├── 20150413051920_remove_defendant_from_ranks.rb │ ├── 20150413042157_create_votes.rb │ ├── 20180113231902_create_minority_opinions.rb │ ├── 20150413042330_create_outcomes.rb │ ├── 20180115000053_add_number_of_board_members_to_minority_opinion.rb │ ├── 20150413042738_create_authorities.rb │ ├── 20180111213644_add_date_time_to_minority_opinion.rb │ ├── 20150413042630_create_rules.rb │ ├── 20150413042818_create_categories.rb │ ├── 20150413045339_create_complaints.rb │ ├── 20150711215237_add_case_rule_order.rb │ ├── 20150413041826_create_terms.rb │ ├── 20150413040242_create_defendants.rb │ ├── 20150413040650_create_ranks.rb │ ├── 20180111213003_add_minority_opinion_table.rb │ ├── 20180113234303_add_minority_opinion_text_to_minority_opinion.rb │ ├── 20190808063729_create_superintendents.rb │ ├── 20150413050329_create_case_rules.rb │ ├── 20150711220746_create_case_rule_counts.rb │ ├── 20150413050006_create_board_member_votes.rb │ ├── 20180114233929_add_board_members_to_minority_opinion.rb │ ├── 20150413044606_create_cases.rb │ ├── 20210702212851_migrate_case_rule_count_to_action_text.rb │ ├── 20150413041739_create_board_members.rb │ ├── 20200716210533_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb │ ├── 20210625201619_create_action_text_tables.action_text.rb │ ├── 20211127153204_convert_to_rich_text.rb │ ├── 20180413200531_update_minority_opnions_associations.rb │ ├── 20210625201618_create_active_storage_tables.active_storage.rb │ └── 20160210211917_devise_create_users.rb └── seeds.rb ├── .gitpod.Dockerfile ├── Rakefile ├── postcss.config.js ├── .babelrc ├── .elasticbeanstalk └── config.yml ├── .gitpod.yml ├── package.json ├── .gitignore ├── LICENSE ├── rails-vagrant-provision.sh ├── babel.config.js └── Gemfile /log/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | -global -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.0.2 2 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | defaults 2 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/extranet/cases/_: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/helpers/admin_helper.rb: -------------------------------------------------------------------------------- 1 | module AdminHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/terms_helper.rb: -------------------------------------------------------------------------------- 1 | module TermsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/users_helper.rb: -------------------------------------------------------------------------------- 1 | module UsersHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/welcome_helper.rb: -------------------------------------------------------------------------------- 1 | module WelcomeHelper 2 | end 3 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: puma -C /opt/elasticbeanstalk/config/private/pumaconf.rb -------------------------------------------------------------------------------- /app/models/outcome.rb: -------------------------------------------------------------------------------- 1 | class Outcome < ActiveRecord::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/views/fields/password_field/_index.html.erb: -------------------------------------------------------------------------------- 1 | <%#= field.to_s %> 2 | -------------------------------------------------------------------------------- /app/views/fields/password_field/_show.html.erb: -------------------------------------------------------------------------------- 1 | <%#= field.to_s %> 2 | -------------------------------------------------------------------------------- /.postcssrc.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | postcss-import: {} 3 | postcss-cssnext: {} 4 | -------------------------------------------------------------------------------- /app/helpers/extranet/rules_helper.rb: -------------------------------------------------------------------------------- 1 | module Extranet::RulesHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/models/superintendent.rb: -------------------------------------------------------------------------------- 1 | class Superintendent < ActiveRecord::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/views/users/show.html.erb: -------------------------------------------------------------------------------- 1 |

You are signed in as <%= @user.email %>

2 | -------------------------------------------------------------------------------- /app/helpers/extranet/case_files_helper.rb: -------------------------------------------------------------------------------- 1 | module Extranet::CaseFilesHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/models/rank.rb: -------------------------------------------------------------------------------- 1 | class Rank < ActiveRecord::Base 2 | has_many :defendant 3 | end 4 | -------------------------------------------------------------------------------- /app/models/complaint.rb: -------------------------------------------------------------------------------- 1 | class Complaint < ActiveRecord::Base 2 | belongs_to :case 3 | end 4 | -------------------------------------------------------------------------------- /app/helpers/extranet/minority_opinions_helper.rb: -------------------------------------------------------------------------------- 1 | module Extranet::MinorityOpinionsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/models/authority.rb: -------------------------------------------------------------------------------- 1 | class Authority < ActiveRecord::Base 2 | has_many :categories 3 | end 4 | -------------------------------------------------------------------------------- /app/models/category.rb: -------------------------------------------------------------------------------- 1 | class Category < ActiveRecord::Base 2 | belongs_to :authority 3 | end 4 | -------------------------------------------------------------------------------- /app/helpers/extranet/minority_opinion_votes_helper.rb: -------------------------------------------------------------------------------- 1 | module Extranet::MinorityOpinionVotesHelper 2 | end 3 | -------------------------------------------------------------------------------- /public/intro-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/public/intro-bg.jpg -------------------------------------------------------------------------------- /.ebextensions/05_node_install.config: -------------------------------------------------------------------------------- 1 | container_commands: 2 | 01_install_packages: 3 | command: 'yarn install' -------------------------------------------------------------------------------- /app/views/board/new.html.erb: -------------------------------------------------------------------------------- 1 |

New board member

2 | 3 | <%= form_for(@member) do |f| %> 4 | 5 | <% end %> -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /lib/assets/cases.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/lib/assets/cases.xlsx -------------------------------------------------------------------------------- /lib/assets/rules.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/lib/assets/rules.xlsx -------------------------------------------------------------------------------- /app/controllers/admin_controller.rb: -------------------------------------------------------------------------------- 1 | class AdminController < ApplicationController 2 | def index 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /lib/assets/raw-data.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/lib/assets/raw-data.xlsx -------------------------------------------------------------------------------- /app/assets/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/icon.png -------------------------------------------------------------------------------- /app/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/logo.png -------------------------------------------------------------------------------- /app/views/fields/password_field/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= f.label field.attribute %> 2 | <%= f.password_field field.attribute %> 3 | -------------------------------------------------------------------------------- /lib/assets/case-rules.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/lib/assets/case-rules.xlsx -------------------------------------------------------------------------------- /app/assets/images/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/facebook.png -------------------------------------------------------------------------------- /app/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/favicon.ico -------------------------------------------------------------------------------- /app/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/favicon.png -------------------------------------------------------------------------------- /app/assets/images/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/twitter.png -------------------------------------------------------------------------------- /lib/assets/archive/cases.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/lib/assets/archive/cases.xlsx -------------------------------------------------------------------------------- /lib/assets/board-members.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/lib/assets/board-members.xlsx -------------------------------------------------------------------------------- /app/views/extranet/rules/show.html.erb: -------------------------------------------------------------------------------- 1 |

Extranet::Rules#show

2 |

Find me in app/views/extranet/rules/show.html.erb

3 | -------------------------------------------------------------------------------- /lib/assets/superintendents.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/lib/assets/superintendents.xlsx -------------------------------------------------------------------------------- /app/assets/images/logo-reverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/logo-reverse.png -------------------------------------------------------------------------------- /app/models/case_rule_count.rb: -------------------------------------------------------------------------------- 1 | class CaseRuleCount < ActiveRecord::Base 2 | belongs_to :case_rule 3 | has_rich_text :content 4 | end 5 | -------------------------------------------------------------------------------- /app/views/extranet/board_members/show.html.erb: -------------------------------------------------------------------------------- 1 |

Extranet::Rules#show

2 |

Find me in app/views/extranet/rules/show.html.erb

3 | -------------------------------------------------------------------------------- /app/views/extranet/rules/create.html.erb: -------------------------------------------------------------------------------- 1 |

Extranet::Rules#create

2 |

Find me in app/views/extranet/rules/create.html.erb

3 | -------------------------------------------------------------------------------- /app/views/extranet/rules/update.html.erb: -------------------------------------------------------------------------------- 1 |

Extranet::Rules#update

2 |

Find me in app/views/extranet/rules/update.html.erb

3 | -------------------------------------------------------------------------------- /lib/assets/archive/case-rules.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/lib/assets/archive/case-rules.xlsx -------------------------------------------------------------------------------- /lib/assets/board-member-terms.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/lib/assets/board-member-terms.xlsx -------------------------------------------------------------------------------- /lib/assets/board-member-votes.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/lib/assets/board-member-votes.xlsx -------------------------------------------------------------------------------- /app/views/extranet/rules/destroy.html.erb: -------------------------------------------------------------------------------- 1 |

Extranet::Rules#destroy

2 |

Find me in app/views/extranet/rules/destroy.html.erb

3 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /app/controllers/rules_controller.rb: -------------------------------------------------------------------------------- 1 | class RulesController < ApplicationController 2 | def index 3 | @rules = Rule.order(:code) 4 | end 5 | end -------------------------------------------------------------------------------- /app/views/extranet/board_members/create.html.erb: -------------------------------------------------------------------------------- 1 |

Extranet::Rules#create

2 |

Find me in app/views/extranet/rules/create.html.erb

3 | -------------------------------------------------------------------------------- /app/views/extranet/board_members/destroy.html.erb: -------------------------------------------------------------------------------- 1 |

Extranet::Rules#destroy

2 |

Find me in app/views/extranet/rules/destroy.html.erb

3 | -------------------------------------------------------------------------------- /app/views/extranet/board_members/update.html.erb: -------------------------------------------------------------------------------- 1 |

Extranet::Rules#update

2 |

Find me in app/views/extranet/rules/update.html.erb

3 | -------------------------------------------------------------------------------- /lib/assets/archive/board-member-votes.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/lib/assets/archive/board-member-votes.xlsx -------------------------------------------------------------------------------- /logfile: -------------------------------------------------------------------------------- 1 | FATAL: lock file "postmaster.pid" already exists 2 | HINT: Is another postmaster (PID 347) running in data directory "/usr/local/var/postgres"? 3 | -------------------------------------------------------------------------------- /app/assets/images/board-members/rita-fry.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/rita-fry.jpg -------------------------------------------------------------------------------- /app/views/extranet/board_members/new.html.erb: -------------------------------------------------------------------------------- 1 | <% title "New rule" %> 2 | 3 |
4 | <%= render :partial => "form" %> 5 |
6 | -------------------------------------------------------------------------------- /app/views/extranet/superintendents/new.html.erb: -------------------------------------------------------------------------------- 1 | <% title "Add Superintendent" %> 2 | 3 |
4 | <%= render :partial => "form" %> 5 |
-------------------------------------------------------------------------------- /app/assets/images/board-members/placeholder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/placeholder.jpg -------------------------------------------------------------------------------- /app/assets/images/fallback/nil_board_image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/fallback/nil_board_image.jpg -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/assets/images/board-members/arthur-j-smith.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/arthur-j-smith.jpg -------------------------------------------------------------------------------- /app/assets/images/board-members/george-vlecich.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/george-vlecich.jpg -------------------------------------------------------------------------------- /app/assets/images/board-members/ghian-foreman.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/ghian-foreman.jpg -------------------------------------------------------------------------------- /app/assets/images/board-members/michael-eaddy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/michael-eaddy.jpg -------------------------------------------------------------------------------- /app/assets/images/board-members/patricia-bobb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/patricia-bobb.jpg -------------------------------------------------------------------------------- /app/assets/images/board-members/scott-j-davis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/scott-j-davis.jpg -------------------------------------------------------------------------------- /app/assets/images/board-members/william-conlon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/william-conlon.jpg -------------------------------------------------------------------------------- /app/controllers/static_pages_controller.rb: -------------------------------------------------------------------------------- 1 | class StaticPagesController < ApplicationController 2 | def about 3 | end 4 | 5 | def feedback 6 | end 7 | end -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /app/assets/images/board-members/elisa-rodriguez.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/elisa-rodriguez.jpg -------------------------------------------------------------------------------- /app/assets/images/board-members/melissa-ballate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/melissa-ballate.jpg -------------------------------------------------------------------------------- /app/assets/images/board-members/susan-l-mckeever.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/susan-l-mckeever.jpg -------------------------------------------------------------------------------- /app/assets/images/board-members/victor-gonzales.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/victor-gonzales.jpg -------------------------------------------------------------------------------- /app/assets/images/board-members/william-kirkling.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/william-kirkling.jpg -------------------------------------------------------------------------------- /app/assets/images/board_member/image/23/P1090535.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board_member/image/23/P1090535.JPG -------------------------------------------------------------------------------- /app/assets/images/fallback/thumb_nil_board_image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/fallback/thumb_nil_board_image.jpg -------------------------------------------------------------------------------- /app/views/devise/mailer/password_change.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

We're contacting you to notify you that your password has been changed.

4 | -------------------------------------------------------------------------------- /app/views/rakes/mailer/password_change.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

We're contacting you to notify you that your password has been changed.

4 | -------------------------------------------------------------------------------- /app/assets/images/board-members/demetrius-e-carney.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/demetrius-e-carney.jpg -------------------------------------------------------------------------------- /app/assets/images/board-members/phyllis-l-apelbaum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/phyllis-l-apelbaum.jpg -------------------------------------------------------------------------------- /app/assets/images/board-members/rev-johnny-l-miller.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/rev-johnny-l-miller.jpg -------------------------------------------------------------------------------- /app/assets/images/board-members/rhoda-davis-sweeney.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board-members/rhoda-davis-sweeney.jpg -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /db/migrate/20160601164054_add_files_to_cases.rb: -------------------------------------------------------------------------------- 1 | class AddFilesToCases < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :cases, :files, :json 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/views/extranet/rules/new.html.erb: -------------------------------------------------------------------------------- 1 | <% title "New rule" %> 2 | 3 | <%= render :partial => "form" %> 4 | 5 |

<%= link_to "Back to rules", extranet_rules_path %>

6 | 7 | -------------------------------------------------------------------------------- /db/migrate/20160705151922_add_is_open_to_cases.rb: -------------------------------------------------------------------------------- 1 | class AddIsOpenToCases < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :cases, :is_open, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/assets/images/board_member/image/23/thumb_P1090535.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicago-justice-project/policeboard/master/app/assets/images/board_member/image/23/thumb_P1090535.JPG -------------------------------------------------------------------------------- /db/migrate/20160613120827_add_is_active_to_case.rb: -------------------------------------------------------------------------------- 1 | class AddIsActiveToCase < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :cases, :is_active, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180329175930_add_category_to_cases.rb: -------------------------------------------------------------------------------- 1 | class AddCategoryToCases < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :cases, :category, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /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: '_policeboard_session' 4 | -------------------------------------------------------------------------------- /config/webpack/test.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development' 2 | 3 | const environment = require('./environment') 4 | 5 | module.exports = environment.toWebpackConfig() 6 | -------------------------------------------------------------------------------- /app/models/defendant.rb: -------------------------------------------------------------------------------- 1 | class Defendant < ActiveRecord::Base 2 | has_many :cases 3 | belongs_to :rank 4 | 5 | def full_name 6 | [first_name, last_name].join(' ') 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /config/webpack/production.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = process.env.NODE_ENV || 'production' 2 | 3 | const environment = require('./environment') 4 | 5 | module.exports = environment.toWebpackConfig() 6 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /db/migrate/20150413052034_add_rank_to_defendant.rb: -------------------------------------------------------------------------------- 1 | class AddRankToDefendant < ActiveRecord::Migration[4.2] 2 | def change 3 | add_reference :defendants, :rank, index: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160523201643_add_image_to_board_members.rb: -------------------------------------------------------------------------------- 1 | class AddImageToBoardMembers < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :board_members, :image, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180411045332_add_appealed_to_cases.rb: -------------------------------------------------------------------------------- 1 | class AddAppealedToCases < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :cases, :appealed, :boolean, default: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/views/extranet/rules/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% title "Edit rule" %> 2 | <% body_id "extranet-rule-detail" %> 3 | 4 | 5 |
6 | <%= render :partial => "form" %> 7 |
8 | 9 | -------------------------------------------------------------------------------- /db/migrate/20160613164548_add_majority_decision_to_case.rb: -------------------------------------------------------------------------------- 1 | class AddMajorityDecisionToCase < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :cases, :majority_decision, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20171212190548_add_minority_opinion_to_cases.rb: -------------------------------------------------------------------------------- 1 | class AddMinorityOpinionToCases < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :cases, :minority_opinion, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20201007191242_add_investigated_by_to_cases.rb: -------------------------------------------------------------------------------- 1 | class AddInvestigatedByToCases < ActiveRecord::Migration[6.0] 2 | def change 3 | add_column :cases, :investigated_by, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/assets/stylesheets/terms.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Terms controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/views/board/_member_cases.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

Recent cases

3 | 6 |
7 | -------------------------------------------------------------------------------- /app/views/board/_vote_list.html.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/extranet/superintendents/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% title "Edit Superintendent" %> 2 | <% body_id "extranet-superintendent-detail" %> 3 | 4 |
5 | <%= render :partial => "form" %> 6 |
-------------------------------------------------------------------------------- /db/migrate/20150413051920_remove_defendant_from_ranks.rb: -------------------------------------------------------------------------------- 1 | class RemoveDefendantFromRanks < ActiveRecord::Migration[4.2] 2 | def change 3 | remove_reference :ranks, :defendant, index: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/assets/stylesheets/admin.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the admin controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/users.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the users controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/models/board_member_vote.rb: -------------------------------------------------------------------------------- 1 | class BoardMemberVote < ActiveRecord::Base 2 | belongs_to :case 3 | belongs_to :board_member 4 | belongs_to :vote, optional: true 5 | has_rich_text :dissent_description 6 | end 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/assets/stylesheets/extranet/rules.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the extranet/rules controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/extranet/case_files.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the extranet/CaseFiles controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/javascript/packs/search.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | $().ready(function () { 3 | /* Search */ 4 | $('#search-toggle').on('click touchstart', function(){ 5 | $('#nav .search').toggle(); 6 | return false; 7 | }); 8 | }); -------------------------------------------------------------------------------- /db/migrate/20150413042157_create_votes.rb: -------------------------------------------------------------------------------- 1 | class CreateVotes < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :votes do |t| 4 | t.string :name 5 | 6 | t.timestamps 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /db/migrate/20180113231902_create_minority_opinions.rb: -------------------------------------------------------------------------------- 1 | class CreateMinorityOpinions < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :minority_opinions do |t| 4 | 5 | t.timestamps null: false 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/javascript/packs/terms.coffee: -------------------------------------------------------------------------------- 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 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /app/models/rule.rb: -------------------------------------------------------------------------------- 1 | class Rule < ActiveRecord::Base 2 | include ActionView::Helpers::TextHelper 3 | has_rich_text :description 4 | has_rich_text :comment 5 | def item 6 | "Rule #{code} #{ description.to_plain_text.truncate(40)}" 7 | end 8 | end -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /db/migrate/20150413042330_create_outcomes.rb: -------------------------------------------------------------------------------- 1 | class CreateOutcomes < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :outcomes do |t| 4 | t.string :name 5 | 6 | t.timestamps 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /.gitpod.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gitpod/workspace-postgres 2 | 3 | # Install custom tools, runtimes, etc. 4 | # For example "bastet", a command-line tetris clone: 5 | # RUN brew install bastet 6 | # 7 | # More information: https://www.gitpod.io/docs/config-docker/ 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/extranet/minority_opinions.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the extranet/minority_opinions controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/javascript/packs/admin.js.coffee: -------------------------------------------------------------------------------- 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 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /app/javascript/packs/users.js.coffee: -------------------------------------------------------------------------------- 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 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /db/migrate/20180115000053_add_number_of_board_members_to_minority_opinion.rb: -------------------------------------------------------------------------------- 1 | class AddNumberOfBoardMembersToMinorityOpinion < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :minority_opinions, :number_of_votes, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/javascript/packs/extranet/rules.coffee: -------------------------------------------------------------------------------- 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 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /db/migrate/20150413042738_create_authorities.rb: -------------------------------------------------------------------------------- 1 | class CreateAuthorities < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :authorities do |t| 4 | t.string :name 5 | 6 | t.timestamps 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/assets/stylesheets/extranet/minority_opinion_votes.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the extranet/minority_opinion_votes controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/javascript/packs/extranet/case_files.coffee: -------------------------------------------------------------------------------- 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 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /config/webpack/loaders/jquery.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | test: require.resolve("jquery"), 3 | loader: "expose-loader", 4 | options: { 5 | exposes: { 6 | globalName: "$", 7 | override: true, 8 | } 9 | }, 10 | }; -------------------------------------------------------------------------------- /app/javascript/packs/extranet/minority_opinions.coffee: -------------------------------------------------------------------------------- 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 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /app/views/devise/mailer/confirmation_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Welcome <%= @email %>!

2 | 3 |

You can confirm your account email through the link below:

4 | 5 |

<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>

6 | -------------------------------------------------------------------------------- /app/views/rakes/mailer/confirmation_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Welcome <%= @email %>!

2 | 3 |

You can confirm your account email through the link below:

4 | 5 |

<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>

6 | -------------------------------------------------------------------------------- /app/javascript/packs/extranet/minority_opinion_votes.coffee: -------------------------------------------------------------------------------- 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 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/views/board/_member.html.erb: -------------------------------------------------------------------------------- 1 |
<%= image_tag member.photo, alt: [member.full_name, member.board_position].reject(&:blank?).join(', '), size: '70' %>
2 |

<%= link_to [member.full_name, member.board_position].reject(&:blank?).join(', ') , board_path(member) %>

-------------------------------------------------------------------------------- /db/migrate/20180111213644_add_date_time_to_minority_opinion.rb: -------------------------------------------------------------------------------- 1 | class AddDateTimeToMinorityOpinion < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :minority_opinion, :created_at, :datetime 4 | add_column :minority_opinion, :updated_at, :datetime 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /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/spring.rb: -------------------------------------------------------------------------------- 1 | Spring.after_fork do 2 | if ENV['DEBUGGER_STORED_RUBYLIB'] 3 | ENV['DEBUGGER_STORED_RUBYLIB'].split(File::PATH_SEPARATOR).each do |path| 4 | next unless path =~ /ruby-debug-ide/ 5 | load path + '/ruby-debug-ide/multiprocess/starter.rb' 6 | end 7 | end 8 | end -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-import'), 4 | require('postcss-flexbugs-fixes'), 5 | require('postcss-preset-env')({ 6 | autoprefixer: { 7 | flexbox: 'no-2009' 8 | }, 9 | stage: 3 10 | }) 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /app/models/term.rb: -------------------------------------------------------------------------------- 1 | class Term < ActiveRecord::Base 2 | belongs_to :board_member 3 | 4 | def start_at_string 5 | self.start.nil? ? "" : start.to_s(:db) 6 | end 7 | 8 | def start_at_string=(start_at_string) 9 | self.start = Time.parse(start_at_string) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /config/webpack/loaders/datatables.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | test: /datatables\.net.*/, 3 | loader: "imports-loader", 4 | options: { 5 | // Disables AMD plugin as DataTables.net 6 | // checks for AMD before CommonJS. 7 | additionalCode: "var define = false;", 8 | }, 9 | }; -------------------------------------------------------------------------------- /db/migrate/20150413042630_create_rules.rb: -------------------------------------------------------------------------------- 1 | class CreateRules < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :rules do |t| 4 | t.integer :code 5 | t.text :description 6 | t.text :comment 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20150413042818_create_categories.rb: -------------------------------------------------------------------------------- 1 | class CreateCategories < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :categories do |t| 4 | t.string :name 5 | t.references :authority, index: true 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20150413045339_create_complaints.rb: -------------------------------------------------------------------------------- 1 | class CreateComplaints < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :complaints do |t| 4 | t.string :number 5 | t.references :case, index: true 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20150711215237_add_case_rule_order.rb: -------------------------------------------------------------------------------- 1 | class AddCaseRuleOrder < ActiveRecord::Migration[4.2] 2 | def change 3 | remove_column :case_rules, :content, :text 4 | remove_column :case_rules, :is_guilty, :boolean 5 | add_column :case_rules, :rule_order, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/javascript/packs/table-scroll.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | $().ready(function () { 3 | // Wrap tables with a div 4 | if ($(".table-scroller").size() == 0) $("table").wrap("
") 5 | $(".table-scroller").css("overflow", "auto").css("-webkit-overflow-scrolling", "touch"); 6 | }); -------------------------------------------------------------------------------- /app/models/case_rule.rb: -------------------------------------------------------------------------------- 1 | class CaseRule < ActiveRecord::Base 2 | belongs_to :case 3 | belongs_to :rule 4 | has_many :case_rule_counts, :dependent => :destroy 5 | 6 | accepts_nested_attributes_for :case_rule_counts, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true 7 | 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20150413041826_create_terms.rb: -------------------------------------------------------------------------------- 1 | class CreateTerms < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :terms do |t| 4 | t.date :start 5 | t.date :end 6 | t.references :board_member, index: true 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /config/webpack/loaders/sparkline.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | test: require.resolve("jquery-sparkline"), 3 | loader: "imports-loader", 4 | options: { 5 | // Disables AMD plugin as DataTables.net 6 | // checks for AMD before CommonJS. 7 | additionalCode: "var define = false;", 8 | }, 9 | }; -------------------------------------------------------------------------------- /app/models/vote.rb: -------------------------------------------------------------------------------- 1 | class Vote < ActiveRecord::Base 2 | def self.AGREE 3 | Vote.find_by_name("Agree").try(:id) 4 | end 5 | 6 | def self.DISSENT 7 | Vote.find_by_name("Dissent").try(:id) 8 | end 9 | 10 | def self.ABSTAIN 11 | Vote.find_by_name("Abstain").try(:id) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20150413040242_create_defendants.rb: -------------------------------------------------------------------------------- 1 | class CreateDefendants < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :defendants do |t| 4 | t.string :first_name 5 | t.string :last_name 6 | t.string :number 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20150413040650_create_ranks.rb: -------------------------------------------------------------------------------- 1 | class CreateRanks < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :ranks do |t| 4 | t.string :name 5 | t.boolean :is_civilian 6 | t.references :defendant, index: true 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20180111213003_add_minority_opinion_table.rb: -------------------------------------------------------------------------------- 1 | class AddMinorityOpinionTable < ActiveRecord::Migration[4.2] 2 | def change 3 | remove_column :cases, :minority_opinion, :text 4 | create_table :minority_opinion do |t| 5 | t.integer :case_id 6 | t.text :opinion_text 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20180113234303_add_minority_opinion_text_to_minority_opinion.rb: -------------------------------------------------------------------------------- 1 | class AddMinorityOpinionTextToMinorityOpinion < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :minority_opinions, :opinion_text, :text 4 | add_column :minority_opinions, :case_id, :integer 5 | drop_table :minority_opinion 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/views/devise/mailer/unlock_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

Your account has been locked due to an excessive number of unsuccessful sign in attempts.

4 | 5 |

Click the link below to unlock your account:

6 | 7 |

<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>

8 | -------------------------------------------------------------------------------- /app/views/rakes/mailer/unlock_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

Your account has been locked due to an excessive number of unsuccessful sign in attempts.

4 | 5 |

Click the link below to unlock your account:

6 | 7 |

<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>

8 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | 6 | def after_sign_in_path_for(resource) 7 | extranet_cases_path 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/controllers/extranet/application_controller.rb: -------------------------------------------------------------------------------- 1 | module Extranet 2 | class ApplicationController < ActionController::Base 3 | layout 'admin' 4 | before_action :authenticate_user! 5 | before_action :authenticate_admin 6 | 7 | def authenticate_admin 8 | # TODO Add authentication logic here. 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /config/webpack/development.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge'); 2 | process.env.NODE_ENV = process.env.NODE_ENV || 'development' 3 | 4 | 5 | const environment = require('./environment') 6 | 7 | const custom = { 8 | optimization: { 9 | minimize: false 10 | } 11 | }; 12 | 13 | module.exports = merge(environment.toWebpackConfig(),custom); 14 | -------------------------------------------------------------------------------- /db/migrate/20190808063729_create_superintendents.rb: -------------------------------------------------------------------------------- 1 | class CreateSuperintendents < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :superintendents do |t| 4 | t.string :first_name 5 | t.string :last_name 6 | t.date :start_of_term 7 | t.date :end_of_term 8 | 9 | t.timestamps null: false 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20150413050329_create_case_rules.rb: -------------------------------------------------------------------------------- 1 | class CreateCaseRules < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :case_rules do |t| 4 | t.references :case, index: true 5 | t.references :rule, index: true 6 | t.text :content 7 | t.boolean :is_guilty 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/views/extranet/cases/new.html.erb: -------------------------------------------------------------------------------- 1 | <% title "New case" %> 2 | <% body_id "extranet-case-detail" %> 3 | 4 |
5 | <%= render :partial => "form" %> 6 |
7 | 8 |

<%= link_to "Back to cases", extranet_cases_path %>

9 | 10 | <%= content_tag 'div', '', id: 'data', data: {isNew: 'true'} %> 11 | <%= javascript_pack_tag "extranet/case" %> -------------------------------------------------------------------------------- /config/tinymce.yml: -------------------------------------------------------------------------------- 1 | menubar: false, 2 | toolbar1: styleselect | undo redo | bold italic | bullist numlist | sub sup | indent outdent | justifyleft justifycenter justifyright | link unlink anchor | table | image media | charmap | hr | removeformat code 3 | plugins: 4 | - image 5 | - link 6 | - anchor 7 | - charmap 8 | - hr 9 | - lists 10 | - media 11 | - table 12 | -------------------------------------------------------------------------------- /db/migrate/20150711220746_create_case_rule_counts.rb: -------------------------------------------------------------------------------- 1 | class CreateCaseRuleCounts < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :case_rule_counts do |t| 4 | t.references :case_rule, index: true 5 | t.integer :count_order 6 | t.text :content 7 | t.boolean :is_guilty 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/models/minority_opinion.rb: -------------------------------------------------------------------------------- 1 | class MinorityOpinion < ActiveRecord::Base 2 | belongs_to :case 3 | 4 | belongs_to :board_member_one, class_name: "BoardMember" 5 | belongs_to :board_member_two, class_name: "BoardMember" 6 | belongs_to :board_member_three, class_name: "BoardMember" 7 | belongs_to :board_member_four, class_name: "BoardMember" 8 | has_rich_text :opinion_text 9 | end 10 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": "> 1%", 7 | "uglify": true 8 | }, 9 | "useBuiltIns": true 10 | }] 11 | ], 12 | 13 | "plugins": [ 14 | "syntax-dynamic-import", 15 | "transform-object-rest-spread", 16 | ["transform-class-properties", { "spec": true }] 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /app/controllers/registrations_controller.rb: -------------------------------------------------------------------------------- 1 | class RegistrationsController < Devise::RegistrationsController 2 | 3 | before_action :one_user_registered? 4 | 5 | protected 6 | 7 | def one_user_registered? 8 | if ((User.count == 1) & (user_signed_in?)) 9 | redirect_to root_path 10 | elsif User.count == 1 11 | redirect_to new_user_session_path 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /config/initializers/twitter.rb: -------------------------------------------------------------------------------- 1 | module Twitter 2 | mattr_accessor :client 3 | 4 | self.client = Twitter::REST::Client.new do |config| 5 | config.consumer_key = ENV["TWITTER_CONSUMER_KEY"] 6 | config.consumer_secret = ENV["TWITTER_CONSUMER_SECRET"] 7 | config.access_token = ENV["TWITTER_ACCESS_TOKEN"] 8 | config.access_token_secret = ENV["TWITTER_ACCESS_SECRET"] 9 | end 10 | end -------------------------------------------------------------------------------- /app/javascript/packs/extranet/board_member.js: -------------------------------------------------------------------------------- 1 | /*$('#extranet-board-member-detail').ready(function(){ 2 | 3 | $(document).on('change', '#board_member_remove_image', function (){ 4 | if(this.checked){ 5 | console.log('remove image is checked'); 6 | var $img = $(this).closest('.form-row').find('img'); 7 | $img.hide(); 8 | $this.hide(); 9 | } 10 | }); 11 | 12 | }(jQuery);*/ 13 | -------------------------------------------------------------------------------- /app/javascript/packs/users.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | import dt from 'datatables.net'; 3 | 4 | $('#admin-users-index').ready(function () { 5 | $('#users-list').DataTable({ 6 | aoColumns: [ 7 | { iDataSort: 0 }, //1: email 8 | null, //2: last sign in 9 | null, //3: delete 10 | ], 11 | info: false, 12 | order: [[ 0, 'asc']], 13 | paging: false, 14 | searching: true 15 | }); 16 | }); -------------------------------------------------------------------------------- /db/migrate/20150413050006_create_board_member_votes.rb: -------------------------------------------------------------------------------- 1 | class CreateBoardMemberVotes < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :board_member_votes do |t| 4 | t.references :case, index: true 5 | t.references :board_member, index: true 6 | t.references :vote, index: true 7 | t.text :dissent_description 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | # Include default devise modules. Others available are: 3 | # :confirmable, :lockable, :timeoutable and :omniauthable 4 | # Original config: 5 | # devise :database_authenticatable, :registerable, 6 | # :recoverable, :rememberable, :trackable, :validatable 7 | 8 | devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20180114233929_add_board_members_to_minority_opinion.rb: -------------------------------------------------------------------------------- 1 | class AddBoardMembersToMinorityOpinion < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :minority_opinions, :board_member_one, :string 4 | add_column :minority_opinions, :board_member_two, :string 5 | add_column :minority_opinions, :board_member_three, :string 6 | add_column :minority_opinions, :board_member_four, :string 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /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/controllers/welcome_controller.rb: -------------------------------------------------------------------------------- 1 | class WelcomeController < ApplicationController 2 | def index 3 | @cases = Case.where(is_active: true).where.not(recommended_outcome_id: nil).and(Case.where.not(decided_outcome_id: nil)) 4 | @case_outcomes = @cases.group(:recommended_outcome_id, :decided_outcome_id).count 5 | @board_members = BoardMember.order(board_position: :asc, last_name: :asc).select{ |bm| bm.active == true } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/tasks/kill_postgres_connections.rake: -------------------------------------------------------------------------------- 1 | #lib/tasks/kill_postgres_connections.rake 2 | desc "Kill active postgres connection" 3 | task :kill_postgres_connections => :environment do 4 | db_name = "#{File.basename(Rails.root)}_#{Rails.env}" 5 | sh = < 2 | <% body_id "extranet-case-detail" %> 3 | 4 | 5 |
6 | <%= render :partial => "form" %> 7 |
8 | 9 | <%= javascript_pack_tag "extranet/case" %> 10 | 11 | <%= stylesheet_link_tag "https://cdnjs.cloudflare.com/ajax/libs/trix/1.3.1/trix.min.css"%> 12 | -------------------------------------------------------------------------------- /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| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /db/migrate/20150413044606_create_cases.rb: -------------------------------------------------------------------------------- 1 | class CreateCases < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :cases do |t| 4 | t.string :number 5 | t.references :defendant, index: true 6 | t.date :date_initiated 7 | t.date :date_decided 8 | t.references :recommended_outcome, index: true 9 | t.references :decided_outcome, index: true 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/views/devise/mailer/reset_password_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

Someone has requested a link to change your password. You can do this through the link below.

4 | 5 |

<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>

6 | 7 |

If you didn't request this, please ignore this email.

8 |

Your password won't change until you access the link above and create a new one.

9 | -------------------------------------------------------------------------------- /app/views/rakes/mailer/reset_password_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

Someone has requested a link to change your password. You can do this through the link below.

4 | 5 |

<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>

6 | 7 |

If you didn't request this, please ignore this email.

8 |

Your password won't change until you access the link above and create a new one.

9 | -------------------------------------------------------------------------------- /app/views/layouts/_footer.html.erb: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /db/migrate/20210702212851_migrate_case_rule_count_to_action_text.rb: -------------------------------------------------------------------------------- 1 | class MigrateCaseRuleCountToActionText < ActiveRecord::Migration[6.1] 2 | include ActionView::Helpers::TextHelper 3 | def change 4 | rename_column :case_rule_counts, :content, :content_old 5 | CaseRuleCount.all.each do |caseRuleCount| 6 | caseRuleCount.update_attribute(:content, simple_format(caseRuleCount.content_old)) 7 | end 8 | remove_column :case_rule_counts, :content_old 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /bin/webpack: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" 4 | ENV["NODE_ENV"] ||= "development" 5 | 6 | require "pathname" 7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 8 | Pathname.new(__FILE__).realpath) 9 | 10 | require "bundler/setup" 11 | 12 | require "webpacker" 13 | require "webpacker/webpack_runner" 14 | 15 | APP_ROOT = File.expand_path("..", __dir__) 16 | Dir.chdir(APP_ROOT) do 17 | Webpacker::WebpackRunner.run(ARGV) 18 | end 19 | -------------------------------------------------------------------------------- /.ebextensions/02app.config: -------------------------------------------------------------------------------- 1 | # .ebextensions/packages.config 2 | option_settings: 3 | aws:elasticbeanstalk:application:environment: 4 | LOGGING: debug 5 | packages: 6 | yum: 7 | amazon-linux-extras: [] 8 | git: [] 9 | patch: [] 10 | commands: 11 | 01_postgres_activate: 12 | command: sudo amazon-linux-extras enable postgresql11 13 | 02_postgres_install: 14 | command: sudo yum install -y postgresql-devel 15 | 16 | 17 | -------------------------------------------------------------------------------- /db/migrate/20150413041739_create_board_members.rb: -------------------------------------------------------------------------------- 1 | class CreateBoardMembers < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :board_members do |t| 4 | t.string :first_name 5 | t.string :last_name 6 | t.string :board_position 7 | t.string :job_title 8 | t.string :organization 9 | t.string :facebook_handle 10 | t.string :twitter_handle 11 | t.string :linkedin_handle 12 | 13 | t.timestamps 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /bin/webpack-dev-server: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" 4 | ENV["NODE_ENV"] ||= "development" 5 | 6 | require "pathname" 7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 8 | Pathname.new(__FILE__).realpath) 9 | 10 | require "bundler/setup" 11 | 12 | require "webpacker" 13 | require "webpacker/dev_server_runner" 14 | 15 | APP_ROOT = File.expand_path("..", __dir__) 16 | Dir.chdir(APP_ROOT) do 17 | Webpacker::DevServerRunner.run(ARGV) 18 | end 19 | -------------------------------------------------------------------------------- /app/views/rakes/unlocks/new.html.erb: -------------------------------------------------------------------------------- 1 |

Resend unlock instructions

2 | 3 | <%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %> 4 | <%= devise_error_messages! %> 5 | 6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true %> 9 |
10 | 11 |
12 | <%= f.submit "Resend unlock instructions" %> 13 |
14 | <% end %> 15 | 16 | <%= render "rakes/shared/links" %> 17 | -------------------------------------------------------------------------------- /app/views/devise/unlocks/new.html.erb: -------------------------------------------------------------------------------- 1 |

Resend unlock instructions

2 | 3 | <%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %> 4 | <%= devise_error_messages! %> 5 | 6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true %> 9 |
10 | 11 |
12 | <%= f.submit "Resend unlock instructions" %> 13 |
14 | <% end %> 15 | 16 | <%= render "devise/shared/links" %> 17 | -------------------------------------------------------------------------------- /app/javascript/packs/case.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | $('#case-detail').ready(function () { 3 | 4 | 5 | $(".toggle-files").on('click touchstart', function(){ 6 | $(".files").slideToggle(); 7 | return false; 8 | }); 9 | 10 | $("[class^='toggle-case-rule-counts']").on('click touchstart', function(){ 11 | console.log("toggling"); 12 | var target = $(this).attr('class').split('toggle-')[1]; 13 | $("[class^='" + target + "']").slideToggle(); 14 | return false; 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /app/views/devise/passwords/new.html.erb: -------------------------------------------------------------------------------- 1 |

Forgot your password?

2 | 3 | <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %> 4 | <%= devise_error_messages! %> 5 | 6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true %> 9 |
10 | 11 |
12 | <%= f.submit "Send me reset password instructions" %> 13 |
14 | <% end %> 15 | 16 | <%= render "devise/shared/links" %> 17 | -------------------------------------------------------------------------------- /app/views/rakes/passwords/new.html.erb: -------------------------------------------------------------------------------- 1 |

Forgot your password?

2 | 3 | <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %> 4 | <%= devise_error_messages! %> 5 | 6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true %> 9 |
10 | 11 |
12 | <%= f.submit "Send me reset password instructions" %> 13 |
14 | <% end %> 15 | 16 | <%= render "rakes/shared/links" %> 17 | -------------------------------------------------------------------------------- /config/initializers/postgresql_database_tasks.old: -------------------------------------------------------------------------------- 1 | # config/initializers/postgresql_database_tasks.rb 2 | module ActiveRecord 3 | module Tasks 4 | class PostgreSQLDatabaseTasks 5 | def drop 6 | establish_master_connection 7 | connection.select_all "select pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where datname='#{configuration['database']}' AND state='idle';" 8 | connection.drop_database configuration['database'] 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery.readyselector.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | var ready = $.fn.ready; 3 | $.fn.ready = function (fn) { 4 | if (this.context === undefined) { 5 | // The $().ready(fn) case. 6 | ready(fn); 7 | } else if (this.selector) { 8 | ready($.proxy(function(){ 9 | $(this.selector, this.context).each(fn); 10 | }, this)); 11 | } else { 12 | ready($.proxy(function(){ 13 | $(this).each(fn); 14 | }, this)); 15 | } 16 | } 17 | })(jQuery); 18 | -------------------------------------------------------------------------------- /app/controllers/extranet/minority_opinions_controller.rb: -------------------------------------------------------------------------------- 1 | module Extranet 2 | class MinorityOpinionsController < Extranet::ApplicationController 3 | 4 | def create 5 | @minority_opinion = MinorityOpinion.new 6 | @minority_opinion.case_id = params[:case_id] 7 | @minority_opinion.save 8 | redirect_to :back 9 | end 10 | 11 | def destroy 12 | @minority_opinion = MinorityOpinion.find(params[:id]) 13 | @minority_opinion.destroy 14 | redirect_to :back 15 | end 16 | 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /db/migrate/20200716210533_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20180723000244) 2 | class AddForeignKeyConstraintToActiveStorageAttachmentsForBlobId < ActiveRecord::Migration[6.0] 3 | def up 4 | return if foreign_key_exists?(:active_storage_attachments, column: :blob_id) 5 | 6 | if table_exists?(:active_storage_blobs) 7 | add_foreign_key :active_storage_attachments, :active_storage_blobs, column: :blob_id 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/views/extranet/cases/_form_case_rule_counts.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 |

    3 | Count <%= rule_count_form.object.count_order %>: 4 | <%= rule_count_form.radio_button :is_guilty, :false %>Not guilty 5 | <%= rule_count_form.radio_button :is_guilty, :true %>Guilty 6 | <%= rule_count_form.radio_button :is_guilty, "" %>Not available 7 |

    8 | 9 | <%= rule_count_form.rich_text_area :content %> 10 | <%= rule_count_form.hidden_field :_destroy %> 11 | <%= link_to "remove", "#", class: "remove_fields" %> 12 |
  • -------------------------------------------------------------------------------- /app/views/extranet/cases/index.csv.erb: -------------------------------------------------------------------------------- 1 | <%- 2 | headers = [ 3 | 'Case Number', 'Name', 'Title', 'Recommended Discipline', 'Final decision', 'Start date', 'End date' 4 | ] 5 | -%> 6 | <%= CSV.generate_line headers %> 7 | <%- @cases.each do |c| -%> 8 | <%= 9 | CSV.generate_line([ 10 | c.number, 11 | c.defendant.try(:full_name), 12 | c.defendant.try(:rank).try(:name), 13 | c.recommended_outcome.try(:name), 14 | c.decided_outcome.try(:name), 15 | c.date_initiated, 16 | c.date_decided, 17 | ]).html_safe 18 | -%> 19 | <%- end -%> 20 | -------------------------------------------------------------------------------- /app/views/extranet/board_members/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% title "Edit rule" %> 2 | <% body_id "extranet-board-member-detail" %> 3 | 4 | 5 |
    6 | <%= render :partial => "form" %> 7 | <%= link_to "Add Term", extranet_board_member_terms_path(@board_member), :method => :post %> 8 |
    9 |
    10 | <% if @board_member.terms.length > 1 %> 11 | <%= link_to 'Remove Last Term'.html_safe, extranet_board_member_term_path(@board_member, @board_member.terms.last), method: :delete %> 12 | <% end %> 13 |
    14 | 15 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads Spring without using Bundler, in order to be fast. 4 | # It gets overwritten when you run the `spring binstub` command. 5 | 6 | unless defined?(Spring) 7 | require 'rubygems' 8 | require 'bundler' 9 | 10 | lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read) 11 | spring = lockfile.specs.detect { |spec| spec.name == 'spring' } 12 | if spring 13 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path 14 | gem 'spring', spring.version 15 | require 'spring/binstub' 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /db/migrate/20210625201619_create_action_text_tables.action_text.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from action_text (originally 20180528164100) 2 | class CreateActionTextTables < ActiveRecord::Migration[6.0] 3 | def change 4 | create_table :action_text_rich_texts do |t| 5 | t.string :name, null: false 6 | t.text :body, size: :long 7 | t.references :record, null: false, polymorphic: true, index: false 8 | 9 | t.timestamps 10 | 11 | t.index [ :record_type, :record_id, :name ], name: "index_action_text_rich_texts_uniqueness", unique: true 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/views/extranet/cases/_case_rule_count_fields.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 |

    3 | (<%= link_to "Remove", "#", class: "remove_fields" %>) 4 | Count <%= f.object.count_order %>: 5 | 6 | 7 | 8 |

    9 |

    <%= f.rich_text_area :content%>

    10 | <%= f.hidden_field :_destroy %> 11 |
  • -------------------------------------------------------------------------------- /app/views/rakes/confirmations/new.html.erb: -------------------------------------------------------------------------------- 1 |

    Resend confirmation instructions

    2 | 3 | <%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %> 4 | <%= devise_error_messages! %> 5 | 6 |
    7 | <%= f.label :email %>
    8 | <%= f.email_field :email, autofocus: true, value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %> 9 |
    10 | 11 |
    12 | <%= f.submit "Resend confirmation instructions" %> 13 |
    14 | <% end %> 15 | 16 | <%= render "rakes/shared/links" %> 17 | -------------------------------------------------------------------------------- /app/views/devise/confirmations/new.html.erb: -------------------------------------------------------------------------------- 1 |

    Resend confirmation instructions

    2 | 3 | <%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %> 4 | <%= devise_error_messages! %> 5 | 6 |
    7 | <%= f.label :email %>
    8 | <%= f.email_field :email, autofocus: true, value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %> 9 |
    10 | 11 |
    12 | <%= f.submit "Resend confirmation instructions" %> 13 |
    14 | <% end %> 15 | 16 | <%= render "devise/shared/links" %> 17 | -------------------------------------------------------------------------------- /app/views/layouts/_home_intro.html.erb: -------------------------------------------------------------------------------- 1 | 2 |
    3 |
    4 |
    5 |

    The most comprehensive archive of misconduct allegations against the Chicago Police Department

    6 |

    Archiving the most serious allegations of misconduct brought against the Chicago Police Department and its employees as handled by the Chicago Police Board.

    7 |

    <%= link_to 'Browse cases', cases_path, class: "action" %> <%= link_to raw("How the process works »"), about_path + "#process" %>

    8 |
    9 |
    10 |
    11 | -------------------------------------------------------------------------------- /config/webpack/environment.js: -------------------------------------------------------------------------------- 1 | const { environment } = require("@rails/webpacker"); 2 | 3 | const webpack = require("webpack"); 4 | 5 | // import our loaders. 6 | 7 | 8 | // append them to webpack loaders. 9 | // ProviderPlugin helps us to load jQuery when the variables of $ and jQuery 10 | // are encountered as free variables at other modules. 11 | // Let's say if you want to use Bootstrap 4 and Popper.js. 12 | // 13 | // Refer here https://webpack.js.org/plugins/provide-plugin/ 14 | environment.plugins.append( 15 | "Provide", 16 | new webpack.ProvidePlugin({ 17 | fa: "font-awesome", 18 | }) 19 | ); 20 | 21 | module.exports = environment; 22 | -------------------------------------------------------------------------------- /app/javascript/packs/board-members-voting-history.js: -------------------------------------------------------------------------------- 1 | /*var dt = require( 'datatables.net' )(); 2 | $('body').ready(function () { 3 | 4 | $('.voting-history').DataTable({ 5 | aaSorting: [[0, "asc"]], //disable initial sort 6 | aoColumns: [ 7 | { bVisible: false }, //0: hidden board member name for sorting 8 | null, //1: photo 9 | { iDataSort: 0 }, //2: board member 10 | null, //3: agreed 11 | null, //4: disagreed 12 | null, //5: did not vote 13 | { bSortable: false } //6: voting chart 14 | ], 15 | info: false, 16 | paging: false, 17 | searching: false 18 | }); 19 | 20 | });*/ 21 | -------------------------------------------------------------------------------- /.elasticbeanstalk/config.yml: -------------------------------------------------------------------------------- 1 | branch-defaults: 2 | master: 3 | environment: production 4 | group_suffix: null 5 | post_rich_fixes: 6 | environment: staging 7 | staging: 8 | environment: ruby3-upgrade-staging-env 9 | environment-defaults: 10 | staging: 11 | branch: null 12 | repository: null 13 | global: 14 | application_name: policeboard 15 | branch: null 16 | default_ec2_keyname: steves 17 | default_region: us-east-1 18 | include_git_submodules: true 19 | instance_profile: null 20 | platform_name: null 21 | platform_version: null 22 | profile: eb-cli 23 | repository: null 24 | sc: git 25 | workspace_type: Application 26 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: 2 | file: .gitpod.Dockerfile 3 | 4 | tasks: 5 | - name: Install 6 | init: > 7 | gem install bundle && 8 | bundle install && 9 | gp sync-done install 10 | - name: DBInit 11 | openMode: split-right 12 | init: gp sync-await install 13 | command: | 14 | rake db:create db:migrate db:seed import:all || 15 | exit 16 | - name: Webpacker 17 | init: gp sync-await install 18 | openMode: split-right 19 | command: | 20 | mkdir -p tmp/pids && 21 | npm install && 22 | bundle exec rails webpacker:compile && 23 | exit 24 | ports: 25 | - port: 3000 26 | onOpen: open-browser 27 | -------------------------------------------------------------------------------- /app/views/cases/_case.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 | <% if c.defendant.present? then %> 3 |

    <%= link_to c.defendant.full_name, case_path(c) %>

    4 | <% end %> 5 |

    6 | <%= c.recommended_outcome.nil? ? "" : "Recommendation: #{c.recommended_outcome.name}," %> 7 | <%= c.decided_outcome.nil? ? "" : "Decision: #{c.decided_outcome.name}" %> 8 |

    9 |
      10 |
    • <%= c.date_initiated.nil? ? "" : c.date_initiated.to_formatted_s(:long) %>
    • 11 |
    • Case <%= c.number %>
    • 12 |
    • <%= c.length_of_process.nil? ? "" : "Length of process: #{c.length_of_process}" %>
    • 13 |
    14 |
  • 15 | -------------------------------------------------------------------------------- /app/views/active_storage/blobs/_blob.html.erb: -------------------------------------------------------------------------------- 1 |
    attachment--<%= blob.filename.extension %>"> 2 | <% if blob.representable? %> 3 | <%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %> 4 | <% end %> 5 | 6 |
    7 | <% if caption = blob.try(:caption) %> 8 | <%= caption %> 9 | <% else %> 10 | <%= blob.filename %> 11 | <%= number_to_human_size blob.byte_size %> 12 | <% end %> 13 |
    14 |
    15 | -------------------------------------------------------------------------------- /.ebextensions/04_yarn.config: -------------------------------------------------------------------------------- 1 | commands: 2 | 01_node_get: 3 | cwd: /tmp 4 | command: 'sudo curl --silent --location https://rpm.nodesource.com/setup_14.x | sudo bash -' 5 | 6 | 02_node_install: 7 | cwd: /tmp 8 | command: 'sudo yum -y install nodejs' 9 | 10 | 03_yarn_get: 11 | cwd: /tmp 12 | # don't run the command if yarn is already installed (file /usr/bin/yarn exists) 13 | test: '[ ! -f /usr/bin/yarn ] && echo "yarn not installed"' 14 | command: 'sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo' 15 | 16 | 04_yarn_install: 17 | cwd: /tmp 18 | test: '[ ! -f /usr/bin/yarn ] && echo "yarn not installed"' 19 | command: 'sudo yum -y install yarn' 20 | 21 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | 9 | #users = User.create([ { :email => "annat@webitects.com", :password => "password", :password_confirmation => "password" } ]) 10 | 11 | users = User.create([{:email => "test@test.com", :password => "password", :password_confirmation => "password"}, {:email => "tsiska@chicagojustice.org", :password => "password", :password_confirmation => "password"}]) 12 | -------------------------------------------------------------------------------- /app/views/extranet/cases/_form_case_rules.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 |

    <%= case_rule_form.object.id %> Rule <%= case_rule_form.object.rule.code %> (<%= case_rule_form.object.case_rule_counts.count() %> counts): 4 | <%= case_rule_form.object.rule.description %>

    5 | 6 | <%= case_rule_form.hidden_field :_destroy %> 7 | <%= link_to "remove", "#", class: "remove_fields" %> 8 | 9 |
      10 | <%= case_rule_form.fields_for :case_rule_counts, case_rule_form.object.case_rule_counts.order(:count_order) do |rule_count_form| %> 11 | <%= render "form_case_rule_counts", :rule_count_form => rule_count_form %> 12 | <% end %> 13 |
    14 |
  • 15 | 16 | -------------------------------------------------------------------------------- /app/views/rakes/sessions/new.html.erb: -------------------------------------------------------------------------------- 1 |

    Log in

    2 | 3 | <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> 4 |
    5 | <%= f.label :email %>
    6 | <%= f.email_field :email, autofocus: true %> 7 |
    8 | 9 |
    10 | <%= f.label :password %>
    11 | <%= f.password_field :password, autocomplete: "off" %> 12 |
    13 | 14 | <% if devise_mapping.rememberable? -%> 15 |
    16 | <%= f.check_box :remember_me %> 17 | <%= f.label :remember_me %> 18 |
    19 | <% end -%> 20 | 21 |
    22 | <%= f.submit "Log in" %> 23 |
    24 | <% end %> 25 | 26 | <%= render "rakes/shared/links" %> 27 | -------------------------------------------------------------------------------- /app/views/users/new.html.erb: -------------------------------------------------------------------------------- 1 |

    New user

    2 | 3 | <%= form_for(@user) do |f| %> 4 |
    5 | <%= f.label :email %>
    6 | <%= f.email_field :email, autofocus: true %> 7 |
    8 | 9 |
    10 | <%= f.label :password %> 11 | <% if @minimum_password_length %> 12 | (<%= @minimum_password_length %> characters minimum) 13 | <% end %>
    14 | <%= f.password_field :password, autocomplete: "off" %> 15 |
    16 | 17 |
    18 | <%= f.label :password_confirmation %>
    19 | <%= f.password_field :password_confirmation, autocomplete: "off" %> 20 |
    21 | 22 | 23 |
    24 | <%= f.submit "Submit" %> 25 |
    26 | <% end %> 27 | 28 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | def new 3 | @user = User.new() 4 | end 5 | 6 | def show 7 | @user = User.find(params[:id]) 8 | end 9 | 10 | def create 11 | @user = User.new(user_params) 12 | if @user.save 13 | redirect_to users, :notice => "User successfully added" 14 | else 15 | flash[:error] = "Oops, there was an error" 16 | render 'new' 17 | end 18 | end 19 | 20 | def destroy 21 | @user = User.find(params[:id]) 22 | @user.destroy 23 | 24 | if @user.destroy 25 | redirect_to users_path, notice: "User deleted." 26 | end 27 | end 28 | 29 | def user_params 30 | params.require(:user).permit(:email, :password, :password_confirmation) 31 | end 32 | end -------------------------------------------------------------------------------- /.ebextensions/01setup_swap.config: -------------------------------------------------------------------------------- 1 | files: 2 | "/home/ec2-user/setup_swap.sh": 3 | mode: "000755" 4 | owner: root 5 | group: root 6 | content: | 7 | #!/bin/bash 8 | # based on http://steinn.org/post/elasticbeanstalk-swap/ 9 | 10 | SWAPFILE=/var/swapfile 11 | SWAP_MEGABYTES=2048 12 | 13 | echo "Configuring swapfile!" 14 | 15 | if [ -f $SWAPFILE ]; then 16 | echo "Swapfile $SWAPFILE found, assuming already setup" 17 | exit; 18 | fi 19 | 20 | /bin/dd if=/dev/zero of=$SWAPFILE bs=1M count=$SWAP_MEGABYTES 21 | /bin/chmod 600 $SWAPFILE 22 | /sbin/mkswap $SWAPFILE 23 | /sbin/swapon $SWAPFILE 24 | 25 | commands: 26 | 01setup_swap: 27 | command: "bash setup_swap.sh" 28 | cwd: "/home/ec2-user/" -------------------------------------------------------------------------------- /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 | # Add Yarn node_modules folder to the asset load path. 9 | Rails.application.config.assets.paths << Rails.root.join('node_modules') 10 | 11 | # Precompile additional assets. 12 | # application.js, application.css, and all non-JS/CSS in the app/assets 13 | # folder are already added. 14 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 15 | Rails.application.config.assets.precompile = ['*.js', '*.css', '*.png', '*.ico', '*.jpg'] -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@rails/actiontext": "^6.1.3-2", 4 | "@rails/webpacker": "5.4.3", 5 | "babel-plugin-syntax-dynamic-import": "^6.18.0", 6 | "babel-plugin-transform-class-properties": "^6.24.1", 7 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 8 | "babel-preset-env": "^1.7.0", 9 | "css-loader": "^1.0.1", 10 | "datatables.net": "^1.11.3", 11 | "datatables.net-dt": "^1.11.3", 12 | "expose-loader": "^1.0.3", 13 | "imports-loader": "^1.2.0", 14 | "jquery": "^3.6.0", 15 | "jquery-sparkline": "^2.4.0", 16 | "trix": "^1.2.0", 17 | "webpack": "^4.46.0", 18 | "webpack-cli": "^3.3.12", 19 | "webpack-merge": "^5.10.0" 20 | }, 21 | "devDependencies": { 22 | "webpack-dev-server": "^3" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any styles 10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new 11 | * file per style scope. 12 | * 13 | *= require reset 14 | *= require master 15 | *= require forms 16 | *= require_self 17 | *= require font-awesome 18 | */ 19 | -------------------------------------------------------------------------------- /app/views/extranet/cases/_form_defendant.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 |
    <%= f.label :first_name, "Name" %>
    3 |
    4 |
    5 |

    <%= f.text_field :first_name, :class => "txt" %>

    6 |

    <%= f.text_field :last_name, :class => "txt" %>

    7 |
    8 |
    9 |
  • 10 |
  • 11 |
    <%= f.label :rank_id, "Title" %>
    12 |
    <%= f.collection_select :rank_id, Rank.all, :id, :name %>
    13 |
  • 14 |
  • 15 |
    <%= f.label :number, "Badge number" %>
    16 |
    <%= f.text_field :number, :class => "txt-med" %>
    17 |
  • 18 | -------------------------------------------------------------------------------- /app/views/devise/sessions/new.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | <% title "Sign in" %> 3 | 4 |
    5 |

    Sign in

    6 | 7 | <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> 8 |

    <%= f.email_field :email, autofocus: true, :placeholder => "Email...", :class => "txt" %>

    9 |

    <%= f.password_field :password, autocomplete: "off", :placeholder => "Password...", :class => "txt" %>

    10 | 11 | <% if devise_mapping.rememberable? -%> 12 |

    <%= f.check_box :remember_me %> <%= f.label :remember_me %>

    13 | <% end -%> 14 | 15 |

    <%= f.submit "Sign in", :class => "action" %>

    16 | <% end %> 17 | 18 | <%= render "devise/shared/links" %> 19 |
    20 |
    -------------------------------------------------------------------------------- /app/views/rakes/registrations/new.html.erb: -------------------------------------------------------------------------------- 1 |

    Sign up

    2 | 3 | <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> 4 | <%= devise_error_messages! %> 5 | 6 |
    7 | <%= f.label :email %>
    8 | <%= f.email_field :email, autofocus: true %> 9 |
    10 | 11 |
    12 | <%= f.label :password %> 13 | <% if @minimum_password_length %> 14 | (<%= @minimum_password_length %> characters minimum) 15 | <% end %>
    16 | <%= f.password_field :password, autocomplete: "off" %> 17 |
    18 | 19 |
    20 | <%= f.label :password_confirmation %>
    21 | <%= f.password_field :password_confirmation, autocomplete: "off" %> 22 |
    23 | 24 |
    25 | <%= f.submit "Sign up" %> 26 |
    27 | <% end %> 28 | 29 | <%= render "rakes/shared/links" %> 30 | -------------------------------------------------------------------------------- /app/views/devise/registrations/new.html.erb: -------------------------------------------------------------------------------- 1 |

    Sign up

    2 | 3 | <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> 4 | <%= devise_error_messages! %> 5 | 6 |
    7 | <%= f.label :email %>
    8 | <%= f.email_field :email, autofocus: true %> 9 |
    10 | 11 |
    12 | <%= f.label :password %> 13 | <% if @minimum_password_length %> 14 | (<%= @minimum_password_length %> characters minimum) 15 | <% end %>
    16 | <%= f.password_field :password, autocomplete: "off" %> 17 |
    18 | 19 |
    20 | <%= f.label :password_confirmation %>
    21 | <%= f.password_field :password_confirmation, autocomplete: "off" %> 22 |
    23 | 24 |
    25 | <%= f.submit "Sign up" %> 26 |
    27 | <% end %> 28 | 29 | <%= render "devise/shared/links" %> 30 | -------------------------------------------------------------------------------- /app/views/users/index.html.erb: -------------------------------------------------------------------------------- 1 | <% title "Admin users" %> 2 | <% body_id "admin-users-index" %> 3 | 4 |
    5 | 6 |

    Users

    7 | <%= link_to "Add user test", new_user_path, :class => "action" %> 8 | 9 |
    10 |
    11 |
    12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | <% @users = User.all %> 22 | <% @users.each do |user| %> 23 | 24 | 25 | 26 | 27 | 28 | <% end %> 29 | 30 |
    EmailLast sign in
    <%= user.email %><%= user.last_sign_in_at %><%= link_to 'x', user_path(user.id), method: :delete %>
    31 |
    32 | 33 | 34 | 35 | <%= javascript_pack_tag "users" %> 36 | -------------------------------------------------------------------------------- /app/javascript/packs/home.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | import dt from 'datatables.net'; 3 | import sparkline from 'jquery-sparkline'; 4 | 5 | $('#home').ready(function () { 6 | 7 | /*$('#case-outcomes').DataTable({ 8 | aaSorting: [[2, "desc"]], //disable initial sort 9 | aoColumns: [ 10 | { bVisible: false }, //0: hidden cases total for sorting 11 | null, //1: recommendation -> decision 12 | { iDataSort: 0 }, //2: cases 13 | { bSortable: false }, //3: annual trend sparkline 14 | { bSortable: false } //4: annual trend barchart 15 | ], 16 | info: false, 17 | paging: false, 18 | searching: false 19 | });*/ 20 | 21 | $('.inlinesparkline').sparkline('html', { 22 | fillColor: "rgba(0, 0, 0, 0.1)", 23 | height: "38px", 24 | lineColor: "#666", 25 | lineWidth: 2, 26 | spotRadius: 0, 27 | width: "140px" 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /app/javascript/packs/rules.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | import dt from 'datatables.net'; 3 | $('#rules-index').ready(function () { 4 | 5 | $('#rules-list').DataTable({ 6 | aoColumns: [ 7 | { bVisible: false }, //0: hidden rule # for sorting 8 | { iDataSort: 0 }, //1: rule 9 | null, //2: description 10 | { iDataSort: 4 }, //3: cases stat 11 | { bVisible: false }, //4: hidden cases stat for sorting 12 | { bSortable: false } //5: cases barchart 13 | ], 14 | info: false, 15 | order: [[ 1, 'asc']], 16 | paging: false, 17 | searching: false 18 | }); 19 | 20 | $('.toggle-special-comment').on('click touchstart', function(){ 21 | var verb = $(this).find('.verb').text(); 22 | $(this).find('.verb').text(verb === 'Show' ? 'Hide' : 'Show'); 23 | $(this).parent().children('.special-comment-div').slideToggle(); 24 | return false; 25 | }); 26 | }); -------------------------------------------------------------------------------- /app/views/extranet/cases/_defendant_fields.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 |
    <%= f.label :first_name, "Name" %>
    3 |
    4 |
    5 |

    <%= f.text_field :first_name, :class => "txt" %>

    6 |

    <%= f.text_field :last_name, :class => "txt" %>

    7 |
    8 |
    9 |
  • 10 |
  • 11 |
    <%= f.label :number, "Badge/employee number" %>
    12 |
    <%= f.text_field :number, :class => "txt-med" %>
    13 |
  • 14 |
  • 15 |
    <%= f.label :rank_id, "Title" %>
    16 |
    <%= f.collection_select :rank_id, Rank.all.reject{ |r| !r.name? }.sort_by{|r| r.name }, :id, :name %>
    17 |
  • 18 | -------------------------------------------------------------------------------- /app/views/rakes/passwords/edit.html.erb: -------------------------------------------------------------------------------- 1 |

    Change your password

    2 | 3 | <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> 4 | <%= devise_error_messages! %> 5 | <%= f.hidden_field :reset_password_token %> 6 | 7 |
    8 | <%= f.label :password, "New password" %>
    9 | <% if @minimum_password_length %> 10 | (<%= @minimum_password_length %> characters minimum)
    11 | <% end %> 12 | <%= f.password_field :password, autofocus: true, autocomplete: "off" %> 13 |
    14 | 15 |
    16 | <%= f.label :password_confirmation, "Confirm new password" %>
    17 | <%= f.password_field :password_confirmation, autocomplete: "off" %> 18 |
    19 | 20 |
    21 | <%= f.submit "Change my password" %> 22 |
    23 | <% end %> 24 | 25 | <%= render "rakes/shared/links" %> 26 | -------------------------------------------------------------------------------- /app/views/devise/passwords/edit.html.erb: -------------------------------------------------------------------------------- 1 |

    Change your password

    2 | 3 | <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> 4 | <%= devise_error_messages! %> 5 | <%= f.hidden_field :reset_password_token %> 6 | 7 |
    8 | <%= f.label :password, "New password" %>
    9 | <% if @minimum_password_length %> 10 | (<%= @minimum_password_length %> characters minimum)
    11 | <% end %> 12 | <%= f.password_field :password, autofocus: true, autocomplete: "off" %> 13 |
    14 | 15 |
    16 | <%= f.label :password_confirmation, "Confirm new password" %>
    17 | <%= f.password_field :password_confirmation, autocomplete: "off" %> 18 |
    19 | 20 |
    21 | <%= f.submit "Change my password" %> 22 |
    23 | <% end %> 24 | 25 | <%= render "devise/shared/links" %> 26 | -------------------------------------------------------------------------------- /app/controllers/extranet/case_files_controller.rb: -------------------------------------------------------------------------------- 1 | class Extranet::CaseFilesController < ApplicationController 2 | before_action :set_case 3 | 4 | 5 | def destroy 6 | remove_image_at_index(params[:id].to_i) 7 | flash[:error] = "Failed deleting file" unless @case.save 8 | redirect_to :back 9 | end 10 | 11 | private 12 | 13 | def set_case 14 | #raise params.inspect 15 | @case = Case.find(params[:case_id]) 16 | end 17 | 18 | def remove_image_at_index(index) 19 | if @case.files.count == 1 20 | @case.remove_files = true 21 | else 22 | remain_files = @case.files 23 | #raise remain_files.inspect 24 | delete_file = remain_files.delete_at(index) 25 | #raise remain_files.inspect 26 | delete_file.try(:remove!) 27 | @case.files = remain_files; 28 | end 29 | end 30 | 31 | def files_params 32 | params.fetch(:case, {}).permit({files: []}) 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /config/initializers/fog.rb: -------------------------------------------------------------------------------- 1 | 2 | CarrierWave.configure do |config| 3 | 4 | if Rails.env.development? || Rails.env.test? 5 | CarrierWave.configure do |config| 6 | config.storage = :file 7 | end 8 | end 9 | 10 | config.fog_provider = 'fog/aws' 11 | 12 | config.fog_credentials = { 13 | provider: 'AWS', 14 | region: ENV["AWS_REGION"], # optional, defaults to 'us-east-1' 15 | aws_access_key_id: ENV["AWS_ACCESS_KEY_ID"] || 'awskey', 16 | aws_secret_access_key: ENV["AWS_SECRET_KEY"] || 'awssecret' 17 | } 18 | 19 | config.fog_directory = ENV["AWS_BUCKET"] 20 | 21 | config.fog_public = true # optional, defaults to true 22 | config.fog_attributes = { 'Cache-Control' => "max-age=#{365.day.to_i}" } # optional, defaults to {} 23 | 24 | if Rails.env.production? 25 | CarrierWave.configure do |config| 26 | config.storage = :fog 27 | end 28 | end 29 | end 30 | 31 | -------------------------------------------------------------------------------- /config/locales/simple_form.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | simple_form: 3 | "yes": 'Yes' 4 | "no": 'No' 5 | required: 6 | text: 'required' 7 | mark: '*' 8 | # You can uncomment the line below if you need to overwrite the whole required html. 9 | # When using html, text and mark won't be used. 10 | # html: '*' 11 | error_notification: 12 | default_message: "Please review the problems below:" 13 | # Examples 14 | # labels: 15 | # defaults: 16 | # password: 'Password' 17 | # user: 18 | # new: 19 | # email: 'E-mail to sign in.' 20 | # edit: 21 | # email: 'E-mail.' 22 | # hints: 23 | # defaults: 24 | # username: 'User name to sign in.' 25 | # password: 'No special characters, please.' 26 | # include_blanks: 27 | # defaults: 28 | # age: 'Rather not say' 29 | # prompts: 30 | # defaults: 31 | # age: 'Select your age' 32 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html 3 | root 'welcome#index' 4 | 5 | get '/about', to: 'static_pages#about' 6 | get '/feedback', to: 'static_pages#feedback' 7 | get 'board/responsibilities', to: 'board#responsibilities' 8 | 9 | resources :cases, only:[:show, :index] 10 | resources :board 11 | resources :rules, only: [:show, :index] 12 | 13 | resources :analytics, only: [:show, :index] 14 | 15 | #get 'admin/index' 16 | devise_for :users, controllers: { registrations: "registrations" } 17 | 18 | namespace :extranet do 19 | resources :rules, :board_members, :superintendents 20 | resources :board_members do 21 | resources :terms, only:[:create, :destroy] 22 | end 23 | resources :cases do 24 | resources :case_files, only:[:destroy] 25 | resources :minority_opinions, only:[:create, :destroy] 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at https://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /app/views/extranet/cases/_board_member_vote_fields.erb: -------------------------------------------------------------------------------- 1 |
  • 2 | <%= f.hidden_field :_destroy %> 3 | 4 | 9 | 10 | 11 | (<%= link_to "Remove", "#", class: "remove_fields" %>) 12 | <%= f.object.board_member ? f.object.board_member.full_name : "" %> 13 | 14 | 15 | 16 | <%= f.collection_radio_buttons :vote_id, Vote.all, :id, :name %> 17 | 18 | 19 |
    20 |

    <%= f.label :dissent_description, "Reason for dissent" %>

    21 | <%= f.rich_text_area :dissent_description, class: "dissent-description txt" %> 22 |
    23 |
  • 24 | -------------------------------------------------------------------------------- /app/views/extranet/cases/show.html.erb: -------------------------------------------------------------------------------- 1 | <% title "Case ##{@case.number}"%> 2 |

    <%= "#{@case.number}" %> 3 | 4 |

    5 |
    Case #
    6 |
    <%= @case.number %>
    7 | 8 |
    Name
    9 |
    <%= @case.defendant.present? ? @case.defendant.full_name : '' %>
    10 | 11 |
    Case files
    12 |
    13 | <%= form_for [:extranet, @case], url: extranet_case_case_files_path(@case), html: { multipart: true }, method: :post do |f| %> 14 | <%= f.file_field :files, multiple: true %> 15 | <%= f.submit "Add files" %> 16 | <% end %> 17 | 18 |
    19 | 20 |
    Judgement
    21 |
    <%= @case.date_decided %>
    22 |
    <%= @case.decided_outcome.present? ? @case.decided_outcome.name : '' %>
    23 | 24 |
    Last modified
    25 |
    <%= @case.updated_at %>
    26 |
    27 | 28 |

    29 | <%= link_to "Edit", edit_extranet_case_path(@case) %> | 30 | <%= button_to "Destroy", extranet_case_path(@case), :confirm => 'Are you sure?', :method => :delete %> | 31 | 32 |

    33 | -------------------------------------------------------------------------------- /app/javascript/packs/policeboard.js: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------+ 2 | | Site: Chicago Police Board Information Center | 3 | | Part: Common Javascript Methods | 4 | +-----------------------------------------------*/ 5 | import $ from 'jquery'; 6 | $(function() { 7 | if ($("#notice").val()) { 8 | displayNotification("success", $("#notice").val()); 9 | } 10 | else if ($("#alert").val()) { 11 | displayNotification("error", $("#alert").val()); 12 | } 13 | }); 14 | 15 | function displayNotification (notificationType, message) { 16 | if (notificationType == "success") { 17 | iziToast.success({ 18 | title: 'Success', 19 | message: message, 20 | progressBar: false, 21 | position: "topLeft" 22 | }); 23 | } 24 | else if (notificationType == "error") { 25 | iziToast.error({ 26 | title: 'Error', 27 | message: message, 28 | progressBar: false, 29 | position: "topLeft" 30 | }); 31 | } 32 | } -------------------------------------------------------------------------------- /config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: a11b2d246690132926cb5d6d735a04637a1b09d9186483ad170b7d92f3a509f974d30998730e4178339680b5cac33a091f8fa798c2e69510b9c854b391cbd0aa 15 | 16 | test: 17 | secret_key_base: ae3291d193e7504ee7e18be4f5ad0131bfd8f15d3282c3e9776e10b829f0e6d36eed6844af2810cff11b5fce2427ec711c80aa6071f85d40d4f3290043366a74 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /app/javascript/packs/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | 14 | // rails 15 | //= require jquery 16 | 17 | // app 18 | //= require jquery.readyselector 19 | //= require jquery.sparkline.min 20 | //= require responsive.min 21 | //= require responsive-init 22 | //= require search 23 | //= require table-scroll 24 | //= require policeboard 25 | //= require tinymce 26 | //= require iziToast 27 | 28 | 29 | 30 | require("trix") 31 | require("@rails/actiontext") 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/views/board/index.html.erb: -------------------------------------------------------------------------------- 1 | <% title "Board" %> 2 | <% body_id "board-index" %> 3 | 4 |
    5 |

    The Chicago Police Board

    6 |

    The Chicago Police Board is an independent civilian body that oversees certain activities of the Chicago Police Department. The nine members of the Board are private citizens appointed by the Mayor with the advice and consent of the City Council.

    7 |

    <%= link_to raw("More about the board's responsibilities »"), board_responsibilities_path %>

    8 |
    9 | 10 | <%= render partial: "list", locals: { board_members: @current_board_members, title: '

    Current board members

    ', table_id: 'current-board-list' } %> 11 | 12 | <%= render partial: "list", locals: { board_members: @past_board_members, title: '

    Past board members

    ', table_id: 'past-board-list' } %> 13 | 14 | 15 | 16 | 17 | <%= javascript_pack_tag "board-members-voting-history" %> 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | # Ignore bundler config. 7 | /.bundle 8 | 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | /db/*.sqlite3-journal 13 | 14 | /config/config.yml 15 | 16 | # Ignore all logfiles and tempfiles. 17 | /log/*.log 18 | /tmp 19 | 20 | # Ignore junk files 21 | .DS_Store 22 | .DS_Store? 23 | **.orig 24 | 25 | # Ignore local environment config 26 | .env 27 | 28 | public/**/** 29 | 30 | 31 | # Ignore application configuration 32 | /config/application.yml 33 | .idea/* 34 | deploy/* 35 | .generators 36 | .rakeTasks 37 | /public/packs 38 | /public/packs-test 39 | /node_modules 40 | yarn-debug.log* 41 | .yarn-integrity 42 | 43 | /public/packs 44 | /public/packs-test 45 | /node_modules 46 | /yarn-error.log 47 | yarn-debug.log* 48 | .yarn-integrity 49 | 50 | /config/master.key 51 | -------------------------------------------------------------------------------- /app/views/static_pages/feedback.html.erb: -------------------------------------------------------------------------------- 1 | <% title "Feedback" %> 2 | 3 |
    4 |
    5 | 6 |
    7 | 26 | 27 |
    28 | -------------------------------------------------------------------------------- /app/assets/stylesheets/actiontext.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Provides a drop-in pointer for the default Trix stylesheet that will format the toolbar and 3 | // the trix-editor content (whether displayed or under editing). Feel free to incorporate this 4 | // inclusion directly in any other asset bundle and remove this file. 5 | // 6 | //= require trix/dist/trix 7 | 8 | // We need to override trix.css’s image gallery styles to accommodate the 9 | // element we wrap around attachments. Otherwise, 10 | // images in galleries will be squished by the max-width: 33%; rule. 11 | .trix-content { 12 | .attachment-gallery { 13 | > action-text-attachment, 14 | > .attachment { 15 | flex: 1 0 33%; 16 | padding: 0 0.5em; 17 | max-width: 33%; 18 | } 19 | 20 | &.attachment-gallery--2, 21 | &.attachment-gallery--4 { 22 | > action-text-attachment, 23 | > .attachment { 24 | flex-basis: 50%; 25 | max-width: 50%; 26 | } 27 | } 28 | } 29 | 30 | action-text-attachment { 31 | .attachment { 32 | padding: 0 !important; 33 | max-width: 100% !important; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/views/extranet/superintendents/index.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | <% title "Superintendents" %> 3 |
    4 |

    Superintendents

    5 |

    <%= link_to "Add superintendent", [:new, :extranet, :superintendent], :class => "action" %>

    6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | <% @superintendents.each do |s| %> 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | <% end %> 27 | 28 |
    NameStart of termEnd of termLast modified
    <%= link_to s.first_name + " " + s.last_name, [:edit, :extranet, s] %><%= s.start_of_term %><%= s.end_of_term %><%= s.updated_at %><%= link_to "X", [:extranet, s], :confirm => 'Are you sure?', :method => :delete, :title => "Delete" %>
    29 |
    -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ChicagoJusticeProject 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /app/views/extranet/rules/index.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | <% title "Rules" %> 3 |

    Rules

    4 | 5 |

    <%= link_to "Add rule", [:new, :extranet, :rule], :class => "action" %>

    6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | <% @rules.each do |r| %> 18 | 19 | 20 | 21 | 22 | 23 | 24 | <% end %> 25 | 26 |
    # Description Last modified
    <%= r.code %><%= link_to r.description, [:edit, :extranet, r] %><%= r.updated_at %><%= link_to "X", [:extranet, r], :confirm => 'Are you sure?', :method => :delete, :title => "Delete" %>
    27 |
    28 | 29 | -------------------------------------------------------------------------------- /app/views/extranet/cases/_case_rule_fields.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 | <%= f.hidden_field :rule_id, class: 'rule_id' %> 3 | <%= f.hidden_field :_destroy %> 4 | 8 |

    9 | (<%= link_to "Remove", "#", class: "remove_fields" %>) 10 | Rule <%= f.object.rule ? f.object.rule.code : "" %> 11 | (<%= f.object.case_rule_counts.count() %> counts): 12 | <%= f.object.rule ? f.object.rule.description : "" %> 13 |

    14 | 15 |
    16 |
      17 | <%= f.fields_for :case_rule_counts, f.object.case_rule_counts.order(:count_order) do |builder| %> 18 | <%= render "case_rule_count_fields", :f => builder %> 19 | <% end %> 20 |
    21 |

    <%= link_to_add_fields "Add count to rule #{f.object.rule ? f.object.rule.code : ""}", f, :case_rule_counts %>

    22 |
    23 |
  • 24 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path('..', __dir__) 6 | 7 | def system!(*args) 8 | system(*args) || abort("\n== Command #{args} failed ==") 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to setup or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at anytime and get an expectable outcome. 14 | # Add necessary setup 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 21 | # system('bin/yarn') 22 | 23 | # puts "\n== Copying sample files ==" 24 | # unless File.exist?('config/database.yml') 25 | # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' 26 | # end 27 | 28 | puts "\n== Preparing database ==" 29 | system! 'bin/rails db:prepare' 30 | 31 | puts "\n== Removing old logs and tempfiles ==" 32 | system! 'bin/rails log:clear tmp:clear' 33 | 34 | puts "\n== Restarting application server ==" 35 | system! 'bin/rails restart' 36 | end 37 | -------------------------------------------------------------------------------- /app/views/extranet/rules/_form.html.erb: -------------------------------------------------------------------------------- 1 |

    Rule details

    2 | <%= form_for [:extranet, @rule] do |f| %> 3 |
      4 |
    1. 5 |
      <%= f.label :code, "Rule code" %>
      6 |
      <%= f.text_field :code, autofocus: true, :class => "txt-med" %>
      7 |
    2. 8 |
    3. 9 |
      <%= f.label :description %>
      10 |
      11 | <%= f.rich_text_area :description, :class => "tinymce", :rows => 40, :cols => 120 %> 12 | <%= tinymce %> 13 |
      14 |
    4. 15 |
    5. 16 |
      <%= f.label :comment %>
      17 |
      <%= f.rich_text_area :comment, :class => "tinymce", :rows => 40, :cols => 120 %>
      18 |
    6. 19 | 20 |
    21 | 22 |
      23 |
    1. 24 |
      25 | <%= f.submit "Save", :class => "action" %> <%= link_to "Cancel", extranet_rules_path %> 26 |
      27 |
    2. 28 |
    29 | 30 | 31 | <% end %> 32 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | require "rails" 4 | # Pick the frameworks you want: 5 | require "active_model/railtie" 6 | require "active_job/railtie" 7 | require "active_record/railtie" 8 | require "active_storage/engine" 9 | require "action_controller/railtie" 10 | require "action_mailer/railtie" 11 | require "action_mailbox/engine" 12 | require "action_text/engine" 13 | require "action_view/railtie" 14 | # require "action_cable/engine" 15 | require "sprockets/railtie" 16 | require "rails/test_unit/railtie" 17 | require "font-awesome-rails" 18 | 19 | # Require the gems listed in Gemfile, including any gems 20 | # you've limited to :test, :development, or :production. 21 | Bundler.require(*Rails.groups) 22 | 23 | module Policeboard 24 | class Application < Rails::Application 25 | # Initialize configuration defaults for originally generated Rails version. 26 | config.load_defaults 5.0 27 | 28 | # Settings in config/environments/* take precedence over those specified here. 29 | # Application configuration can go into files in config/initializers 30 | # -- all .rb files in that directory are automatically loaded after loading 31 | # the framework and any gems in your application. 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket 23 | 24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /app/views/rakes/shared/_links.html.erb: -------------------------------------------------------------------------------- 1 | <%- if controller_name != 'sessions' %> 2 | <%= link_to "Log in", new_session_path(resource_name) %>
    3 | <% end -%> 4 | 5 | <%- if devise_mapping.registerable? && controller_name != 'registrations' %> 6 | <%= link_to "Sign up", new_registration_path(resource_name) %>
    7 | <% end -%> 8 | 9 | <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> 10 | <%= link_to "Forgot your password?", new_password_path(resource_name) %>
    11 | <% end -%> 12 | 13 | <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> 14 | <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
    15 | <% end -%> 16 | 17 | <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> 18 | <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
    19 | <% end -%> 20 | 21 | <%- if devise_mapping.omniauthable? %> 22 | <%- resource_class.omniauth_providers.each do |provider| %> 23 | <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %>
    24 | <% end -%> 25 | <% end -%> 26 | -------------------------------------------------------------------------------- /app/views/extranet/board_members/index.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | <% title "Board" %> 3 | 4 |

    Board

    5 | 6 |

    <%= link_to "Add board member", [:new, :extranet, :board_member], :class => "action" %>

    7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | <% @board_members.each do |board| %> 19 | 20 | 21 | 22 | 23 | 24 | 25 | <% end %> 26 | 27 |
    Name Status Last modified
    <%= link_to board.first_name + " " + board.last_name, [:edit, :extranet, board] %><%= board.active ? "Current" : "Past" %><%= board.updated_at %><%= link_to "X", [:extranet, board], :confirm => 'Are you sure?', :method => :delete, :title => "Delete" %>
    28 |
    -------------------------------------------------------------------------------- /app/controllers/cases_controller.rb: -------------------------------------------------------------------------------- 1 | class CasesController < ApplicationController 2 | def index 3 | if params[:search] 4 | @header = "Search results" 5 | @cases = Case.search(params[:search]) 6 | @counter = "Matching cases: #{@cases.count}" 7 | else 8 | @header = "Recent cases" 9 | @cases = Case.where(is_active: true).where.not(defendant_id: nil) 10 | @counter = "Total cases: #{@cases.count}" 11 | end 12 | 13 | @cases = @cases.order(Arel.sql('date_initiated IS NULL, date_initiated DESC')).paginate(:page => params[:page]) 14 | 15 | @cases_per_year = Case.where('date_initiated IS NOT NULL') 16 | .order(Arel.sql('EXTRACT(YEAR from date_initiated)')) 17 | .group(Arel.sql('EXTRACT(YEAR from date_initiated)')) 18 | .count 19 | @case_trend = [] 20 | (@cases_per_year.keys.first.to_i..@cases_per_year.keys.last.to_i).each do |year| 21 | @case_trend << (@cases_per_year[year.to_f] || 0) 22 | end 23 | end 24 | 25 | def show 26 | @case = Case.find(params[:id]) 27 | if !@case.is_active 28 | redirect_to cases_path, :notice =>"Case not found" 29 | end 30 | #@files = Dir.glob("**/public/case_files/" + @case.number + "_*.pdf").map{|path| path.gsub("public/","/") } 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /app/views/devise/shared/_links.html.erb: -------------------------------------------------------------------------------- 1 | <%- if controller_name != 'sessions' %> 2 | <%= link_to "Sign in", new_session_path(resource_name) %>

    3 | <% end -%> 4 | 5 | <% 6 | =begin %> 7 | <%- if devise_mapping.registerable? && controller_name != 'registrations' %> 8 | <%= link_to "Sign up", new_registration_path(resource_name) %>
    9 | <% end -%> 10 | 11 | <% 12 | =end%> 13 | 14 | <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> 15 | <%= link_to "Forgot your password?", new_password_path(resource_name) %>
    16 | <% end -%> 17 | 18 | <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> 19 | <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
    20 | <% end -%> 21 | 22 | <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> 23 | <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
    24 | <% end -%> 25 | 26 | <%- if devise_mapping.omniauthable? %> 27 | <%- resource_class.omniauth_providers.each do |provider| %> 28 | <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %>
    29 | <% end -%> 30 | <% end -%> 31 | -------------------------------------------------------------------------------- /app/uploaders/image_uploader.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | class ImageUploader < CarrierWave::Uploader::Base 4 | include CarrierWave::MiniMagick 5 | 6 | # Override the directory where uploaded files will be stored. 7 | # This is a sensible default for uploaders that are meant to be mounted: 8 | def store_dir 9 | "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" 10 | end 11 | 12 | # Provide a default URL as a default if there hasn't been a file uploaded: 13 | def default_url(*args) 14 | ActionController::Base.helpers.asset_path("fallback/" + [version_name, "nil_board_image.jpg"].compact.join('_')) 15 | end 16 | 17 | # Process files as they are uploaded: 18 | # process :scale => [200, 300] 19 | 20 | # def scale(width, height) 21 | # # do something 22 | # end 23 | 24 | process resize_to_fit: [800, 800] 25 | 26 | # Create different versions of your uploaded files: 27 | version :thumb do 28 | process :resize_to_limit => [200, 200] 29 | end 30 | 31 | # Add a white list of extensions which are allowed to be uploaded. 32 | # For images you might use something like this: 33 | # def extension_white_list 34 | # %w(jpg jpeg gif png) 35 | # end 36 | 37 | # Override the filename of the uploaded files: 38 | # Avoid using model.id or version_name here, see uploader/store.rb for details. 39 | # def filename 40 | # "something.jpg" if original_filename 41 | # end 42 | 43 | end 44 | -------------------------------------------------------------------------------- /app/assets/stylesheets/reset.css: -------------------------------------------------------------------------------- 1 | /*------------------------------------+ 2 | | Part: Reset browser default styles | 3 | +------------------------------------*/ 4 | 5 | /* Imports 6 | =====================================================================*/ 7 | @import url(//fonts.googleapis.com/css?family=Source+Sans+Pro:300,300italic,400,400italic,600,600italic,700,700italic); 8 | 9 | /*@import "fontawesome/fontawesome.scss";*/ 10 | /*(@import url(//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css);*/ 11 | 12 | a, abbr, acronym, address, applet, big, blockquote, body, caption, cite, code, 13 | dd, del, dfn, div, dl, dt, em, fieldset, font, form, h1, h2, h3, h4, h5, h6, 14 | html, iframe, img, ins, kbd, label, legend, li, object, ol, p, pre, q, s, samp, 15 | small, span, strike, strong, sub, sup, table, tbody, td tfoot, th, thead, tr, 16 | tt, ul, var { 17 | border: 0; 18 | font-family: inherit; 19 | font-size: 100%; 20 | font-style: inherit; 21 | font-weight: inherit; 22 | margin: 0; 23 | outline: 0; 24 | padding: 0; 25 | vertical-align: baseline; 26 | } 27 | 28 | :focus { outline: 0; } 29 | blockquote, q { quotes: "" ""; } 30 | blockquote:before, blockquote:after, q:before, q:after { content: ""; } 31 | body { background: #fff; line-height: 1; color: #000; } 32 | caption, th, td { text-align: left; font-weight: normal; } 33 | ol, ul { list-style: none; } 34 | table { border-collapse: separate; border-spacing: 0; } -------------------------------------------------------------------------------- /app/views/devise/registrations/edit.html.erb: -------------------------------------------------------------------------------- 1 |

    Edit <%= resource_name.to_s.humanize %>

    2 | 3 | <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> 4 | <%= devise_error_messages! %> 5 | 6 |
    7 | <%= f.label :email %>
    8 | <%= f.email_field :email, autofocus: true %> 9 |
    10 | 11 | <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> 12 |
    Currently waiting confirmation for: <%= resource.unconfirmed_email %>
    13 | <% end %> 14 | 15 |
    16 | <%= f.label :password %> (leave blank if you don't want to change it)
    17 | <%= f.password_field :password, autocomplete: "off" %> 18 |
    19 | 20 |
    21 | <%= f.label :password_confirmation %>
    22 | <%= f.password_field :password_confirmation, autocomplete: "off" %> 23 |
    24 | 25 |
    26 | <%= f.label :current_password %> (we need your current password to confirm your changes)
    27 | <%= f.password_field :current_password, autocomplete: "off" %> 28 |
    29 | 30 |
    31 | <%= f.submit "Update" %> 32 |
    33 | <% end %> 34 | 35 |

    Cancel my account

    36 | 37 |

    Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>

    38 | 39 | <%= link_to "Back", :back %> 40 | -------------------------------------------------------------------------------- /app/views/rakes/registrations/edit.html.erb: -------------------------------------------------------------------------------- 1 |

    Edit <%= resource_name.to_s.humanize %>

    2 | 3 | <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> 4 | <%= devise_error_messages! %> 5 | 6 |
    7 | <%= f.label :email %>
    8 | <%= f.email_field :email, autofocus: true %> 9 |
    10 | 11 | <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> 12 |
    Currently waiting confirmation for: <%= resource.unconfirmed_email %>
    13 | <% end %> 14 | 15 |
    16 | <%= f.label :password %> (leave blank if you don't want to change it)
    17 | <%= f.password_field :password, autocomplete: "off" %> 18 |
    19 | 20 |
    21 | <%= f.label :password_confirmation %>
    22 | <%= f.password_field :password_confirmation, autocomplete: "off" %> 23 |
    24 | 25 |
    26 | <%= f.label :current_password %> (we need your current password to confirm your changes)
    27 | <%= f.password_field :current_password, autocomplete: "off" %> 28 |
    29 | 30 |
    31 | <%= f.submit "Update" %> 32 |
    33 | <% end %> 34 | 35 |

    Cancel my account

    36 | 37 |

    Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>

    38 | 39 | <%= link_to "Back", :back %> 40 | -------------------------------------------------------------------------------- /app/controllers/extranet/superintendents_controller.rb: -------------------------------------------------------------------------------- 1 | module Extranet 2 | class SuperintendentsController < Extranet::ApplicationController 3 | before_action :populate_superintendent, only: [:edit, :update] 4 | 5 | def index 6 | @superintendents = Superintendent.order(start_of_term: :desc) 7 | end 8 | 9 | def new 10 | @superintendent = Superintendent.new 11 | end 12 | 13 | def create 14 | @superintendent = Superintendent.new(superintendent_params) 15 | if @superintendent.save 16 | redirect_to extranet_superintendents_path, :notice => "New superintendent successfully added" 17 | else 18 | flash[:alert] = "Oops, there was an error adding a new superintendent." 19 | render :action => 'new' 20 | end 21 | end 22 | 23 | def update 24 | if @superintendent.update(superintendent_params) 25 | redirect_to extranet_superintendents_path, :notice => "Superintendent successfully updated" 26 | else 27 | flash[:alert] = "Oops, there was an error updating superintendent information." 28 | render :action => 'edit' 29 | end 30 | end 31 | 32 | private 33 | def superintendent_params 34 | params.require(:superintendent).permit(:first_name, :last_name, :start_of_term, :end_of_term) 35 | end 36 | 37 | def populate_superintendent 38 | @superintendent = Superintendent.find(params[:id]) 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /db/migrate/20211127153204_convert_to_rich_text.rb: -------------------------------------------------------------------------------- 1 | class ConvertToRichText < ActiveRecord::Migration[6.1] 2 | include ActionView::Helpers::TextHelper 3 | def change 4 | rename_column :board_member_votes, :dissent_description, :dissent_description_old 5 | BoardMemberVote.all.each do |boardMemberVote| 6 | boardMemberVote.update_attribute(:dissent_description, simple_format(boardMemberVote.dissent_description_old)) 7 | end 8 | remove_column :board_member_votes, :dissent_description_old 9 | 10 | rename_column :cases, :majority_decision, :majority_decision_old 11 | Case.all.each do |theCase| 12 | theCase.update_attribute(:majority_decision, simple_format(theCase.majority_decision_old)) 13 | end 14 | remove_column :cases, :majority_decision_old 15 | 16 | rename_column :minority_opinions, :opinion_text, :opinion_text_old 17 | MinorityOpinion.all.each do |minorityOpinion| 18 | minorityOpinion.update_attribute(:opinion_text, simple_format(minorityOpinion.opinion_text_old)) 19 | end 20 | remove_column :minority_opinions, :opinion_text_old 21 | 22 | rename_column :rules, :description, :description_old 23 | rename_column :rules, :comment, :comment_old 24 | Rule.all.each do |rule| 25 | rule.update_attribute(:description, simple_format(rule.description_old)) 26 | rule.update_attribute(:comment, simple_format(rule.comment_old)) 27 | end 28 | remove_column :rules, :description_old 29 | remove_column :rules, :comment_old 30 | 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /app/views/board/responsibilities.html.erb: -------------------------------------------------------------------------------- 1 | <% title "Board responsibilities" %> 2 | 3 |
    4 |

    Board responsibilities

    5 |

    The Police Board's primary powers and responsibilities include the following:

    6 |

    The Board decides disciplinary cases when the Superintendent of Police files charges to discharge or suspend a police officer for more than thirty days.

    7 |

    The Board reviews, upon the request of police officers, disciplinary suspensions of six through thirty days.

    8 |

    The Board decides matters in which the Chief Administrator of the Independent Police Review Authority and the Superintendent do not concur regarding discipline of a police officer.

    9 |

    The Board holds monthly public meetings that provide an opportunity for all members of the public to present questions and comments to the Board, the Superintendent of Police, and the Chief Administrator of the Independent Police Review Authority.

    10 |

    When there is a vacancy in the position of Superintendent of Police, the Board reviews applications, conducts interviews, and submits to the Mayor a list of three candidates; the Mayor must choose from the list or request another list from the Board.

    11 |

    The Board adopts the rules and regulations governing the Police Department.

    12 |

    <%= link_to raw("See board members and their voting history »"), board_index_path %>

    13 |
    -------------------------------------------------------------------------------- /db/migrate/20180413200531_update_minority_opnions_associations.rb: -------------------------------------------------------------------------------- 1 | class UpdateMinorityOpnionsAssociations < ActiveRecord::Migration[4.2] 2 | def change 3 | MinorityOpinion.where("board_member_one = ''").update_all(board_member_one: nil) 4 | MinorityOpinion.where("board_member_two = ''").update_all(board_member_two: nil) 5 | MinorityOpinion.where("board_member_three = ''").update_all(board_member_three: nil) 6 | MinorityOpinion.where("board_member_four = ''").update_all(board_member_four: nil) 7 | 8 | change_column :minority_opinions, :board_member_one, 'integer USING CAST(board_member_one AS integer)' 9 | change_column :minority_opinions, :board_member_two, 'integer USING CAST(board_member_two AS integer)' 10 | change_column :minority_opinions, :board_member_three, 'integer USING CAST(board_member_three AS integer)' 11 | change_column :minority_opinions, :board_member_four, 'integer USING CAST(board_member_four AS integer)' 12 | 13 | rename_column :minority_opinions, :board_member_one, :board_member_one_id 14 | rename_column :minority_opinions, :board_member_two, :board_member_two_id 15 | rename_column :minority_opinions, :board_member_three, :board_member_three_id 16 | rename_column :minority_opinions, :board_member_four, :board_member_four_id 17 | 18 | add_index :minority_opinions, :board_member_one_id 19 | add_index :minority_opinions, :board_member_two_id 20 | add_index :minority_opinions, :board_member_three_id 21 | add_index :minority_opinions, :board_member_four_id 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/uploaders/case_file_uploader.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | class CaseFileUploader < CarrierWave::Uploader::Base 4 | # Override the directory where uploaded files will be stored. 5 | # This is a sensible default for uploaders that are meant to be mounted: 6 | def store_dir 7 | #"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" 8 | "uploads/#{model.class.to_s.underscore}/#{mounted_as}" 9 | end 10 | 11 | # Provide a default URL as a default if there hasn't been a file uploaded: 12 | # def default_url 13 | # # For Rails 3.1+ asset pipeline compatibility: 14 | # # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_')) 15 | # 16 | # "/images/fallback/" + [version_name, "default.png"].compact.join('_') 17 | # end 18 | 19 | # Process files as they are uploaded: 20 | # process :scale => [200, 300] 21 | # 22 | # def scale(width, height) 23 | # # do something 24 | # end 25 | 26 | # Create different versions of your uploaded files: 27 | # version :thumb do 28 | # process :resize_to_fit => [50, 50] 29 | # end 30 | 31 | # Add a white list of extensions which are allowed to be uploaded. 32 | # For images you might use something like this: 33 | def extension_white_list 34 | %w(pdf doc docx) 35 | end 36 | 37 | # Override the filename of the uploaded files: 38 | # Avoid using model.id or version_name here, see uploader/store.rb for details. 39 | # def filename 40 | # "something.jpg" if original_filename 41 | # end 42 | 43 | end 44 | -------------------------------------------------------------------------------- /config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy 4 | # For further information see the following documentation 5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy 6 | 7 | # Rails.application.config.content_security_policy do |policy| 8 | # policy.default_src :self, :https 9 | # policy.font_src :self, :https, :data 10 | # policy.img_src :self, :https, :data 11 | # policy.object_src :none 12 | # policy.script_src :self, :https 13 | # policy.style_src :self, :https 14 | # # If you are using webpack-dev-server then specify webpack-dev-server host 15 | # policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development? 16 | 17 | # # Specify URI for violation reports 18 | # # policy.report_uri "/csp-violation-report-endpoint" 19 | # end 20 | 21 | # If you are using UJS then enable automatic nonce generation 22 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } 23 | 24 | # Set the nonce only to specific directives 25 | # Rails.application.config.content_security_policy_nonce_directives = %w(script-src) 26 | 27 | # Report CSP violations to a specified URI 28 | # For further information see the following documentation: 29 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only 30 | # Rails.application.config.content_security_policy_report_only = true 31 | -------------------------------------------------------------------------------- /db/migrate/20210625201618_create_active_storage_tables.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20170806125915) 2 | class CreateActiveStorageTables < ActiveRecord::Migration[5.2] 3 | def change 4 | create_table :active_storage_blobs do |t| 5 | t.string :key, null: false 6 | t.string :filename, null: false 7 | t.string :content_type 8 | t.text :metadata 9 | t.string :service_name, null: false 10 | t.bigint :byte_size, null: false 11 | t.string :checksum, null: false 12 | t.datetime :created_at, null: false 13 | 14 | t.index [ :key ], unique: true 15 | end 16 | 17 | create_table :active_storage_attachments do |t| 18 | t.string :name, null: false 19 | t.references :record, null: false, polymorphic: true, index: false 20 | t.references :blob, null: false 21 | 22 | t.datetime :created_at, null: false 23 | 24 | t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true 25 | t.foreign_key :active_storage_blobs, column: :blob_id 26 | end 27 | 28 | create_table :active_storage_variant_records do |t| 29 | t.belongs_to :blob, null: false, index: false 30 | t.string :variation_digest, null: false 31 | 32 | t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true 33 | t.foreign_key :active_storage_blobs, column: :blob_id 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /db/migrate/20160210211917_devise_create_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateUsers < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table(:users) do |t| 4 | ## Database authenticatable 5 | t.string :email, null: false, default: "" 6 | t.string :encrypted_password, null: false, default: "" 7 | 8 | ## Recoverable 9 | t.string :reset_password_token 10 | t.datetime :reset_password_sent_at 11 | 12 | ## Rememberable 13 | t.datetime :remember_created_at 14 | 15 | ## Trackable 16 | t.integer :sign_in_count, default: 0, null: false 17 | t.datetime :current_sign_in_at 18 | t.datetime :last_sign_in_at 19 | t.inet :current_sign_in_ip 20 | t.inet :last_sign_in_ip 21 | 22 | ## Confirmable 23 | # t.string :confirmation_token 24 | # t.datetime :confirmed_at 25 | # t.datetime :confirmation_sent_at 26 | # t.string :unconfirmed_email # Only if using reconfirmable 27 | 28 | ## Lockable 29 | # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts 30 | # t.string :unlock_token # Only if unlock strategy is :email or :both 31 | # t.datetime :locked_at 32 | 33 | 34 | t.timestamps null: false 35 | end 36 | 37 | add_index :users, :email, unique: true 38 | add_index :users, :reset_password_token, unique: true 39 | # add_index :users, :confirmation_token, unique: true 40 | # add_index :users, :unlock_token, unique: true 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /app/controllers/analytics_controller.rb: -------------------------------------------------------------------------------- 1 | class AnalyticsController < ApplicationController 2 | 3 | def index 4 | start_year = (params[:start_year] || Date.today.year - 4).to_i 5 | end_year = (params[:end_year] || Date.today.year).to_i 6 | 7 | @cases_filed_by_year_range = (start_year..end_year).to_a 8 | total_cases = [] 9 | decided_cases = [] 10 | 11 | 12 | recommended_outcome_ids = Outcome.where(name: ["Suspension", "Termination"]).map(&:id) 13 | decided_outcome_ids = Outcome.where(name: ["Returned to Duty", "Settlement", "Suspension", "Termination"]).map(&:id) 14 | rank_ids = Rank.where(name: ["Police Officer", "Detective", "Gang Crimes Specialist", "Lieutenant", "Sargeant"]).map(&:id) 15 | 16 | 17 | @cases_filed_by_year_range.each do |year| 18 | cases_per_year = Case.includes(:defendant).where('extract(year from date_initiated) = ?', year).where(recommended_outcome_id: recommended_outcome_ids).where(:defendants => {rank_id: rank_ids}) 19 | decisions_per_year = Case.includes(:defendant).where('extract(year from date_decided) = ?', year).where(decided_outcome_id: decided_outcome_ids).where(:defendants => {rank_id: rank_ids}) 20 | 21 | total_cases.push(cases_per_year.count) 22 | decided_cases.push(decisions_per_year.count) 23 | end 24 | 25 | @cases_filed_by_year_series = [ 26 | { 27 | name: 'Total cases', 28 | data: total_cases 29 | }, 30 | { 31 | name: 'Decided cases', 32 | data: decided_cases 33 | } 34 | ] 35 | 36 | end 37 | 38 | end 39 | 40 | -------------------------------------------------------------------------------- /app/views/board/show.html.erb: -------------------------------------------------------------------------------- 1 | <% title @member.full_name %> 2 | <% body_id "board-detail" %> 3 | 4 |
    5 |
    6 |
    <%= image_tag @member.photo, alt: [@member.full_name, @member.board_position].reject(&:blank?).join(', ') %>
    7 | 8 |

    <%= [@member.full_name, @member.board_position].reject(&:blank?).join(', ') %>

    9 | 10 |

    11 | <%= [@member.job_title, @member.organization].reject(&:blank?).join(', ') %> 12 | <% @member.terms.order(start: :desc).each do |term| %> 13 |
    Appointed <%= term.start.to_formatted_s(:long) %>–<%= term.end ? term.end.to_formatted_s(:long) : '' %> 14 | <% if term.end && term.end >= DateTime.now.to_date %>(Current board member)<% end %> 15 | <% end %> 16 |

    17 |
    18 | <% @vote_bar_chart.each do |bar| %> 19 |
    20 | <%= bar[:display] %> 21 |
    22 | <% end %> 23 |
    24 |
      25 |
    • How often board member agreed with discipline recommendation
    • 26 |
    • Disagreed with recommendation
    • 27 |
    • Did not vote
    • 28 |
    29 |
    30 |
    31 | 32 | <%= render partial: "member_cases", locals: { cases: @member.cases } %> 33 | -------------------------------------------------------------------------------- /app/controllers/extranet/rules_controller.rb: -------------------------------------------------------------------------------- 1 | module Extranet 2 | class RulesController < Extranet::ApplicationController 3 | def index 4 | @rules = Rule.all 5 | @rules.inspect 6 | end 7 | 8 | def new 9 | @rule = Rule.new 10 | end 11 | 12 | def create 13 | @rule = Rule.create 14 | if @rule.save 15 | redirect_to extranet_rules_path, :notice => "Rule successfully added" 16 | else 17 | flash[:error] = "Oops, there was an error creating a new rule." 18 | render :action => 'new' 19 | end 20 | end 21 | 22 | def edit 23 | @rule = Rule.find(params[:id]) 24 | end 25 | 26 | def update 27 | @rule = Rule.find(params[:id]) 28 | if @rule.update(rule_params) 29 | redirect_to extranet_rules_path, :notice => "rule successfully saved" 30 | else 31 | render :action => 'edit' 32 | end 33 | end 34 | 35 | def show 36 | end 37 | 38 | def destroy 39 | @rule = Rule.find(params[:id]) 40 | @rule.destroy 41 | flash[:notice] = "Rule deleted" 42 | redirect_to extranet_rules_path 43 | end 44 | 45 | private 46 | def rule_params 47 | params.require(:rule).permit(:code, :description, :comment) 48 | #params.require(:case).permit(:number, :date_initiated, :date_decided, :recommended_outcome_id, :decided_outcome_id, 49 | # defendant_attributes: [:first_name, :last_name, :rank_id, :number], 50 | # :case_rules_attributes => [[:id, :_destroy]] 51 | #) 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /app/views/extranet/cases/index.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | 3 | <% title "Cases" %> 4 | 5 |

    Cases

    6 |

    <%= link_to "Download CSV", extranet_cases_path(format: :csv) %>

    7 | 8 |

    <%= link_to "Add case", [:new, :extranet, :case], :class => "action" %>

    9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | <% @cases.each do |c| %> 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | <% end %> 34 | 35 |
    <%= sort_link("number", "Case #") %><%= sort_link("defendants.first_name", "Name") %><%= sort_link("date_decided", "Judgement date") %><%= sort_link("outcomes.name", "Outcome") %><%= sort_link("updated_at", "Last modified") %><%= sort_link("id", "Last created") %>
    <%= link_to c.number, [:edit, :extranet, c] %><%= c.defendant.present? ? c.defendant.full_name : '' %><%= c.date_decided %><%= c.decided_outcome.present? ? c.decided_outcome.name : '' %><%= c.updated_at %><%= c.created_at %><%= link_to "X", [:extranet, c], :confirm => 'Are you sure?', :method => :delete, :title => "Delete" %>
    36 |
    37 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | def body_id(body_id) 3 | content_for (:body_id) { body_id } 4 | end 5 | 6 | def navClass(controller) 7 | "current" if params[:controller] == controller || request.path.starts_with?('/' + controller) 8 | end 9 | 10 | def title(page_title) 11 | content_for (:title) { page_title } 12 | end 13 | 14 | def link_to_add_fields(name, f, association) 15 | new_object = f.object.class.reflect_on_association(association).klass.new 16 | fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder| 17 | render(association.to_s.singularize + "_fields", :f => builder) 18 | end 19 | 20 | link_to(name,'#', class: "add_fields", data: {id: 0, fields: fields.gsub("\n",""), association: association}) 21 | end 22 | 23 | def sort_link(column, title = nil) 24 | title ||= column.titleize 25 | direction = column == sort_column && sort_direction == "asc" ? "desc" : "asc" 26 | icon = sort_direction == "asc" ? "▲" : "▼" 27 | icon = column == sort_column ? icon : "" 28 | link_to "#{title} #{icon}".html_safe, 29 | params.permit(:per_page, :search, :sort, :direction).merge(sort: column, direction: direction) 30 | end 31 | 32 | def share_on_facebook 33 | link_to image_tag("facebook.png"), 'https://www.facebook.com/sharer.php?u='+request.original_url, target: :blank 34 | end 35 | 36 | def share_on_twitter(title) 37 | link_to image_tag("twitter.png"), 'https://twitter.com/share?text='+title+'&url='+request.original_url, target: :blank 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /.ebextensions/03_files.config: -------------------------------------------------------------------------------- 1 | files: 2 | "/opt/elasticbeanstalk/support/conf/webapp_healthd.conf": 3 | mode: "000644" 4 | owner: root 5 | group: root 6 | content: | 7 | upstream my_app { 8 | server unix:///var/run/puma/my_app.sock; 9 | } 10 | 11 | log_format healthd '$msec"$uri"' 12 | '$status"$request_time"$upstream_response_time"' 13 | '$http_x_forwarded_for'; 14 | 15 | server { 16 | listen 80; 17 | server_name _ localhost; # need to listen to localhost for worker tier 18 | 19 | if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})") { 20 | set $year $1; 21 | set $month $2; 22 | set $day $3; 23 | set $hour $4; 24 | } 25 | 26 | access_log /var/log/nginx/access.log main; 27 | access_log /var/log/nginx/healthd/application.log.$year-$month-$day-$hour healthd; 28 | 29 | client_max_body_size 20M; 30 | 31 | location / { 32 | proxy_pass http://my_app; # match the name of upstream directive which is defined above 33 | proxy_set_header Host $host; 34 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 35 | } 36 | 37 | location /assets { 38 | alias /var/app/current/public/assets; 39 | gzip_static on; 40 | gzip on; 41 | expires max; 42 | add_header Cache-Control public; 43 | } 44 | 45 | location /public { 46 | alias /var/app/current/public; 47 | gzip_static on; 48 | gzip on; 49 | expires max; 50 | add_header Cache-Control public; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers: a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum; this matches the default thread size of Active Record. 6 | # 7 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 8 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } 9 | threads min_threads_count, max_threads_count 10 | 11 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 12 | # 13 | port ENV.fetch("PORT") { 3000 } 14 | 15 | # Specifies the `environment` that Puma will run in. 16 | # 17 | environment ENV.fetch("RAILS_ENV") { "development" } 18 | 19 | # Specifies the `pidfile` that Puma will use. 20 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } 21 | 22 | # Specifies the number of `workers` to boot in clustered mode. 23 | # Workers are forked web server processes. If using threads and workers together 24 | # the concurrency of the application would be max `threads` * `workers`. 25 | # Workers do not work on JRuby or Windows (both of which do not support 26 | # processes). 27 | # 28 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 29 | 30 | # Use the `preload_app!` method when specifying a `workers` number. 31 | # This directive tells Puma to first boot the application and load code 32 | # before forking the application. This takes advantage of Copy On Write 33 | # process behavior so workers use less memory. 34 | # 35 | # preload_app! 36 | 37 | # Allow puma to be restarted by `rails restart` command. 38 | plugin :tmp_restart 39 | -------------------------------------------------------------------------------- /rails-vagrant-provision.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sudo locale-gen en_US.UTF-8 4 | sudo update-locale LANG=en_US.UTF-8 5 | sudo update-locale LC_ALL=en_US.UTF-8 6 | 7 | sudo apt-get update 8 | sudo apt-get install -y build-essential git curl libxslt1-dev libxml2-dev libssl-dev 9 | 10 | # postgres 11 | echo "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main " | sudo tee -a /etc/apt/sources.list.d/pgdg.list 12 | sudo wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - 13 | sudo apt-get update 14 | sudo apt-get install -y postgresql-9.3 libpq-dev 15 | echo '# "local" is for Unix domain socket connections only 16 | local all all trust 17 | # IPv4 local connections: 18 | host all all 0.0.0.0/0 trust 19 | # IPv6 local connections: 20 | host all all ::/0 trust' | sudo tee /etc/postgresql/9.3/main/pg_hba.conf 21 | sudo sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/g" /etc/postgresql/9.3/main/postgresql.conf 22 | sudo /etc/init.d/postgresql restart 23 | sudo su - postgres -c 'createuser -s vagrant' 24 | 25 | # redis 26 | sudo apt-get install -y python-software-properties 27 | sudo add-apt-repository -y ppa:rwky/redis 28 | sudo apt-get update 29 | sudo apt-get install -y redis-server 30 | 31 | # rvm and ruby 32 | su - vagrant -c 'curl -sSL https://get.rvm.io | bash -s stable --ruby' 33 | su - vagrant -c 'rvm rvmrc warning ignore allGemfiles' 34 | 35 | # node 36 | su - vagrant -c 'curl https://raw.githubusercontent.com/creationix/nvm/v0.14.0/install.sh | sh' 37 | su - vagrant -c 'nvm install 0.10' 38 | su - vagrant -c 'nvm alias default 0.10' 39 | 40 | echo "All done installing! -------------------------------------------------------------------------------- /app/controllers/board_controller.rb: -------------------------------------------------------------------------------- 1 | class BoardController < ApplicationController 2 | def index 3 | board_members = BoardMember.order(board_position: :asc, last_name: :asc) 4 | @current_board_members = board_members.select{ |bm| bm.active == true } 5 | @past_board_members = board_members.select{ |bm| bm.active == false } 6 | end 7 | 8 | def show 9 | @member = BoardMember.find(params[:id]) 10 | 11 | @vote_bar_chart = [ 12 | { :class => "agree", :size => @member.votes_agree_rate }, 13 | { :class => "disagree", :size => @member.votes_dissent_rate }, 14 | { :class => "novote", :size => @member.votes_abstain_rate}] 15 | 16 | if @member.votes_agree_rate > 10 17 | @vote_bar_chart[0].merge!(:symbol => "fa-check-circle", :display => "#{@member.votes_agree_rate}%") 18 | end 19 | if @member.votes_dissent_rate > 10 20 | @vote_bar_chart[1].merge!(:symbol => "fa-times-circle", :display => "#{@member.votes_dissent_rate}%") 21 | end 22 | if @member.votes_abstain_rate > 10 23 | @vote_bar_chart[2].merge!(:symbol => "fa-ban", :display => "#{@member.votes_abstain_rate}%") 24 | end 25 | end 26 | 27 | def new 28 | @member = BoardMember.new() 29 | end 30 | 31 | def create 32 | @member = BoardMember.new(entry_params) 33 | if @member.save 34 | redirect_to board_path(@board), notice: 'Board successfully created' 35 | else 36 | render :new 37 | end 38 | end 39 | 40 | def update 41 | @member = BoardMember.find(params[:id]) 42 | if @member.update(params) 43 | redirect_to board_path(@board), notice: 'Board successfully updated' 44 | else 45 | render :edit 46 | end 47 | end 48 | 49 | def responsibilities 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
    60 |
    61 |

    We're sorry, but something went wrong.

    62 |
    63 |

    If you are the application owner check the logs for more information.

    64 |
    65 | 66 | 67 | -------------------------------------------------------------------------------- /app/views/extranet/superintendents/_form.html.erb: -------------------------------------------------------------------------------- 1 |

    Superintendent details

    2 | <%= form_for [:extranet, @superintendent], :html => {:multipart => true} do |f| %> 3 |
      4 |
    1. 5 |
      <%= f.label :first_name, "Name" %>
      6 |
      7 |
      8 |

      <%= f.text_field :first_name, :class => "txt" %>

      9 |

      <%= f.text_field :last_name, :class => "txt" %>

      10 |
      11 |
      12 |
    2. 13 |
    3. 14 |
      <%= f.label :start_of_term, "Start of term" %>
      15 |
      16 |
      17 |

      <%= f.date_field :start_of_term, :class => "txt", :placeholder => "Start (YYYY-MM-DD)" %>

      18 |
      19 |
      20 |
    4. 21 |
    5. 22 |
      <%= f.label :end_of_term, "End of term" %>
      23 |
      24 |
      25 |

      <%= f.date_field :end_of_term, :class => "txt", :placeholder => "End (YYYY-MM-DD)" %>

      26 |
      27 |
      28 |
    6. 29 |
    30 | 31 |
      32 |
    1. 33 |
      34 | <%= f.submit "Save", :class => "action" %> 35 | <%= link_to "Cancel", extranet_superintendents_path %> 36 |
      37 |
    2. 38 |
    39 | <% end %> 40 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
    60 |
    61 |

    The change you wanted was rejected.

    62 |

    Maybe you tried to change something you didn't have access to.

    63 |
    64 |

    If you are the application owner check the logs for more information.

    65 |
    66 | 67 | 68 | -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
    60 |
    61 |

    The page you were looking for doesn't exist.

    62 |

    You may have mistyped the address or the page may have moved.

    63 |
    64 |

    If you are the application owner check the logs for more information.

    65 |
    66 | 67 | 68 | -------------------------------------------------------------------------------- /app/models/board_member.rb: -------------------------------------------------------------------------------- 1 | class BoardMember < ActiveRecord::Base 2 | has_many :board_member_votes 3 | has_many :terms 4 | has_many :cases, through: :board_member_votes 5 | mount_uploader :image, ImageUploader 6 | 7 | accepts_nested_attributes_for :terms, :allow_destroy => true 8 | 9 | def active 10 | self.terms.each do |term| 11 | if term.end && term.end >= DateTime.now.to_date 12 | return true 13 | end 14 | end 15 | return false 16 | end 17 | 18 | def photo 19 | board_dir = "board-members/" 20 | photo = [board_dir, full_name.downcase.gsub(' ','-').gsub('.',''), ".jpg"].join 21 | File.exists?([Rails.root, "/app/assets/images/", photo].join) ? photo : "#{board_dir}placeholder.jpg" 22 | end 23 | 24 | def full_name 25 | [first_name, last_name].join(' ') 26 | end 27 | 28 | def votes_total_count 29 | total = BoardMemberVote.where(board_member_id: id).count 30 | total == 0 ? 1 : total 31 | end 32 | 33 | def votes_abstain_count 34 | BoardMemberVote.where(board_member_id: id, vote_id: Vote.ABSTAIN).count 35 | end 36 | 37 | def votes_abstain_rate 38 | (votes_abstain_count.to_f / votes_total_count * 100).round 39 | end 40 | 41 | def votes_dissent_count 42 | BoardMemberVote.where(board_member_id: id, vote_id: Vote.DISSENT).count 43 | end 44 | 45 | def votes_dissent_rate 46 | (votes_dissent_count.to_f / votes_total_count * 100).round 47 | end 48 | 49 | def votes_agree_count 50 | agree_vote_id = Vote.find_by_name("Agree") 51 | BoardMemberVote.where(board_member_id: id, vote_id: Vote.AGREE).count 52 | end 53 | 54 | def votes_agree_rate 55 | (votes_agree_count.to_f / votes_total_count * 100).round 56 | end 57 | 58 | def status 59 | if active 60 | return 'current' 61 | else 62 | return 'past' 63 | end 64 | 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /app/controllers/extranet/board_members_controller.rb: -------------------------------------------------------------------------------- 1 | module Extranet 2 | class BoardMembersController < Extranet::ApplicationController 3 | def index 4 | @board_members = BoardMember.all 5 | end 6 | 7 | def new 8 | @board_member = BoardMember.new 9 | 1.times do 10 | term = @board_member.terms.build 11 | end 12 | end 13 | 14 | def create 15 | @board_member = BoardMember.new(board_member_params) 16 | if @board_member.save 17 | redirect_to extranet_board_members_path, :notice => "Board member successfully added" 18 | else 19 | flash[:error] = "Oops there was an error." 20 | render 'new' 21 | end 22 | end 23 | 24 | def edit 25 | @board_member = BoardMember.find(params[:id]) 26 | end 27 | 28 | def update 29 | #render :text => @some_object.inspect 30 | #raise board_member_params.inspect 31 | #debug.inspect 32 | 33 | @board_member = BoardMember.find(params[:id]) 34 | if @board_member.update(board_member_params) 35 | redirect_to extranet_board_members_path, :notice => "Board member successfully updated" 36 | else 37 | render :action => 'edit' 38 | end 39 | 40 | end 41 | 42 | def show 43 | @board_member = BoardMember.find(params[:id]) 44 | end 45 | 46 | def destroy 47 | @board_member = BoardMember.find(params[:id]) 48 | @board_member.destroy 49 | flash[:notice] = "Board member deleted" 50 | redirect_to extranet_board_members_path 51 | end 52 | 53 | private 54 | def board_member_params 55 | params.require(:board_member).permit(:first_name, :last_name, :image, :remove_image, :board_position, :job_title, :organization, 56 | terms_attributes: [:id, :board_member_id, :start, :end] ) 57 | 58 | #params.require(:board_member).permit! 59 | 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | var validEnv = ['development', 'test', 'production'] 3 | var currentEnv = api.env() 4 | var isDevelopmentEnv = api.env('development') 5 | var isProductionEnv = api.env('production') 6 | var isTestEnv = api.env('test') 7 | 8 | if (!validEnv.includes(currentEnv)) { 9 | throw new Error( 10 | 'Please specify a valid `NODE_ENV` or ' + 11 | '`BABEL_ENV` environment variables. Valid values are "development", ' + 12 | '"test", and "production". Instead, received: ' + 13 | JSON.stringify(currentEnv) + 14 | '.' 15 | ) 16 | } 17 | 18 | return { 19 | presets: [ 20 | isTestEnv && [ 21 | '@babel/preset-env', 22 | { 23 | targets: { 24 | node: 'current' 25 | } 26 | } 27 | ], 28 | (isProductionEnv || isDevelopmentEnv) && [ 29 | '@babel/preset-env', 30 | { 31 | forceAllTransforms: true, 32 | useBuiltIns: 'entry', 33 | corejs: 3, 34 | modules: false, 35 | exclude: ['transform-typeof-symbol'] 36 | } 37 | ] 38 | ].filter(Boolean), 39 | plugins: [ 40 | 'babel-plugin-macros', 41 | '@babel/plugin-syntax-dynamic-import', 42 | isTestEnv && 'babel-plugin-dynamic-import-node', 43 | '@babel/plugin-transform-destructuring', 44 | [ 45 | '@babel/plugin-proposal-class-properties', 46 | { 47 | loose: true 48 | } 49 | ], 50 | [ 51 | '@babel/plugin-proposal-object-rest-spread', 52 | { 53 | useBuiltIns: true 54 | } 55 | ], 56 | [ 57 | '@babel/plugin-transform-runtime', 58 | { 59 | helpers: false 60 | } 61 | ], 62 | [ 63 | '@babel/plugin-transform-regenerator', 64 | { 65 | async: false 66 | } 67 | ] 68 | ].filter(Boolean) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'simple_form' 4 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 5 | gem 'rails', '~> 6.0' 6 | # Use postgresql as the database for Active Record 7 | gem 'pg' 8 | # Use SCSS for stylesheets 9 | gem 'sass-rails', '~> 5.0' 10 | # Use Uglifier as compressor for JavaScript assets 11 | gem 'uglifier', '>= 1.3.0' 12 | # Use CoffeeScript for .js.coffee assets and views 13 | gem 'coffee-rails', '~> 5.0' 14 | # See https://github.com/sstephenson/execjs#readme for more supported runtimes 15 | # gem 'therubyracer', platforms: :ruby 16 | 17 | 18 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 19 | gem 'jbuilder', '~> 2.0' 20 | # bundle exec rake doc:rails generates the API under doc/api. 21 | #gem 'sdoc', '~> 0.4.0', group: :doc 22 | 23 | gem 'twitter' 24 | 25 | group :development do 26 | gem 'foreman' 27 | gem 'htmlbeautifier' 28 | gem 'spring' 29 | gem 'listen' 30 | end 31 | 32 | # Use ActiveModel has_secure_password 33 | # gem 'bcrypt', '~> 3.1.7' 34 | 35 | # Use unicorn as the app server 36 | # gem 'unicorn' 37 | 38 | # Use Capistrano for deployment 39 | # gem 'capistrano-rails', group: :development 40 | 41 | # Use debugger 42 | # gem 'debugger', group: [:development, :test] 43 | 44 | # use devise for authentication 45 | gem 'devise' 46 | 47 | 48 | # For Heroku 49 | #gem 'rails_12factor', group: :production 50 | gem 'puma' 51 | 52 | ruby '~> 3.0' 53 | 54 | gem 'font-awesome-rails', '~> 4.7.0.7' 55 | #gem 'font-awesome-sass' 56 | gem 'roo', '~> 2.0.0' 57 | gem 'will_paginate' 58 | 59 | gem 'mini_magick' 60 | gem 'carrierwave', '~> 1.0' 61 | 62 | gem 'fog-aws' 63 | 64 | gem 'tinymce-rails' 65 | 66 | #for managing environment variables 67 | gem 'figaro' 68 | 69 | gem 'aws-sdk' 70 | 71 | #for debugging 72 | gem 'byebug', group: [:development, :test] 73 | 74 | 75 | #for notification banners 76 | gem 'izitoast' 77 | 78 | gem 'bootsnap' 79 | 80 | gem 'webpacker', '~> 5.4' 81 | 82 | 83 | -------------------------------------------------------------------------------- /config/initializers/new_framework_defaults_5_2.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains migration options to ease your Rails 5.2 upgrade. 4 | # 5 | # Once upgraded flip defaults one by one to migrate to the new default. 6 | # 7 | # Read the Guide for Upgrading Ruby on Rails for more info on each option. 8 | 9 | # Make Active Record use stable #cache_key alongside new #cache_version method. 10 | # This is needed for recyclable cache keys. 11 | # Rails.application.config.active_record.cache_versioning = true 12 | 13 | # Use AES-256-GCM authenticated encryption for encrypted cookies. 14 | # Also, embed cookie expiry in signed or encrypted cookies for increased security. 15 | # 16 | # This option is not backwards compatible with earlier Rails versions. 17 | # It's best enabled when your entire app is migrated and stable on 5.2. 18 | # 19 | # Existing cookies will be converted on read then written with the new scheme. 20 | # Rails.application.config.action_dispatch.use_authenticated_cookie_encryption = true 21 | 22 | # Use AES-256-GCM authenticated encryption as default cipher for encrypting messages 23 | # instead of AES-256-CBC, when use_authenticated_message_encryption is set to true. 24 | # Rails.application.config.active_support.use_authenticated_message_encryption = true 25 | 26 | # Add default protection from forgery to ActionController::Base instead of in 27 | # ApplicationController. 28 | # Rails.application.config.action_controller.default_protect_from_forgery = true 29 | 30 | # Store boolean values are in sqlite3 databases as 1 and 0 instead of 't' and 31 | # 'f' after migrating old data. 32 | # Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true 33 | 34 | # Use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header. 35 | # Rails.application.config.active_support.use_sha1_digests = true 36 | 37 | # Make `form_with` generate id attributes for any generated HTML tags. 38 | # Rails.application.config.action_view.form_with_generates_ids = true 39 | -------------------------------------------------------------------------------- /app/views/rules/index.html.erb: -------------------------------------------------------------------------------- 1 | <% title "Rules of conduct" %> 2 | <% body_id "rules-index" %> 3 | 4 |
    5 |

    Rules of conduct

    6 | 7 |

    From the Rules and Regulations of the Chicago Police Department adopted and published by the Police Board.

    8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | <% @rules.each do |rule| %> 22 | 23 | 24 | 25 | 34 | <% cases = CaseRule.where(rule_id: rule.id).count %> 35 | 36 | 37 | 38 | 39 | <% end %> 40 | 41 |
    Hidden rule #Rule Description Cases Hidden cases
    <%= rule.code %>Rule <%= rule.code %> 26 |

    <%= rule.description %> 27 | <% if rule.comment && raw(rule.comment).length>45 %> 28 | Show special comment

    29 | 30 | <% else %> 31 |
    32 | <% end %> 33 |
    <%= cases %> (<%= (cases.to_f / Case.count * 100).round %>%)
    42 |
    43 | 44 | 45 | 46 | <%= javascript_pack_tag "rules" %> 47 | -------------------------------------------------------------------------------- /app/views/welcome/index.html.erb: -------------------------------------------------------------------------------- 1 | <% title "Home" %> 2 | <% body_id "home" %> 3 | 4 | 5 | 6 | 7 |
    8 |

    Case outcomes

    9 |

    How does the superintendent's recommended discipline compare to the final police board's judgement?

    10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | <% @case_outcomes.each do |outcomes, count| %> 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | <% end %> 31 | 32 |
    Recommendation Decision Cases Annual trend
    <%= count %><%= Outcome.find(outcomes[0]).name %> <%= Outcome.find(outcomes[1]).name %><%= count %> (<%= (count.to_f / @cases.count * 100).round %>%)<%= Case.count_per_year_for_outcome(outcomes[0], outcomes[1]).join(',') %>
    33 |
    34 | 35 | <%= render partial: "board/list", locals: { board_members: @board_members, title: '

    Board member voting history

    ', table_id: 'board-list' } %> 36 | 37 | 38 | 39 | 40 | <%= javascript_pack_tag "board-members-voting-history" %> 41 | <%= javascript_pack_tag "home" %> 42 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | # The test environment is used exclusively to run your application's 2 | # test suite. You never need to work with it otherwise. Remember that 3 | # your test database is "scratch space" for the test suite and is wiped 4 | # and recreated between test runs. Don't rely on the data there! 5 | 6 | Rails.application.configure do 7 | # Settings specified here will take precedence over those in config/application.rb. 8 | 9 | config.cache_classes = true 10 | 11 | # Do not eager load code on boot. This avoids loading your whole application 12 | # just for the purpose of running a single test. If you are using a tool that 13 | # preloads Rails for running tests, you may have to set it to true. 14 | config.eager_load = false 15 | 16 | # Configure public file server for tests with Cache-Control for performance. 17 | config.public_file_server.enabled = true 18 | config.public_file_server.headers = { 19 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}" 20 | } 21 | 22 | # Show full error reports and disable caching. 23 | config.consider_all_requests_local = true 24 | config.action_controller.perform_caching = false 25 | config.cache_store = :null_store 26 | 27 | # Raise exceptions instead of rendering exception templates. 28 | config.action_dispatch.show_exceptions = false 29 | 30 | # Disable request forgery protection in test environment. 31 | config.action_controller.allow_forgery_protection = false 32 | 33 | # Store uploaded files on the local file system in a temporary directory. 34 | config.active_storage.service = :test 35 | 36 | config.action_mailer.perform_caching = false 37 | 38 | # Tell Action Mailer not to deliver emails to the real world. 39 | # The :test delivery method accumulates sent emails in the 40 | # ActionMailer::Base.deliveries array. 41 | config.action_mailer.delivery_method = :test 42 | 43 | # Print deprecation notices to the stderr. 44 | config.active_support.deprecation = :stderr 45 | 46 | # Raises error for missing translations. 47 | # config.action_view.raise_on_missing_translations = true 48 | end 49 | -------------------------------------------------------------------------------- /app/views/analytics/index.html.erb: -------------------------------------------------------------------------------- 1 | <% title "Analytics" %> 2 | <% body_id "analytics-index" %> 3 |
    4 |

    Case Analytics

    5 |
    6 | 7 | 8 |
    9 |
    10 | 11 |
    12 | <%= form_tag({url: analytics_path}, {method: :get}) do %> 13 | <%= label_tag :start_year %> 14 | <%= text_field_tag :start_year, params[:start_year]|| Date.today.year - 4 %> 15 | 16 | <%= label_tag :end_year %> 17 | <%= text_field_tag :end_year, params[:end_year] || Date.today.year %> 18 | 19 | <%= submit_tag "Update" %> 20 | <% end %> 21 |
    22 |
    23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /config/webpacker.yml: -------------------------------------------------------------------------------- 1 | # Note: You must restart bin/webpack-dev-server for changes to take effect 2 | 3 | default: &default 4 | source_path: app/javascript 5 | source_entry_path: packs 6 | public_root_path: public 7 | public_output_path: packs 8 | cache_path: tmp/cache/webpacker 9 | webpack_compile_output: true 10 | 11 | # Additional paths webpack should lookup modules 12 | # ['app/assets', 'engine/foo/app/assets'] 13 | additional_paths: ['app/assets','node_modules'] 14 | 15 | # Reload manifest.json on all requests so we reload latest compiled packs 16 | cache_manifest: false 17 | 18 | # Extract and emit a css file 19 | extract_css: false 20 | 21 | static_assets_extensions: 22 | - .jpg 23 | - .jpeg 24 | - .png 25 | - .gif 26 | - .tiff 27 | - .ico 28 | - .svg 29 | - .eot 30 | - .otf 31 | - .ttf 32 | - .woff 33 | - .woff2 34 | 35 | extensions: 36 | - .mjs 37 | - .js 38 | - .sass 39 | - .scss 40 | - .css 41 | - .module.sass 42 | - .module.scss 43 | - .module.css 44 | - .png 45 | - .svg 46 | - .gif 47 | - .jpeg 48 | - .jpg 49 | 50 | development: 51 | <<: *default 52 | compile: true 53 | 54 | # Reference: https://webpack.js.org/configuration/dev-server/ 55 | dev_server: 56 | https: false 57 | host: localhost 58 | port: 3035 59 | public: localhost:3035 60 | hmr: false 61 | # Inline should be set to true if using HMR 62 | inline: true 63 | overlay: true 64 | compress: true 65 | disable_host_check: true 66 | use_local_ip: false 67 | quiet: false 68 | pretty: false 69 | headers: 70 | 'Access-Control-Allow-Origin': '*' 71 | watch_options: 72 | ignored: '**/node_modules/**' 73 | 74 | 75 | test: 76 | <<: *default 77 | compile: true 78 | 79 | # Compile test packs to a separate directory 80 | public_output_path: packs-test 81 | 82 | production: 83 | <<: *default 84 | 85 | # Production depends on precompilation of packs prior to booting for performance. 86 | compile: false 87 | 88 | # Extract and emit a css file 89 | extract_css: true 90 | 91 | # Cache manifest.json for performance 92 | cache_manifest: true 93 | -------------------------------------------------------------------------------- /app/views/board/_list.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | <%= raw(title) %> 3 | 4 | > 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | <% board_members.each do |bm| %> 26 | 27 | 28 | 29 | 37 | 38 | 39 | 40 | 45 | 46 | <% end %> 47 | 48 |
    How often a member agreed with the final decision of the board 11 |
    Board member Agreed Disagreed Did not vote Voting chart
    <%= bm.last_name %><%= image_tag bm.image_url(:thumb), alt: [bm.full_name, bm.board_position].reject(&:blank?).join(', '), size: '70' %> 30 |

    31 | <%= link_to [bm.full_name, bm.board_position].reject(&:blank?).join(', ') , board_path(bm) %> 32 |

    33 |

    34 | <%= [bm.job_title, bm.organization].reject(&:blank?).join(', ') %> 35 |

    36 |
    <%= bm.votes_agree_rate %>%<%= bm.votes_dissent_rate %>%<%= bm.votes_abstain_rate %>% 41 |
    42 |
    43 |
    44 |
    49 |
    50 | -------------------------------------------------------------------------------- /config/initializers/new_framework_defaults_6_0.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains migration options to ease your Rails 6.0 upgrade. 4 | # 5 | # Once upgraded flip defaults one by one to migrate to the new default. 6 | # 7 | # Read the Guide for Upgrading Ruby on Rails for more info on each option. 8 | 9 | # Don't force requests from old versions of IE to be UTF-8 encoded. 10 | # Rails.application.config.action_view.default_enforce_utf8 = false 11 | 12 | # Embed purpose and expiry metadata inside signed and encrypted 13 | # cookies for increased security. 14 | # 15 | # This option is not backwards compatible with earlier Rails versions. 16 | # It's best enabled when your entire app is migrated and stable on 6.0. 17 | # Rails.application.config.action_dispatch.use_cookies_with_metadata = true 18 | 19 | # Change the return value of `ActionDispatch::Response#content_type` to Content-Type header without modification. 20 | # Rails.application.config.action_dispatch.return_only_media_type_on_content_type = false 21 | 22 | # Return false instead of self when enqueuing is aborted from a callback. 23 | # Rails.application.config.active_job.return_false_on_aborted_enqueue = true 24 | 25 | # Send Active Storage analysis and purge jobs to dedicated queues. 26 | # Rails.application.config.active_storage.queues.analysis = :active_storage_analysis 27 | # Rails.application.config.active_storage.queues.purge = :active_storage_purge 28 | 29 | # When assigning to a collection of attachments declared via `has_many_attached`, replace existing 30 | # attachments instead of appending. Use #attach to add new attachments without replacing existing ones. 31 | # Rails.application.config.active_storage.replace_on_assign_to_many = true 32 | 33 | # Use ActionMailer::MailDeliveryJob for sending parameterized and normal mail. 34 | # 35 | # The default delivery jobs (ActionMailer::Parameterized::DeliveryJob, ActionMailer::DeliveryJob), 36 | # will be removed in Rails 6.1. This setting is not backwards compatible with earlier Rails versions. 37 | # If you send mail in the background, job workers need to have a copy of 38 | # MailDeliveryJob to ensure all delivery jobs are processed properly. 39 | # Make sure your entire app is migrated and stable on 6.0 before using this setting. 40 | # Rails.application.config.action_mailer.delivery_job = "ActionMailer::MailDeliveryJob" 41 | 42 | # Enable the same cache key to be reused when the object being cached of type 43 | # `ActiveRecord::Relation` changes by moving the volatile information (max updated at and count) 44 | # of the relation's cache key into the cache version to support recycling cache key. 45 | # Rails.application.config.active_record.collection_cache_versioning = true 46 | -------------------------------------------------------------------------------- /app/views/cases/index.html.erb: -------------------------------------------------------------------------------- 1 | <% title "Cases" %> 2 | 3 |
    4 |

    Cases

    5 | 6 | 16 |
    17 | 18 |
    19 |
    20 |

    <%= @header %>

    21 | 22 |
      23 | <% if @cases.present? %> 24 | <%= render partial: "case", collection: @cases, as: :c %> 25 | <%= will_paginate @cases %> 26 | <% else %> 27 |

      No cases found for your search criteria.

      28 | <% end %> 29 |
    30 |

    <%= link_to raw('View all cases »'), cases_path if params[:search]%>

    31 |
    32 | 33 |
    34 |

    <%= @counter %>

    35 |
    > 36 |
    37 |
    38 |
    39 |
    40 | 41 | <%= javascript_include_tag "//code.highcharts.com/highcharts.js" %> 42 | 95 | 96 | <%= javascript_pack_tag "case" %> -------------------------------------------------------------------------------- /app/views/extranet/board_members/_form.html.erb: -------------------------------------------------------------------------------- 1 |

    Board details

    2 | <%= form_for [:extranet, @board_member], :html => {:multipart => true} do |f| %> 3 |
      4 |
    1. 5 |
      <%= f.label :first_name, "Name" %>
      6 |
      7 |
      8 |

      <%= f.text_field :first_name, :class => "txt" %>

      9 |

      <%= f.text_field :last_name, :class => "txt" %>

      10 |
      11 |
      12 |
    2. 13 |
    3. 14 |
      <%= f.label :image %>
      15 |
      <%= image_tag @board_member.image_url(:thumb).to_s %> 16 |
      <%= f.check_box :remove_image %>Remove image
      17 |
      <%= f.file_field :image %>
      18 |
    4. 19 |
    5. 20 |
      <%= f.label :board_position %>
      21 |
      <%= f.text_field :board_position, :class => "txt-med" %>
      22 |
    6. 23 |
    7. 24 |
      <%= f.label :organization %>
      25 |
      <%= f.text_field :organization, :class => "txt-med" %>
      26 |
    8. 27 |
    9. 28 |
      <%= f.label :job_title %>
      29 |
      <%= f.text_field :job_title, :class => "txt-med" %>
      30 |
    10. 31 | 32 | <%= f.fields_for :terms do |builder| %> 33 |
    11. 34 |
      <%= builder.label :start, "Appointed" %>
      35 |
      36 |
      37 |

      Started (YYYY-MM-DD) <%= builder.text_field :start %>

      38 |

      Ended (YYYY-MM-DD) 39 | <%= builder.text_field :end %>

      40 | <%= builder.hidden_field :id %> 41 | <%= builder.hidden_field :_destroy %> 42 |
      43 |
      44 |
    12. 45 | <% end %> 46 | 47 |
    48 | 49 |
      50 |
    1. 51 |
      52 | <%= f.submit "Save", :class => "action" %> <%= link_to "Cancel", extranet_board_members_path %> 53 |
      54 |
    2. 55 |
    56 | 57 | 58 | <% end %> 59 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | config.log_level = :debug 3 | # Verifies that versions and hashed value of the package contents in the project's package.json 4 | config.webpacker.check_yarn_integrity = true 5 | # Settings specified here will take precedence over those in config/application.rb. 6 | 7 | # In the development environment your application's code is reloaded on 8 | # every request. This slows down response time but is perfect for development 9 | # since you don't have to restart the web server when you make code changes. 10 | config.cache_classes = false 11 | 12 | # Do not eager load code on boot. 13 | config.eager_load = false 14 | 15 | # Show full error reports. 16 | config.consider_all_requests_local = true 17 | 18 | # Enable/disable caching. By default caching is disabled. 19 | # Run rails dev:cache to toggle caching. 20 | if Rails.root.join('tmp', 'caching-dev.txt').exist? 21 | config.action_controller.perform_caching = true 22 | config.action_controller.enable_fragment_cache_logging = true 23 | 24 | config.cache_store = :memory_store 25 | config.public_file_server.headers = { 26 | 'Cache-Control' => "public, max-age=#{2.days.to_i}" 27 | } 28 | else 29 | config.action_controller.perform_caching = false 30 | 31 | config.cache_store = :null_store 32 | end 33 | 34 | # Store uploaded files on the local file system (see config/storage.yml for options). 35 | config.active_storage.service = :local 36 | 37 | # Don't care if the mailer can't send. 38 | config.action_mailer.raise_delivery_errors = false 39 | 40 | config.action_mailer.perform_caching = false 41 | 42 | # Print deprecation notices to the Rails logger. 43 | config.active_support.deprecation = :log 44 | 45 | # Raise an error on page load if there are pending migrations. 46 | config.active_record.migration_error = :page_load 47 | 48 | # Highlight code that triggered database queries in logs. 49 | config.active_record.verbose_query_logs = true 50 | 51 | # Debug mode disables concatenation and preprocessing of assets. 52 | # This option may cause significant delays in view rendering with a large 53 | # number of complex assets. 54 | config.assets.debug = true 55 | 56 | # Suppress logger output for asset requests. 57 | config.assets.quiet = true 58 | 59 | # Raises error for missing translations. 60 | # config.action_view.raise_on_missing_translations = true 61 | 62 | # Use an evented file watcher to asynchronously detect changes in source code, 63 | # routes, locales, etc. This feature depends on the listen gem. 64 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker 65 | 66 | config.hosts << ENV["APP_DOMAIN"] unless ENV["APP_DOMAIN"].nil? 67 | if (gitpod_workspace_url = ENV["GITPOD_WORKSPACE_URL"]) 68 | config.hosts << /.*#{URI.parse(gitpod_workspace_url).host}/ 69 | end 70 | config.app_domain = ENV["APP_DOMAIN"] || "localhost:3000" 71 | 72 | end 73 | -------------------------------------------------------------------------------- /app/javascript/packs/responsive-init.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | $().ready(function () { 3 | 4 | //this script relies on responsive.js 5 | var _Responsive = Responsive || 6 | // ensure no js errors if not included 7 | { init: function () { alert('Method not implemented; please include responsive.js script in page head!'); } }, 8 | 9 | 10 | //flags 11 | _menu_created, 12 | _menu_open, 13 | 14 | 15 | //method to create the custom sidebar menu for smaller window sizes 16 | _createMenu = function () { 17 | if ($("#nav").size() == 0) return; 18 | 19 | var nav = $("#nav").html(); 20 | 21 | $("body").append(""); 22 | $("#header .content").prepend(" Menu"); 23 | $("#menu .fa-home").after(" Home"); 24 | 25 | $("#menu").height($(window).height()); 26 | $("#nav").hide(); 27 | 28 | $("#nav-toggle").click(function (event) { 29 | $("#menu").show().animate({ right: "0" }, 150); 30 | $("#wrapper").css({ position: "fixed", top: 0, width: $("#wrapper").width() }).animate({ right: "250px" }, 150); 31 | _menu_open = true; 32 | event.stopPropagation(); 33 | return false; 34 | }); 35 | 36 | $("#nav-toggle").click(function (event) { 37 | $("#menu").show().animate({ right: "0" }, 150); 38 | $("#wrapper").css({ position: "fixed", top: 0, width: $("#wrapper").width() }).animate({ right: "250px" }, 150); 39 | _menu_open = true; 40 | event.stopPropagation(); 41 | return false; 42 | }); 43 | 44 | $("html").on("click touchstart", function (e) { 45 | if (_menu_open && $("#menu").has(e.target).length === 0) { 46 | $("#menu").animate({ right: "-400px" }, 150, function () { 47 | $(this).hide(); 48 | }); 49 | $("#wrapper").animate({ right: 0 }, 150, function () { 50 | $(this).css({ position: "static", top: "auto", width: "auto" }); 51 | }); 52 | _menu_open = false; 53 | e.stopPropagation(); 54 | return false; 55 | } 56 | }); 57 | }, 58 | 59 | //method to remove the custom sidebar menu 60 | _removeMenu = function () { 61 | $("#menu, #nav-toggle").remove(); 62 | $("#wrapper").css({ position: "static", top: "auto", width: "auto" }); 63 | $("#nav").show(); 64 | }; 65 | 66 | 67 | // initialize responsive layouts 68 | _Responsive.init({ 69 | layouts: { 70 | MEDIUM: { maxWidth: 900, stylesheet: false }, 71 | NARROW: { maxWidth: 400, stylesheet: false } 72 | }, 73 | //listen for responsive layout change; will also be fired once on page load 74 | onLayoutChange: function (layout) { 75 | if (layout == _Responsive.LayoutType.MEDIUM || layout == _Responsive.LayoutType.NARROW) { 76 | if (!_menu_created) 77 | _createMenu(); 78 | _menu_created = true; 79 | } 80 | else { 81 | if (_menu_created) 82 | _removeMenu(); 83 | _menu_created = false; 84 | } 85 | } 86 | }); 87 | 88 | }); 89 | --------------------------------------------------------------------------------