├── log └── .keep ├── .rspec ├── app ├── mailers │ ├── .keep │ ├── application_mailer.rb │ └── organisation_admin_mailer.rb ├── models │ ├── .keep │ ├── concerns │ │ └── .keep │ ├── country_scores_datum.rb │ ├── link.rb │ ├── improvement.rb │ ├── country_score.rb │ ├── organisation_score.rb │ ├── ability.rb │ ├── questionnaire.rb │ ├── dimension.rb │ ├── score.rb │ ├── answer.rb │ ├── question.rb │ ├── country.rb │ ├── activity.rb │ ├── organisation.rb │ ├── assessment_answer.rb │ └── user.rb ├── assets │ ├── images │ │ ├── .keep │ │ ├── cc.png │ │ ├── favicon.ico │ │ └── logo-footer.png │ ├── javascripts │ │ ├── targets.coffee │ │ ├── forms.js.erb │ │ └── application.js │ └── stylesheets │ │ ├── colours.scss │ │ ├── targets.scss │ │ ├── application.scss │ │ ├── question.scss │ │ └── home.scss ├── controllers │ ├── concerns │ │ └── .keep │ ├── home_controller.rb │ ├── admin_controller.rb │ ├── countries_controller.rb │ ├── organisations_controller.rb │ ├── base_admin_controller.rb │ ├── organisation_admins_controller.rb │ ├── targets_controller.rb │ ├── application_controller.rb │ ├── user_controller.rb │ ├── registrations_controller.rb │ └── assessments_controller.rb ├── views │ ├── layouts │ │ ├── mailer.text.erb │ │ ├── mailer.html.erb │ │ ├── _footer.html.erb │ │ ├── _header.html.erb │ │ └── application.html.erb │ ├── user │ │ ├── edit.html.erb │ │ ├── new.html.erb │ │ └── _form.html.erb │ ├── devise │ │ ├── mailer │ │ │ ├── confirmation_instructions.html.erb │ │ │ ├── unlock_instructions.html.erb │ │ │ └── reset_password_instructions.html.erb │ │ ├── passwords │ │ │ ├── edit.html.erb │ │ │ └── new.html.erb │ │ ├── unlocks │ │ │ └── new.html.erb │ │ ├── confirmations │ │ │ └── new.html.erb │ │ ├── shared │ │ │ ├── _password.html.erb │ │ │ └── _links.html.erb │ │ ├── sessions │ │ │ └── new.html.erb │ │ └── registrations │ │ │ └── new.html.erb │ ├── assessments │ │ ├── _score_label.html.erb │ │ ├── _next_goal_label.html.erb │ │ ├── _activity_label.html.erb │ │ ├── _theme_label.html.erb │ │ ├── edit.html.erb │ │ ├── _first_assessment.html.erb │ │ ├── _information_tab.html.erb │ │ ├── index.html.erb │ │ ├── _summary_tab.html.erb │ │ ├── _share_modal.html.erb │ │ ├── _activity_tab.html.erb │ │ ├── _assessment_summary.html.erb │ │ ├── _overview.html.erb │ │ ├── report.html.erb │ │ └── _improvements_tab.html.erb │ ├── shared │ │ └── _errors.html.erb │ ├── organisation_admin_mailer │ │ ├── help_request.text.erb │ │ └── help_request.html.erb │ ├── pages │ │ ├── contact.html.erb │ │ └── cookie_policy.html.erb │ ├── organisation_admins │ │ └── new_contact.html.erb │ ├── links │ │ └── _link_fields.html.erb │ ├── admin │ │ └── index.html.erb │ ├── assessment_answers │ │ ├── edit.html.erb │ │ ├── new.html.erb │ │ └── _form.html.erb │ ├── statistics │ │ └── index.html.erb │ └── targets │ │ └── edit.html.erb └── helpers │ ├── admin_helper.rb │ ├── home_helper.rb │ ├── targets_helper.rb │ ├── organisations_helper.rb │ ├── assessment_answers_helper.rb │ ├── assessments_helper.rb │ ├── user_helper.rb │ ├── devise_helper.rb │ └── application_helper.rb ├── lib ├── assets │ └── .keep ├── tasks │ ├── .keep │ ├── countries.rake │ ├── statistics.rake │ ├── questionnaire.rake │ ├── organisations.rake │ └── cucumber.rake ├── country_importer.rb ├── organisation_importer.rb ├── assessment_scorer.rb ├── progress_calculator.rb └── questionnaire_importer.rb ├── public ├── favicon.ico ├── robots.txt ├── 500.html ├── 422.html └── 404.html ├── test ├── helpers │ └── .keep ├── mailers │ └── .keep ├── models │ ├── .keep │ └── user_test.rb ├── controllers │ ├── .keep │ └── home_controller_test.rb ├── fixtures │ ├── .keep │ └── users.yml └── integration │ └── .keep ├── .ruby-version ├── vendor └── assets │ ├── javascripts │ └── .keep │ └── stylesheets │ └── .keep ├── features ├── step_definitions │ ├── .gitkeep │ ├── admin_steps.rb │ ├── statistics_steps.rb │ ├── register_steps.rb │ ├── web_steps.rb │ ├── question_steps.rb │ ├── authentication_steps.rb │ └── assessment_steps.rb ├── admin.feature ├── home.feature ├── targets.feature ├── sharing.feature └── report.feature ├── survey └── survey.xls ├── spec ├── lib │ ├── test-survey.xls │ ├── organisations_rake_spec.rb │ └── organisation_importer_spec.rb ├── support │ └── factory_girl.rb ├── controllers │ ├── user_controller_spec.rb │ ├── targets_controller_spec.rb │ ├── assessments_controller_spec.rb │ ├── assessment_answers_controller_spec.rb │ ├── organisation_admins_controller_spec.rb │ ├── admin_controller_spec.rb │ ├── organisations_controller_spec.rb │ ├── countries_controller_spec.rb │ └── registrations_controller_spec.rb ├── factories │ ├── questionnaires.rb │ ├── improvements.rb │ ├── links.rb │ ├── scores.rb │ ├── activities.rb │ ├── dimensions.rb │ ├── questions.rb │ ├── organisation_scores.rb │ ├── assessment_answers.rb │ ├── countries.rb │ ├── answers.rb │ └── assessments.rb ├── views │ └── assessments │ │ └── index.html.erb_spec.rb ├── models │ ├── link_spec.rb │ ├── score_spec.rb │ ├── questionnaire_spec.rb │ ├── dimension_spec.rb │ ├── country_spec.rb │ ├── improvement_spec.rb │ ├── question_spec.rb │ ├── answer_spec.rb │ ├── organisation_spec.rb │ ├── activity_spec.rb │ └── user_spec.rb ├── helpers │ ├── targets_helper_spec.rb │ ├── assessments_helper_spec.rb │ ├── organisations_helper_spec.rb │ └── assessment_answers_helper_spec.rb ├── mailers │ └── organisation_admin_mailer_spec.rb └── rails_helper.rb ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── bin ├── bundle ├── rake ├── rails ├── rspec ├── autospec ├── cucumber ├── spring └── setup ├── config ├── boot.rb ├── initializers │ ├── cookies_serializer.rb │ ├── session_store.rb │ ├── mime_types.rb │ ├── filter_parameter_logging.rb │ ├── backtrace_silencers.rb │ ├── assets.rb │ ├── wrap_parameters.rb │ └── inflections.rb ├── environment.rb ├── cucumber.yml ├── database.yml ├── secrets.yml ├── application.rb ├── environments │ ├── test.rb │ └── development.rb └── locales │ └── en.yml ├── config.ru ├── db ├── migrate │ ├── 20150320160725_add_name_to_users.rb │ ├── 20150311123734_change_notes_column_type.rb │ ├── 20150306133403_add_organisation_id_to_users.rb │ ├── 20161104002323_add_country_to_user.rb │ ├── 20160926132807_create_country_scores.rb │ ├── 20161216082751_add_country_to_country_score.rb │ ├── 20150224155616_add_admin_to_users.rb │ ├── 20161216082828_add_activity_to_country_score.rb │ ├── 20150311170825_add_assessment_id_to_assessment_answers.rb │ ├── 20150309071504_create_dimensions.rb │ ├── 20150325123402_create_improvements.rb │ ├── 20150318112628_create_scores.rb │ ├── 20150305150652_create_organisations.rb │ ├── 20150309071529_create_activities.rb │ ├── 20150309071413_create_questionnaires.rb │ ├── 20150311124917_create_links.rb │ ├── 20161218004436_create_country_scores_data.rb │ ├── 20161104002256_create_countries.rb │ ├── 20150309071639_create_questions.rb │ ├── 20161218043408_add_stats_to_country_scores.rb │ ├── 20150504121056_add_token_to_assessment.rb │ ├── 20150309071711_create_answers.rb │ ├── 20150311110709_create_assessments.rb │ ├── 20150311121727_create_assessment_answers.rb │ ├── 20150506111100_create_organisation_scores.rb │ └── 20150224140146_devise_create_users.rb └── seeds.rb ├── .travis.yml ├── Rakefile ├── script └── cucumber ├── .gitignore ├── LICENCE.md ├── app.json ├── Gemfile └── CONTRIBUTING.md /log/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | -------------------------------------------------------------------------------- /app/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/helpers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/models/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/controllers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/integration/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.4.1 2 | 3 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /features/step_definitions/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /app/helpers/admin_helper.rb: -------------------------------------------------------------------------------- 1 | module AdminHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/home_helper.rb: -------------------------------------------------------------------------------- 1 | module HomeHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/targets_helper.rb: -------------------------------------------------------------------------------- 1 | module TargetsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/organisations_helper.rb: -------------------------------------------------------------------------------- 1 | module OrganisationsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/assessment_answers_helper.rb: -------------------------------------------------------------------------------- 1 | module AssessmentAnswersHelper 2 | end 3 | -------------------------------------------------------------------------------- /survey/survey.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodi/pathway/HEAD/survey/survey.xls -------------------------------------------------------------------------------- /app/models/country_scores_datum.rb: -------------------------------------------------------------------------------- 1 | class CountryScoresDatum < ActiveRecord::Base 2 | 3 | end -------------------------------------------------------------------------------- /app/assets/images/cc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodi/pathway/HEAD/app/assets/images/cc.png -------------------------------------------------------------------------------- /spec/lib/test-survey.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodi/pathway/HEAD/spec/lib/test-survey.xls -------------------------------------------------------------------------------- /app/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodi/pathway/HEAD/app/assets/images/favicon.ico -------------------------------------------------------------------------------- /app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= yield %> 4 | 5 | 6 | -------------------------------------------------------------------------------- /spec/support/factory_girl.rb: -------------------------------------------------------------------------------- 1 | RSpec.configure do |config| 2 | config.include FactoryGirl::Syntax::Methods 3 | end -------------------------------------------------------------------------------- /app/assets/images/logo-footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theodi/pathway/HEAD/app/assets/images/logo-footer.png -------------------------------------------------------------------------------- /spec/controllers/user_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe UserController do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | This PR fixes # 2 | 3 | Changes proposed in this pull request: 4 | 5 | - 6 | - 7 | - 8 | -------------------------------------------------------------------------------- /spec/controllers/targets_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe TargetsController do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | 3 | def index 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/assessments_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe AssessmentsController do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/assessment_answers_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe AssessmentAnswersController do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/organisation_admins_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe OrganisationAdminsController do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: "from@example.com" 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /features/step_definitions/admin_steps.rb: -------------------------------------------------------------------------------- 1 | Then(/^I should see a list of users$/) do 2 | pending # express the regexp above with the code you wish you had 3 | end -------------------------------------------------------------------------------- /spec/factories/questionnaires.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :questionnaire do 3 | version 1 4 | notes "the first one" 5 | end 6 | 7 | end 8 | -------------------------------------------------------------------------------- /spec/factories/improvements.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :improvement do 3 | code "I1" 4 | answer_id 1 5 | notes "MyString" 6 | end 7 | 8 | end 9 | -------------------------------------------------------------------------------- /test/models/user_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class UserTest < ActiveSupport::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /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/20150320160725_add_name_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddNameToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :name, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | sudo: false 3 | cache: bundler 4 | rvm: 5 | - 2.4.1 6 | env: 7 | global: 8 | - GOOGLE_ANALYTICS_TRACKER=UA-XXXX-Y 9 | - HEATMAP_THRESHOLD=1 -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.action_dispatch.cookies_serializer = :json 4 | -------------------------------------------------------------------------------- /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: '_ODMAT_session' 4 | -------------------------------------------------------------------------------- /spec/factories/links.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :link do 3 | assessment_answer nil 4 | link "http://www.example.com" 5 | text "An example link" 6 | end 7 | end -------------------------------------------------------------------------------- /spec/factories/scores.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :score do 3 | assessment_id 1 4 | activity_id 1 5 | score 3 6 | target 4 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /spec/factories/activities.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :activity do 3 | name "data-governance" 4 | title "Data Governance" 5 | dimension_id 1 6 | end 7 | 8 | end 9 | -------------------------------------------------------------------------------- /spec/views/assessments/index.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "assessments/index.html.erb" do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20150311123734_change_notes_column_type.rb: -------------------------------------------------------------------------------- 1 | class ChangeNotesColumnType < ActiveRecord::Migration 2 | def change 3 | change_column :assessments, :notes, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/country_importer.rb: -------------------------------------------------------------------------------- 1 | class CountryImporter 2 | def self.populate(results) 3 | results.each { |result| Country.create(name: result['Name'], code: result['Code'].downcase) } 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /test/controllers/home_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class HomeControllerTest < ActionController::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /app/models/link.rb: -------------------------------------------------------------------------------- 1 | class Link < ActiveRecord::Base 2 | belongs_to :assessment_answer 3 | validates_format_of :link, :with => URI::regexp(%w(http https)), message: "url is an invalid format" 4 | end 5 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path("../spring", __FILE__) 4 | rescue LoadError 5 | end 6 | require_relative '../config/boot' 7 | require 'rake' 8 | Rake.application.run 9 | -------------------------------------------------------------------------------- /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/20150306133403_add_organisation_id_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddOrganisationIdToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :organisation_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/views/user/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %>Edit Account<% end %> 2 | 3 | <%= form_for @user, :url => user_path do |f| %> 4 | <%= render :partial => 'form', :locals => { :f => f } %> 5 | <% end %> -------------------------------------------------------------------------------- /app/views/user/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %>New Account<% end %> 2 | 3 | <%= form_for @user, :url => user_index_path do |f| %> 4 | <%= render :partial => 'form', :locals => { :f => f } %> 5 | <% end %> -------------------------------------------------------------------------------- /spec/factories/dimensions.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :dimension do 3 | name "data-management-processes" 4 | title "Data Management Processes" 5 | questionnaire_id 1 6 | end 7 | 8 | end 9 | -------------------------------------------------------------------------------- /spec/factories/questions.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :question do 3 | code "q1" 4 | activity_id 1 5 | text "Have you published any open data?" 6 | notes "" 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /app/models/improvement.rb: -------------------------------------------------------------------------------- 1 | class Improvement < ActiveRecord::Base 2 | belongs_to :answer 3 | 4 | validates :code, presence: true 5 | validates :code, uniqueness: true 6 | validates :notes, presence: true 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20161104002323_add_country_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddCountryToUser < ActiveRecord::Migration 2 | def change 3 | add_reference :users, :country, index: true 4 | add_foreign_key :users, :countries 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20160926132807_create_country_scores.rb: -------------------------------------------------------------------------------- 1 | class CreateCountryScores < ActiveRecord::Migration 2 | def change 3 | create_table :country_scores do |t| 4 | 5 | t.timestamps null: false 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/assets/javascripts/targets.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/helpers/assessments_helper.rb: -------------------------------------------------------------------------------- 1 | module AssessmentsHelper 2 | 3 | def progress_bar(percent=0) 4 | content_tag :div, "", id: "progress-bar" do 5 | content_tag :div, "", style: "width:#{percent}%;" 6 | end 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path("../spring", __FILE__) 4 | rescue LoadError 5 | end 6 | APP_PATH = File.expand_path('../../config/application', __FILE__) 7 | require_relative '../config/boot' 8 | require 'rails/commands' 9 | -------------------------------------------------------------------------------- /db/migrate/20161216082751_add_country_to_country_score.rb: -------------------------------------------------------------------------------- 1 | class AddCountryToCountryScore < ActiveRecord::Migration 2 | def change 3 | add_reference :country_scores, :country, index: true 4 | add_foreign_key :country_scores, :countries 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20150224155616_add_admin_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddAdminToUsers < ActiveRecord::Migration 2 | def up 3 | add_column :users, :admin, :boolean, :default => false 4 | end 5 | 6 | def down 7 | remove_column :users, :admin 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20161216082828_add_activity_to_country_score.rb: -------------------------------------------------------------------------------- 1 | class AddActivityToCountryScore < ActiveRecord::Migration 2 | def change 3 | add_reference :country_scores, :activity, index: true 4 | add_foreign_key :country_scores, :activities 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/controllers/admin_controller.rb: -------------------------------------------------------------------------------- 1 | class AdminController < ApplicationController 2 | before_filter :authenticate_user! 3 | 4 | def index 5 | authorize! :manage, :users 6 | @users = User.all.order(created_at: :asc) 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /app/helpers/user_helper.rb: -------------------------------------------------------------------------------- 1 | module UserHelper 2 | def resource_name 3 | :user 4 | end 5 | 6 | def resource 7 | @resource ||= User.new 8 | end 9 | 10 | def devise_mapping 11 | @devise_mapping ||= Devise.mappings[:user] 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/models/country_score.rb: -------------------------------------------------------------------------------- 1 | class CountryScore < ActiveRecord::Base 2 | belongs_to :country 3 | belongs_to :activity 4 | 5 | def completed_assessments 6 | return self.initial + self.defined + self.repeatable + self.managed + self.optimising 7 | end 8 | 9 | end -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /spec/factories/organisation_scores.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :organisation_score do 3 | organisation_id 1 4 | activity_id 1 5 | initial 1 6 | repeatable 1 7 | defined 1 8 | managed 1 9 | optimising 1 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /spec/lib/organisations_rake_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'rake' 3 | 4 | describe 'organisations.rake' do 5 | 6 | before { ODMAT::Application.load_tasks } 7 | it { expect { Rake::Task['organisations:import'].invoke }.not_to raise_exception } 8 | 9 | end 10 | -------------------------------------------------------------------------------- /app/views/assessments/_score_label.html.erb: -------------------------------------------------------------------------------- 1 |

Score 6 | 7 |

-------------------------------------------------------------------------------- /db/migrate/20150311170825_add_assessment_id_to_assessment_answers.rb: -------------------------------------------------------------------------------- 1 | class AddAssessmentIdToAssessmentAnswers < ActiveRecord::Migration 2 | def change 3 | add_reference :assessment_answers, :assessment, index: true 4 | add_foreign_key :assessment_answers, :assessments 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/models/organisation_score.rb: -------------------------------------------------------------------------------- 1 | class OrganisationScore < ActiveRecord::Base 2 | belongs_to :organisation 3 | belongs_to :activity 4 | 5 | def completed_assessments 6 | return self.initial + self.defined + self.repeatable + self.managed + self.optimising 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /app/views/assessments/_next_goal_label.html.erb: -------------------------------------------------------------------------------- 1 |

Goal

-------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | 7 | ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| 8 | html_tag.html_safe 9 | end 10 | -------------------------------------------------------------------------------- /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 | 8 | task :default => [:spec, :cucumber] -------------------------------------------------------------------------------- /app/controllers/countries_controller.rb: -------------------------------------------------------------------------------- 1 | class CountriesController < ApplicationController 2 | respond_to :json 3 | 4 | def index 5 | query = params[:q].to_s 6 | 7 | @countries = Country.where("LOWER(name) LIKE (?)", "%#{query.downcase}%") 8 | respond_with @countries 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /app/models/ability.rb: -------------------------------------------------------------------------------- 1 | class Ability 2 | include CanCan::Ability 3 | 4 | def initialize(user, token=nil) 5 | if user.present? 6 | can :manage, :all if user.admin? 7 | can :manage, Assessment, :user_id => user.id 8 | end 9 | can :read, Assessment, token: token 10 | end 11 | 12 | end -------------------------------------------------------------------------------- /app/views/assessments/_activity_label.html.erb: -------------------------------------------------------------------------------- 1 |

Activity 6 | 7 |

-------------------------------------------------------------------------------- /db/migrate/20150309071504_create_dimensions.rb: -------------------------------------------------------------------------------- 1 | class CreateDimensions < ActiveRecord::Migration 2 | def change 3 | create_table :dimensions do |t| 4 | t.string :name 5 | t.string :title 6 | t.integer :questionnaire_id 7 | 8 | t.timestamps null: false 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/views/shared/_errors.html.erb: -------------------------------------------------------------------------------- 1 | <% if object.errors.any? %> 2 |
3 |

The following problems were found:

4 | 9 |
10 | <% end %> 11 | -------------------------------------------------------------------------------- /db/migrate/20150325123402_create_improvements.rb: -------------------------------------------------------------------------------- 1 | class CreateImprovements < ActiveRecord::Migration 2 | def change 3 | create_table :improvements do |t| 4 | t.string :code 5 | t.references :answer, index: true 6 | t.text :notes 7 | 8 | t.timestamps null: false 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20150318112628_create_scores.rb: -------------------------------------------------------------------------------- 1 | class CreateScores < ActiveRecord::Migration 2 | def change 3 | create_table :scores do |t| 4 | t.integer :assessment_id 5 | t.integer :activity_id 6 | t.integer :score 7 | t.integer :target 8 | 9 | t.timestamps null: false 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /db/migrate/20150305150652_create_organisations.rb: -------------------------------------------------------------------------------- 1 | class CreateOrganisations < ActiveRecord::Migration 2 | def change 3 | create_table :organisations do |t| 4 | t.string :name 5 | t.string :title 6 | t.string :dgu_id 7 | t.integer :parent 8 | 9 | t.timestamps null: false 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/controllers/organisations_controller.rb: -------------------------------------------------------------------------------- 1 | class OrganisationsController < ApplicationController 2 | 3 | respond_to :json 4 | 5 | def index 6 | query = params[:q].to_s.gsub(" ", "-") 7 | 8 | @organisations = Organisation.dgu.where("name LIKE (?)", "%#{query.downcase}%") 9 | respond_with @organisations 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /app/views/assessments/_theme_label.html.erb: -------------------------------------------------------------------------------- 1 |

Theme 6 | 7 |

8 | 9 | -------------------------------------------------------------------------------- /db/migrate/20150309071529_create_activities.rb: -------------------------------------------------------------------------------- 1 | class CreateActivities < ActiveRecord::Migration 2 | def change 3 | create_table :activities do |t| 4 | t.string :name 5 | t.string :title 6 | t.integer :dimension_id 7 | t.integer :questionnaire_id 8 | 9 | t.timestamps null: false 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/views/organisation_admin_mailer/help_request.text.erb: -------------------------------------------------------------------------------- 1 | <%= @user.name %>, 2 | 3 | Using the email address <%= @requester_email %>, a user tried to register as the admin of <%= @organisation.title %>. Since you are the current admin of this organisation they were not able to register. 4 | 5 | Message from <%= @requester_email %>: 6 | 7 | <%= @message %> 8 | -------------------------------------------------------------------------------- /db/migrate/20150309071413_create_questionnaires.rb: -------------------------------------------------------------------------------- 1 | class CreateQuestionnaires < ActiveRecord::Migration 2 | def change 3 | create_table :questionnaires do |t| 4 | t.integer :version 5 | t.string :notes 6 | 7 | t.timestamps null: false 8 | end 9 | add_index(:questionnaires, :version, unique: true) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /script/cucumber: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first 4 | if vendored_cucumber_bin 5 | load File.expand_path(vendored_cucumber_bin) 6 | else 7 | require 'rubygems' unless ENV['NO_RUBYGEMS'] 8 | require 'cucumber' 9 | load Cucumber::BINARY 10 | end 11 | -------------------------------------------------------------------------------- /app/controllers/base_admin_controller.rb: -------------------------------------------------------------------------------- 1 | class BaseAdminController < ApplicationController 2 | before_filter :authenticate_user!, :ensure_admin! 3 | 4 | private 5 | 6 | def ensure_admin! 7 | unless current_user.admin? 8 | sign_out current_user 9 | redirect_to root_path 10 | return false 11 | end 12 | end 13 | 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20150311124917_create_links.rb: -------------------------------------------------------------------------------- 1 | class CreateLinks < ActiveRecord::Migration 2 | def change 3 | create_table :links do |t| 4 | t.references :assessment_answer, index: true 5 | t.string :link 6 | t.string :text 7 | 8 | t.timestamps null: false 9 | end 10 | add_foreign_key :links, :assessment_answers 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20161218004436_create_country_scores_data.rb: -------------------------------------------------------------------------------- 1 | class CreateCountryScoresData < ActiveRecord::Migration 2 | def change 3 | create_table :country_scores_data do |t| 4 | t.string :name 5 | t.string :data 6 | 7 | t.timestamps null: false 8 | end 9 | add_index :country_scores_data, :name, unique: true 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20161104002256_create_countries.rb: -------------------------------------------------------------------------------- 1 | class CreateCountries < ActiveRecord::Migration 2 | def change 3 | create_table :countries do |t| 4 | t.string :name 5 | t.string :code 6 | 7 | t.timestamps null: false 8 | end 9 | add_index :countries, :name, unique: true 10 | add_index :countries, :code, unique: true 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/views/organisation_admin_mailer/help_request.html.erb: -------------------------------------------------------------------------------- 1 |

<%= @user.name %>,

2 | 3 |

Using the email address <%= @requester_email %>, a user tried to register as the admin of <%= @organisation.title %>. Since you are the current admin of this organisation they were not able to register.

4 | 5 |

Message from <%= @requester_email %>:

6 | 7 |

<%= @message %>

8 | -------------------------------------------------------------------------------- /spec/models/link_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Link do 4 | 5 | it "should contain a valid url" do 6 | link = FactoryGirl.build(:link) 7 | expect(link.valid?).to eq(true) 8 | end 9 | 10 | it "should not contain a valid url" do 11 | link = FactoryGirl.build(:link, link: "blah") 12 | expect(link.valid?).to eq(false) 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20150309071639_create_questions.rb: -------------------------------------------------------------------------------- 1 | class CreateQuestions < ActiveRecord::Migration 2 | def change 3 | create_table :questions do |t| 4 | t.string :code 5 | t.integer :activity_id 6 | t.integer :questionnaire_id 7 | t.string :text 8 | t.string :notes 9 | t.references :dependency 10 | 11 | t.timestamps null: false 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20161218043408_add_stats_to_country_scores.rb: -------------------------------------------------------------------------------- 1 | class AddStatsToCountryScores < ActiveRecord::Migration 2 | def change 3 | add_column :country_scores, :initial, :integer 4 | add_column :country_scores, :repeatable, :integer 5 | add_column :country_scores, :defined, :integer 6 | add_column :country_scores, :managed, :integer 7 | add_column :country_scores, :optimising, :integer 8 | end 9 | end -------------------------------------------------------------------------------- /spec/factories/assessment_answers.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | 3 | factory :assessment_answer do 4 | question_id 1 5 | answer 6 | assessment_id 1 7 | notes "MyText" 8 | end 9 | 10 | factory :assessment_answer2, class: AssessmentAnswer do 11 | question_id 1 12 | association :answer, factory: :negative_answer 13 | assessment_id 1 14 | notes "MyText" 15 | end 16 | 17 | end 18 | -------------------------------------------------------------------------------- /db/migrate/20150504121056_add_token_to_assessment.rb: -------------------------------------------------------------------------------- 1 | class AddTokenToAssessment < ActiveRecord::Migration 2 | def up 3 | add_column :assessments, :token, :string 4 | Assessment.where("completion_date is not null").each do |assessment| 5 | assessment.generate_share_token 6 | assessment.save 7 | end 8 | end 9 | 10 | def down 11 | remove_column :assessments, :token 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /test/fixtures/users.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /features/step_definitions/statistics_steps.rb: -------------------------------------------------------------------------------- 1 | Given(/^the statistics have been generated$/) do 2 | Organisation.create!(title: "All Organisations") 3 | Organisation.create!(title: "All data.gov.uk organisations") 4 | 5 | generator = StatisticsGenerator.new 6 | generator.generate_all 7 | end 8 | 9 | Given /the heatmap threshold is (.+)/ do |t| 10 | ODMAT::Application::HEATMAP_THRESHOLD = Integer.new(t) 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20150309071711_create_answers.rb: -------------------------------------------------------------------------------- 1 | class CreateAnswers < ActiveRecord::Migration 2 | def change 3 | create_table :answers do |t| 4 | t.string :code 5 | t.integer :question_id 6 | t.integer :questionnaire_id 7 | t.string :text 8 | t.string :notes 9 | t.boolean :positive, :default => false 10 | t.integer :score 11 | 12 | t.timestamps null: false 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20150311110709_create_assessments.rb: -------------------------------------------------------------------------------- 1 | class CreateAssessments < ActiveRecord::Migration 2 | def change 3 | create_table :assessments do |t| 4 | t.references :user, index: true 5 | t.datetime :start_date 6 | t.datetime :completion_date 7 | t.string :title 8 | t.string :notes 9 | 10 | t.timestamps null: false 11 | end 12 | add_foreign_key :assessments, :users 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /bin/rspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rspec' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rspec-core', 'rspec') 17 | -------------------------------------------------------------------------------- /app/models/questionnaire.rb: -------------------------------------------------------------------------------- 1 | class Questionnaire < ActiveRecord::Base 2 | has_many :dimensions 3 | has_many :activities 4 | 5 | validates :version, presence: true 6 | 7 | #which is the current questionnaire that users should be answering? 8 | #TODO: improve this to make it easier to switch which questionaire is "live" 9 | def self.current 10 | return Questionnaire.order("version desc").first 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /bin/autospec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'autospec' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rspec-core', 'autospec') 17 | -------------------------------------------------------------------------------- /bin/cucumber: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'cucumber' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('cucumber', 'cucumber') 17 | -------------------------------------------------------------------------------- /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/20150311121727_create_assessment_answers.rb: -------------------------------------------------------------------------------- 1 | class CreateAssessmentAnswers < ActiveRecord::Migration 2 | def change 3 | create_table :assessment_answers do |t| 4 | t.references :question, index: true 5 | t.references :answer, index: true 6 | t.text :notes 7 | 8 | t.timestamps null: false 9 | end 10 | add_foreign_key :assessment_answers, :questions 11 | add_foreign_key :assessment_answers, :answers 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/organisation_importer.rb: -------------------------------------------------------------------------------- 1 | class OrganisationImporter 2 | def self.populate(results) 3 | results.each { |result| create_organisation(result, nil) } 4 | end 5 | 6 | def self.create_organisation(result, parent) 7 | org = Organisation.create(parent: parent, name: result['name'], title: result['title'], dgu_id: result['id']) 8 | parent = org.id if parent.nil? 9 | result['children'].each { |child| create_organisation(child, parent) } 10 | end 11 | end -------------------------------------------------------------------------------- /spec/controllers/admin_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe AdminController do 4 | 5 | it "should allow an admin to view admin pages" do 6 | sign_in FactoryGirl.create(:admin) 7 | get "index" 8 | response.should be_success 9 | end 10 | 11 | it "should not allow other users to view admin pages" do 12 | sign_in FactoryGirl.create(:user) 13 | get "index" 14 | response.code.should eql("302") 15 | end 16 | 17 | end -------------------------------------------------------------------------------- /app/models/dimension.rb: -------------------------------------------------------------------------------- 1 | class Dimension < ActiveRecord::Base 2 | has_many :activities 3 | belongs_to :questionnaire 4 | 5 | validates :title, presence: true 6 | validates :name, presence: true 7 | validates :name, uniqueness: {scope: :questionnaire_id, message: "dimension name should be unique within questionnaire" } 8 | 9 | def questions 10 | Question.joins(:activity).where(activities: { dimension_id: self.id }) 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/views/devise/passwords/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %>Change your password<% end %> 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 | <%= render "devise/shared/password", f: f %> 8 | 9 |
10 | <%= f.submit "Change my password", class: "btn orange" %> 11 |
12 | <% end %> 13 | 14 | -------------------------------------------------------------------------------- /config/cucumber.yml: -------------------------------------------------------------------------------- 1 | <% 2 | rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : "" 3 | rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}" 4 | std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip" 5 | %> 6 | default: <%= std_opts %> features 7 | wip: --tags @wip:3 --wip features 8 | rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip 9 | -------------------------------------------------------------------------------- /app/mailers/organisation_admin_mailer.rb: -------------------------------------------------------------------------------- 1 | class OrganisationAdminMailer < ApplicationMailer 2 | 3 | default from: 'notifications@example.com' 4 | 5 | def help_request(user, organisation, message, requester_email) 6 | @user = user 7 | @organisation = organisation 8 | @message = message 9 | @requester_email = requester_email 10 | 11 | mail(to: @user.email, subject: "A user would like to help with #{@organisation.title}'s Open Data Maturity") 12 | end 13 | 14 | end 15 | -------------------------------------------------------------------------------- /app/views/devise/mailer/reset_password_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.name %>,

2 | 3 |

We received the request to reset your password for your account for Open Data Pathway. Click the link below to reset your password:

4 | 5 |

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

6 | 7 |

If you have not requested the password reset then don't worry - you can ignore this email. Alternatively you can contact maturity@theodi.org.

8 | -------------------------------------------------------------------------------- /spec/helpers/targets_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the TargetsHelper. For example: 5 | # 6 | # describe TargetsHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # expect(helper.concat_strings("this","that")).to eq("this that") 10 | # end 11 | # end 12 | # end 13 | describe TargetsHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /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 | if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m) 11 | Gem.paths = { "GEM_PATH" => Bundler.bundle_path.to_s } 12 | gem "spring", match[1] 13 | require "spring/binstub" 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /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 | user = User.find_or_create_by!(email: ENV["ADMIN_EMAIL"] ) do |user| 5 | user.password = ENV["ADMIN_PASSWORD"] 6 | user.password_confirmation = ENV["ADMIN_PASSWORD"] 7 | user.terms_of_service = "1" 8 | user.name = "Pathway Administrator" 9 | user.admin = true 10 | end 11 | user.save! -------------------------------------------------------------------------------- /spec/helpers/assessments_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the AssessmentsHelper. For example: 5 | # 6 | # describe AssessmentsHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # expect(helper.concat_strings("this","that")).to eq("this that") 10 | # end 11 | # end 12 | # end 13 | describe AssessmentsHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /spec/helpers/organisations_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the OrganisationsHelper. For example: 5 | # 6 | # describe OrganisationsHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # expect(helper.concat_strings("this","that")).to eq("this that") 10 | # end 11 | # end 12 | # end 13 | describe OrganisationsHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /app/views/pages/contact.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %>Get in touch<% end %> 2 | 3 |

4 | This website is a beta version so its content and features might change. 5 |

6 | 7 |

8 | Please complete our user feedback survey to share your experience with using this tool. 9 |

10 | 11 |

12 | Please report any bugs or mistakes on GitHub or email us at 13 | maturity@theodi.org 14 |

15 | -------------------------------------------------------------------------------- /spec/helpers/assessment_answers_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the AssessmentAnswersHelper. For example: 5 | # 6 | # describe AssessmentAnswersHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # expect(helper.concat_strings("this","that")).to eq("this that") 10 | # end 11 | # end 12 | # end 13 | describe AssessmentAnswersHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 11 | # Rails.application.config.assets.precompile += %w( search.js ) 12 | -------------------------------------------------------------------------------- /app/views/user/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= devise_error_messages! %> 2 | 3 |

<%= f.label :name %>
4 | <%= f.text_field :name %>

5 | 6 |

<%= f.label :email %>
7 | <%= f.text_field :email %>

8 | 9 |

<%= f.label :password %>
10 | <%= f.password_field :password %>

11 | 12 |

<%= f.label :password_confirmation %>
13 | <%= f.password_field :password_confirmation %>

14 | 15 | <% if can? :manage, @users %> 16 |

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

17 | <% end %> 18 | 19 |

<%= f.submit "Submit" %>

-------------------------------------------------------------------------------- /app/models/score.rb: -------------------------------------------------------------------------------- 1 | class Score < ActiveRecord::Base 2 | belongs_to :assessment 3 | belongs_to :activity 4 | 5 | validates :score, :inclusion => {:in => [1,2,3,4,5], allow_blank: false, message: "maturity scores must be between 1-5"} 6 | validates :target, :inclusion => {:in => [1,2,3,4,5], allow_blank: true, message: "maturity targets must be between 1-5"} 7 | 8 | def target 9 | val = self.read_attribute(:target) 10 | if val.blank? 11 | self.score.eql?(5) ? 5 : self.score+1 12 | else 13 | val 14 | end 15 | end 16 | 17 | end 18 | -------------------------------------------------------------------------------- /app/views/devise/unlocks/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %>Resend unlock instructions<% end %> 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", class: "btn green" %> 13 |
14 | <% end %> 15 | 16 | <%= render "devise/shared/links" %> 17 | -------------------------------------------------------------------------------- /features/admin.feature: -------------------------------------------------------------------------------- 1 | Feature: Administrator Functionality 2 | 3 | Background: 4 | Given I am logged in as an administrator 5 | 6 | Scenario: Viewing the home page as a user 7 | When I go to the homepage 8 | Then I should see a link called "Admin" to "/admin" 9 | 10 | Scenario: Viewing the admin page 11 | Given there is a registered user 12 | When I go to the homepage 13 | And I click on "Admin" 14 | Then I should see "Registered Users" 15 | And I should see "user@example.org" 16 | And I should see "admin@example.org" 17 | -------------------------------------------------------------------------------- /lib/tasks/countries.rake: -------------------------------------------------------------------------------- 1 | require 'country_importer' 2 | require 'net/http' 3 | 4 | namespace :countries do 5 | 6 | desc "Imports countries from from a source which keeps up to date with ISO 3166-1" 7 | task :import => :environment do 8 | url = URI.parse("https://raw.githubusercontent.com/datasets/country-list/master/data.csv") 9 | response = Net::HTTP.get(url) 10 | results = CSV.parse(response.force_encoding("UTF-8"), :headers => true) 11 | puts "#{results.length} countries found" 12 | CountryImporter.populate(results) 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /app/views/organisation_admins/new_contact.html.erb: -------------------------------------------------------------------------------- 1 |

Contact organisation admin

2 |

Somebody is already registered as an admin for that organisation

3 |

You can contact them by filling in the following form

4 | 5 | <%= form_tag contact_organisation_admin_path(@organisation.id), method: :post do %> 6 |

<%= label_tag :email, "Your email" %>
7 | <%= email_field_tag :email, @email %> 8 |

9 |

<%= label_tag :message, "Your message to the user" %>

10 |

11 | <%= text_area_tag :message %>

12 | <%= submit_tag "Submit" %> 13 | <% end %> -------------------------------------------------------------------------------- /app/models/answer.rb: -------------------------------------------------------------------------------- 1 | class Answer < ActiveRecord::Base 2 | belongs_to :question 3 | belongs_to :questionnaire 4 | has_many :improvements, dependent: :destroy 5 | 6 | validates :text, presence: true 7 | validates :code, presence: true 8 | validates :code, uniqueness: {scope: :questionnaire_id, message: "answer code should be unique within questionnaire" } 9 | validates :score, :presence => true, if: Proc.new { |a| !a.positive? } 10 | validates :score, :inclusion => {:in => [1,2,3,4,5], allow_blank: true, message: "maturity scores must be between 1-5"} 11 | end 12 | -------------------------------------------------------------------------------- /app/views/devise/confirmations/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %>Resend confirmation instructions<% end %> 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 %> 9 |
10 | 11 |
12 | <%= f.submit "Resend confirmation instructions", class: "btn orange" %> 13 |
14 | <% end %> 15 | 16 | <%= render "devise/shared/links" %> 17 | -------------------------------------------------------------------------------- /spec/mailers/organisation_admin_mailer_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe OrganisationAdminMailer do 4 | 5 | it "sends an email" do 6 | organisation = FactoryGirl.create(:organisation) 7 | user = FactoryGirl.create(:user, organisation_id: organisation.id) 8 | message = "Can you get in touch?" 9 | requester_email = "arequester@example.com" 10 | help_email = OrganisationAdminMailer.help_request(user, organisation, message, requester_email) 11 | expect { help_email.deliver }.to change { ActionMailer::Base.deliveries.count }.by(1) 12 | end 13 | 14 | end 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] if respond_to?(:wrap_parameters) 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 | -------------------------------------------------------------------------------- /app/views/assessments/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %> 2 | Edit assessment 3 | <% end %> 4 | <% content_for :breadcrumb do %> 5 | <%= breadcrumb("Edit assessment") %> 6 | <% end %> 7 | 8 |
9 | <%= form_for @assessment do |f| %> 10 | <%= render "shared/errors", object: f.object %> 11 |

<%= f.label :title, "What would you like to call the assessment?" %>

12 | <%= f.text_field :title %> 13 | 14 |

<%= f.label :notes, "Tell us why you are taking this assessment and any other relevant information" %>

15 | <%= f.text_area :notes %> 16 | 17 | <%= f.submit 'Save' %> 18 | <% end %> -------------------------------------------------------------------------------- /app/views/devise/passwords/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %>Forgot your password?<% end %> 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, "data-validation": "email", "data-validation-error-msg": t(:enter_email), style: "width:40%;" %> 9 |
10 | 11 |
12 | <%= f.submit "Send me reset password instructions", class: "btn green" %> 13 |
14 | <% end %> 15 | 16 | -------------------------------------------------------------------------------- /app/views/links/_link_fields.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 | <%= field_set_tag "" do %> 4 | <%= f.hidden_field :_destroy %> 5 | 6 | <%= f.label :text, title: "The name of the link, e.g. Our Open Data Strategy" %> 7 | <%= f.text_field :text, placeholder: "Link text e.g. Open Data Strategy", class: "form-control" %>
8 | 9 | <%= f.label :link, title: "The URL for the link, e.g. http://example.org" %> 10 | <%= f.text_field :link, placeholder: "http://example.org", class: "form-control" %> 11 | 12 | <%= link_to 'Remove link', '#', class: "btn delete_association" %> 13 | 14 | <% end %> 15 | 16 |
-------------------------------------------------------------------------------- /spec/models/score_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Score do 4 | describe "creation" do 5 | 6 | it "should allow only legal scores" do 7 | score = FactoryGirl.build(:score, score: 6) 8 | score.should_not be_valid 9 | 10 | score = FactoryGirl.build(:score, score: 0) 11 | score.should_not be_valid 12 | end 13 | 14 | it "should allow only legal targets" do 15 | score = FactoryGirl.build(:score, target: 6) 16 | score.should_not be_valid 17 | 18 | score = FactoryGirl.build(:score, target: 0) 19 | score.should_not be_valid 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/controllers/organisation_admins_controller.rb: -------------------------------------------------------------------------------- 1 | class OrganisationAdminsController < ApplicationController 2 | 3 | def new_contact 4 | @organisation = Organisation.find(params[:organisation_id]) 5 | @email = params[:email] 6 | end 7 | 8 | def contact 9 | @organisation = Organisation.find(params[:organisation_id]) 10 | user = User.where(organisation_id: @organisation.id).first 11 | help_email = OrganisationAdminMailer.help_request(user, @organisation, params[:message], params[:email]) 12 | help_email.deliver 13 | redirect_to new_user_registration_path, notice: "A message was sent to the admin of #{@organisation.title}" 14 | end 15 | 16 | end -------------------------------------------------------------------------------- /app/views/assessments/_first_assessment.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |

You haven't started any assessment yet

4 | 5 |
6 |
7 | <%= link_to begin_assessment_path, class: "btn green next" do %> 8 | Start your first assessment 9 | <% end %> 10 |
11 |
12 | 20 |
21 |
-------------------------------------------------------------------------------- /spec/factories/countries.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :country do 3 | name "United Kingdom" 4 | code "gb" 5 | end 6 | 7 | factory :country1, class: Country do 8 | name "United States" 9 | code "us" 10 | end 11 | 12 | factory :country2, class: Country do 13 | name "Australia" 14 | code "au" 15 | end 16 | 17 | factory :country3, class: Country do 18 | name "Uruguay" 19 | code "uy" 20 | end 21 | 22 | factory :country4, class: Country do 23 | name "United Arab Emirates" 24 | code "ae" 25 | end 26 | 27 | factory :country5, class: Country do 28 | name "New Zealand" 29 | code "nz" 30 | end 31 | 32 | end 33 | -------------------------------------------------------------------------------- /features/step_definitions/register_steps.rb: -------------------------------------------------------------------------------- 1 | When(/^I fill in Associated organisation with "([^"]*)"$/) do |value| 2 | hidden_field = find :xpath, "//input[@id='user_associated_organisation']", visible: false 3 | hidden_field.set value 4 | end 5 | 6 | When(/^I fill in Associated country with "([^"]*)"$/) do |value| 7 | hidden_field = find :xpath, "//input[@id='user_associated_country']", visible: false 8 | user = FactoryGirl.build(:country) 9 | user.save 10 | hidden_field.set value 11 | end 12 | 13 | Given(/^a user is associated with an organisation named "(.*?)"$/) do |org| 14 | user = FactoryGirl.build(:user) 15 | user.associated_organisation = org 16 | user.save 17 | end 18 | -------------------------------------------------------------------------------- /lib/tasks/statistics.rake: -------------------------------------------------------------------------------- 1 | require 'statistics_generator' 2 | 3 | namespace :statistics do 4 | 5 | desc "Generates organisation scores for heatmap page" 6 | task :generate => :environment do 7 | generator = StatisticsGenerator.new 8 | 9 | puts "Generating all orgs" 10 | generator.generate_stats_for_all_organisations 11 | 12 | puts "Generating d.g.u orgs" 13 | generator.generate_stats_for_dgu_organisations 14 | 15 | puts "Generating all parent groups" 16 | generator.generate_stats_for_dgu_groups 17 | 18 | puts "Generating all countries orgs" 19 | generator.generate_stats_for_all_countries 20 | 21 | puts "Done" 22 | end 23 | 24 | end 25 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /app/views/assessments/_information_tab.html.erb: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |

Assessor:<%= assessment.user.name.present? ? assessment.user.name : assessment.user.email %>

5 |

Completed on <%= pretty_date(assessment.completion_date) %>

6 |

Started on <%= pretty_date(@assessment.start_date) %>

7 |

<%= assessment.notes %>

8 |
9 |
10 | 11 | -------------------------------------------------------------------------------- /app/controllers/targets_controller.rb: -------------------------------------------------------------------------------- 1 | class TargetsController < ApplicationController 2 | 3 | def edit 4 | @assessment = Assessment.find(params[:assessment_id]) 5 | authorize! :update, @assessment 6 | @dimensions = Questionnaire.current.dimensions 7 | @scores = {} 8 | @assessment.scores.each { |s| @scores.merge!(s.activity_id => s) } 9 | end 10 | 11 | def update 12 | @assessment = Assessment.find(params[:assessment_id]) 13 | authorize! :update, @assessment 14 | @dimensions = Questionnaire.current.dimensions 15 | if @assessment.update_targets(params[:targets]) 16 | redirect_to assessments_path, notice: "Successfully saved goals" 17 | else 18 | render 'edit' 19 | end 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /app/helpers/devise_helper.rb: -------------------------------------------------------------------------------- 1 | module DeviseHelper 2 | def devise_error_messages! 3 | return "" if resource.errors.empty? 4 | 5 | messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join 6 | sentence = I18n.t("errors.messages.not_saved", 7 | :count => resource.errors.count, 8 | :resource => resource.class.model_name.human.downcase) 9 | 10 | html = <<-HTML 11 |
12 |

Oops - please try again

13 |
14 |
15 | HTML 16 | 17 | html.html_safe 18 | end 19 | 20 | def devise_error_messages? 21 | resource.errors.empty? ? false : true 22 | end 23 | 24 | end -------------------------------------------------------------------------------- /app/assets/stylesheets/colours.scss: -------------------------------------------------------------------------------- 1 | $odiBlue: #00b7ff; 2 | $odiBlueDark: #2254f4; 3 | $odiBlueLight: #08def9; 4 | $odiOrange: #ff6700; 5 | $odiYellow: #F9BC26; 6 | $odiRed: #d60303; 7 | $odiGrey: #888888; 8 | $odiGreyDark: #333333; 9 | $odiGreyLight: #BBBBBB; 10 | 11 | // Colour variables, primarily for home modules 12 | $odiColour1: #D60303; // red 13 | $odiColour2: $odiOrange; // orange 14 | $odiColour3: $odiYellow; // yellow 15 | $odiColour4: #67EF67; //light green 16 | $odiColour5: #0DBC37; // med green 17 | $odiColour6: #1dd3a7; // turquoise 18 | $odiColour7: $odiBlueDark; // dark blue 19 | $odiColour8: $odiBlue; 20 | $odiColour9: $odiBlueLight; // light blue 21 | $odiColour10: #ef3aab; // pink 22 | $odiColour11: #e6007c; // magenta 23 | $odiColour12: #b13198; // purple -------------------------------------------------------------------------------- /lib/tasks/questionnaire.rake: -------------------------------------------------------------------------------- 1 | require 'questionnaire_importer' 2 | 3 | namespace :questionnaire do 4 | 5 | desc "Imports questionnaire from survey.xls" 6 | task :import, [:version,:notes] => :environment do |task, args| 7 | args.with_defaults(:notes => "Questionnaire import #{Time.now.strftime("%d/%m/%Y %H:%M")}") 8 | config = File.join( __dir__, "..", "..", "survey", "survey.xls") 9 | QuestionnaireImporter.load(args.version.to_i, config, args.notes ) 10 | end 11 | 12 | desc "Updates questionnaire from survey.xls" 13 | task :update, [:version,:notes] => :environment do |task, args| 14 | config = File.join( __dir__, "..", "..", "survey", "survey.xls") 15 | QuestionnaireImporter.update(args.version.to_i, config ) 16 | end 17 | 18 | end -------------------------------------------------------------------------------- /app/models/question.rb: -------------------------------------------------------------------------------- 1 | class Question < ActiveRecord::Base 2 | has_many :answers, dependent: :destroy 3 | belongs_to :activity 4 | belongs_to :questionnaire 5 | 6 | has_many :dependents, class_name: "Question", 7 | foreign_key: "dependency_id" 8 | belongs_to :dependency, class_name: "Question" 9 | 10 | validates :text, presence: true 11 | validates :code, presence: true 12 | validates :code, uniqueness: {scope: :questionnaire_id, message: "question code should be unique within questionnaire" } 13 | 14 | def next 15 | Question.where(activity_id: activity_id).where("id > ?", id).first 16 | end 17 | 18 | def prev 19 | Question.where(activity_id: activity_id).where("id < ?", id).last 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /.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 | 7 | .env 8 | 9 | # Ignore bundler config. 10 | /.bundle 11 | 12 | # Ignore the default SQLite database. 13 | /db/*.sqlite3 14 | /db/*.sqlite3-journal 15 | 16 | # Ignore all logfiles and tempfiles. 17 | /log/* 18 | !/log/.keep 19 | /tmp 20 | 21 | *~ 22 | 23 | coverage 24 | 25 | # Eclipse stuff 26 | .buildpath 27 | .project 28 | 29 | # RubyMine project files 30 | .idea 31 | 32 | #OS stuff 33 | app/assets/images/Thumbs.db 34 | local_scripts/ 35 | *.iml 36 | -------------------------------------------------------------------------------- /db/migrate/20150506111100_create_organisation_scores.rb: -------------------------------------------------------------------------------- 1 | class CreateOrganisationScores < ActiveRecord::Migration 2 | def up 3 | Organisation.create!(title: "All Organisations") 4 | Organisation.create!(title: "All data.gov.uk organisations") 5 | 6 | create_table :organisation_scores do |t| 7 | t.integer :organisation_id 8 | t.integer :activity_id 9 | t.integer :initial 10 | t.integer :repeatable 11 | t.integer :defined 12 | t.integer :managed 13 | t.integer :optimising 14 | 15 | t.timestamps null: false 16 | end 17 | end 18 | 19 | def down 20 | drop_table :organisation_scores 21 | Organisation.all_organisations_group.delete 22 | Organisation.all_dgu_organisations_group.delete 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /app/models/country.rb: -------------------------------------------------------------------------------- 1 | class Country < ActiveRecord::Base 2 | has_many :users 3 | has_many :assessments, through: :users 4 | has_many :statistics, class_name: "CountryScore" 5 | 6 | validates :name, presence: true 7 | validates :name, uniqueness: true 8 | validates :code, presence: true 9 | validates :code, uniqueness: true 10 | 11 | def to_s 12 | self.name 13 | end 14 | 15 | def as_json(options) 16 | { id: name, text: name } 17 | end 18 | 19 | def users_with_organisations 20 | return users.where("organisation_id is not null") 21 | end 22 | 23 | def users_with_no_organisation 24 | return users.where("organisation_id is null") 25 | end 26 | 27 | def users_with_completed_assessments 28 | return assessments.where("completion_date is not null") 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /app/views/devise/shared/_password.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= f.label :password, class: "required" %> 3 | <% if @validatable %> 4 | (<%= @minimum_password_length %> characters) 5 | <% end %>
6 | <%= f.password_field :password_confirmation, 7 | autofocus: true, 8 | autocomplete: "off", 9 | "data-validation": "length", 10 | "data-validation-length": "min8", 11 | "data-validation-error-msg": t(:password_validation), style: "width:40%;" %> 12 |
13 | 14 |
15 | <%= f.label :password_confirmation, class: "required" %>
16 | <%= f.password_field :password, 17 | autocomplete: "off", 18 | "data-validation": "confirmation", 19 | "data-validation-error-msg": t(:password_confirmation), style: "width:40%;" %> 20 |
21 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: &test 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | adapter: postgresql 26 | encoding: unicode 27 | # For details on connection pooling, see rails configuration guide 28 | # http://guides.rubyonrails.org/configuring.html#database-pooling 29 | pool: 5 30 | 31 | cucumber: 32 | <<: *test -------------------------------------------------------------------------------- /lib/tasks/organisations.rake: -------------------------------------------------------------------------------- 1 | require 'organisation_importer' 2 | 3 | namespace :organisations do 4 | 5 | #work around that heroku schedule only allows up to daily 6 | task :weekly_import => :environment do 7 | if Time.now.monday? 8 | Rake::Task["organisations:import"].execute 9 | end 10 | end 11 | 12 | desc "Imports organisations from the data.gov.uk hierarchy" 13 | task :import => :environment do 14 | Organisation.create(title: "All Organisations") 15 | Organisation.create(title: "All data.gov.uk organisations") 16 | uri = URI("https://data.gov.uk/api/action/group_tree?type=organization") 17 | response = Net::HTTP.get_response(uri) 18 | json = JSON.parse(response.body) 19 | results = json['result'] 20 | puts "#{results.length} top level organisations found" 21 | OrganisationImporter.populate(results) 22 | end 23 | 24 | end 25 | -------------------------------------------------------------------------------- /spec/models/questionnaire_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Questionnaire do 4 | describe "creation" do 5 | 6 | context "valid attributes" do 7 | it "should be valid" do 8 | questionnaire = FactoryGirl.build(:questionnaire) 9 | questionnaire.should be_valid 10 | end 11 | end 12 | 13 | context "invalid attributes" do 14 | it "should not be valid" do 15 | questionnaire = FactoryGirl.build(:questionnaire, version: "") 16 | questionnaire.should_not be_valid 17 | end 18 | 19 | it "should not support duplicates" do 20 | questionnaire = FactoryGirl.build(:questionnaire) 21 | questionnaire.save 22 | questionnaire2 = FactoryGirl.build(:questionnaire) 23 | lambda do 24 | questionnaire2.save 25 | end.should raise_error 26 | end 27 | end 28 | 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /spec/factories/answers.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :answer do 3 | code "q1.1" 4 | question_id 1 5 | text "Yes, we have published at least one dataset under an open licence" 6 | notes "" 7 | positive true 8 | end 9 | 10 | factory :negative_answer, class: Answer do 11 | code "q1.2" 12 | question_id 1 13 | text "No, we have not yet published any open data" 14 | notes "" 15 | positive false 16 | score 1 17 | end 18 | 19 | factory :answer3, class: Answer do 20 | code "q1.2" 21 | question_id 1 22 | text "No, we have not yet published any open data" 23 | notes "" 24 | positive false 25 | score 1 26 | end 27 | 28 | factory :answer4, class: Answer do 29 | code "q1.2" 30 | question_id 1 31 | text "No, we have not yet published any open data" 32 | notes "" 33 | positive true 34 | score 1 35 | end 36 | 37 | end 38 | -------------------------------------------------------------------------------- /spec/models/dimension_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Dimension do 4 | describe "creation" do 5 | 6 | context "valid attributes" do 7 | it "should be valid" do 8 | dimension = FactoryGirl.build(:dimension) 9 | dimension.should be_valid 10 | end 11 | end 12 | 13 | context "invalid attributes" do 14 | it "should not be valid" do 15 | dimension = FactoryGirl.build(:dimension, name: "") 16 | dimension.should_not be_valid 17 | 18 | dimension = FactoryGirl.build(:dimension, title: "") 19 | dimension.should_not be_valid 20 | 21 | end 22 | 23 | it "should not support duplicates" do 24 | dimension = FactoryGirl.build(:dimension) 25 | dimension.save 26 | dimension2 = FactoryGirl.build(:dimension) 27 | dimension2.should_not be_valid 28 | end 29 | end 30 | 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | 4 | # path to your application root. 5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 6 | 7 | Dir.chdir APP_ROOT do 8 | # This script is a starting point to setup your application. 9 | # Add necessary setup steps to this file: 10 | 11 | puts "== Installing dependencies ==" 12 | system "gem install bundler --conservative" 13 | system "bundle check || bundle install" 14 | 15 | # puts "\n== Copying sample files ==" 16 | # unless File.exist?("config/database.yml") 17 | # system "cp config/database.yml.sample config/database.yml" 18 | # end 19 | 20 | puts "\n== Preparing database ==" 21 | system "bin/rake db:setup" 22 | 23 | puts "\n== Removing old logs and tempfiles ==" 24 | system "rm -f log/*" 25 | system "rm -rf tmp/cache" 26 | 27 | puts "\n== Restarting application server ==" 28 | system "touch tmp/restart.txt" 29 | end 30 | -------------------------------------------------------------------------------- /app/views/assessments/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %>My assessments<% end %> 2 | 3 | <% if @current_assessment.blank? and @assessments.blank? %> 4 | <%= render 'first_assessment' %> 5 | <% else %> 6 | <% if !@assessments.empty? %> 7 |
8 |
9 | <%= link_to "Set goals for the next assessment", edit_assessment_targets_path(@last_assessment), class: "btn orange" %> 10 |
11 | <% end %> 12 | 13 | 24 | 25 | <% end %> -------------------------------------------------------------------------------- /spec/models/country_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Country, type: :model do 4 | describe "creation" do 5 | 6 | context "valid attributes" do 7 | it "should be valid" do 8 | country = FactoryGirl.build(:country) 9 | country.should be_valid 10 | end 11 | end 12 | 13 | context "invalid attributes" do 14 | it "should not validate an empty name" do 15 | country = FactoryGirl.build(:country, name: "") 16 | country.should_not be_valid 17 | end 18 | it "should not validate an empty code" do 19 | country = FactoryGirl.build(:country, code: "") 20 | country.should_not be_valid 21 | end 22 | 23 | it "should not support duplicates" do 24 | country = FactoryGirl.build(:country) 25 | country.save 26 | country2 = FactoryGirl.build(:country) 27 | country2.should_not be_valid 28 | end 29 | end 30 | 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Expected Behaviour 4 | 5 | 6 | ## Current Behaviour 7 | 8 | 9 | ## Desired Behaviour (for improvement suggestions) 10 | 11 | 12 | ## Steps to Reproduce (for problems) 13 | 14 | 15 | 1. 16 | 2. 17 | 3. 18 | 4. 19 | 20 | ## Your Environment (for problems) 21 | 22 | * Environment name and version (e.g. Chrome 39, node.js 5.4): 23 | * Operating System and version (desktop or mobile): 24 | -------------------------------------------------------------------------------- /spec/lib/organisation_importer_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'organisation_importer' 3 | 4 | describe OrganisationImporter do 5 | describe '.populate' do 6 | 7 | before(:all) do 8 | file = File.read('spec/lib/defra.json') 9 | json = JSON.parse(file) 10 | @results = json['result'] 11 | OrganisationImporter.populate(@results) 12 | end 13 | 14 | after(:all) do 15 | Organisation.destroy_all 16 | end 17 | 18 | it "should create new organisations from example JSON" do 19 | expect(Organisation.count).to eq(14) 20 | end 21 | 22 | it "should only create one top level organisation from example JSON" do 23 | expect(Organisation.where(parent: nil).count).to eq(1) 24 | end 25 | 26 | it "should not create duplicate entries" do 27 | count = Organisation.count 28 | OrganisationImporter.populate(@results) 29 | expect(Organisation.count).to eq(count) 30 | end 31 | 32 | end 33 | end -------------------------------------------------------------------------------- /app/models/activity.rb: -------------------------------------------------------------------------------- 1 | class Activity < ActiveRecord::Base 2 | has_many :questions 3 | belongs_to :dimension 4 | belongs_to :questionnaire 5 | 6 | validates :title, presence: true 7 | validates :name, presence: true 8 | validates :name, uniqueness: {scope: :questionnaire_id, message: "activity name should be unique within questionnaire" } 9 | 10 | def next_question_for(assessment) 11 | assessment.reload 12 | assessment_answers = assessment.assessment_answers.where(question_id: self.questions) 13 | 14 | answers = Answer.where(id: assessment_answers.pluck(:answer_id)) 15 | unanswered_questions = Question.where(activity_id: self.id).where.not(id: assessment_answers.pluck(:question_id)) 16 | 17 | if unanswered_questions and answers.exists?(positive: false) 18 | nil #finished 19 | elsif unanswered_questions.blank? 20 | nil #finished 21 | else 22 | unanswered_questions.order(:id).first 23 | end 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /spec/models/improvement_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Improvement do 4 | describe "creation" do 5 | 6 | context "valid attributes" do 7 | it "should be valid" do 8 | improvement = FactoryGirl.build(:improvement) 9 | improvement.should be_valid 10 | end 11 | end 12 | 13 | context "invalid attributes" do 14 | it "should not be valid" do 15 | improvement = FactoryGirl.build(:improvement, notes: "") 16 | improvement.should_not be_valid 17 | 18 | improvement = FactoryGirl.build(:improvement, code: "") 19 | improvement.should_not be_valid 20 | 21 | end 22 | 23 | it "should not support duplicates" do 24 | improvement = FactoryGirl.build(:improvement) 25 | improvement.save 26 | improvement2 = FactoryGirl.build(:improvement) 27 | improvement2.should_not be_valid 28 | end 29 | 30 | end 31 | 32 | end 33 | 34 | end 35 | -------------------------------------------------------------------------------- /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: 704f9c66c8e6756c2132d9ee3e6cdf3681a47553ca5e207d4765d1204b0747f108156788d648e9fafdf7cad4c53be3ed6b96a1ee35bf9804977b55ed9af02532 15 | 16 | test: 17 | secret_key_base: bb52b1d57c991f93089bf3523d3ee3a0aa8a8602c85d174c23188ef08ebb65068908472ac4a6516bf9924508e0ca02b30272d2a3a8aa62e9014b7df6e9a998d9 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/views/assessments/_summary_tab.html.erb: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 | <%= render 'theme_label' %> 6 | <%= render 'score_label' %> 7 |
8 | 9 | <% scores = scorer.score_dimensions_from_saved_results %> 10 | <% total = 0; maximum = 0 %> 11 | <% for dimension in @dimensions %> 12 |
13 |

<%= dimension.title %>

14 | <% total += scores[dimension.name][:score]; maximum += scores[dimension.name][:max] %> 15 | <%= scores[dimension.name][:score] %> / <%= scores[dimension.name][:max] %> 16 |
17 | <% end %> 18 |
19 |

Total

20 | <%= total %> / <%= maximum %> 21 |
22 | 23 | 24 |
25 | 26 | ">Download summary scores 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/views/assessments/_share_modal.html.erb: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /features/home.feature: -------------------------------------------------------------------------------- 1 | Feature: Home page 2 | 3 | Scenario: Viewing the home page 4 | When I go to the homepage 5 | And I should see a link called "Privacy policy" to "/privacy-policy" 6 | And I should see a link called "Cookie policy" to "/cookie-policy" 7 | And I should see a link called "Terms of use" to "/terms-of-use" 8 | And I should see a link called "Sign in" to "/users/sign_in" 9 | And I should see a link called "Register" to "/users/sign_up" 10 | And I should see a link called "Statistics" to "/statistics" 11 | And I should see a link called "Get in touch" to "/contact" 12 | And I should see a link called "Feedback" to "/contact" 13 | And the page title should read "Open Data Pathway" 14 | 15 | Scenario: Viewing the home page as a user 16 | Given I am logged in as a user 17 | When I go to the homepage 18 | And I should see a link called "Sign out" to "/users/sign_out" 19 | And I should see a link called "Account" to "/users/edit" 20 | 21 | Scenario: Google Analytics 22 | When I go to the homepage 23 | Then I should see "UA-XXXX-Y" 24 | -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | --------------------- 3 | 4 | Copyright (c) 2013 The Open Data Institute 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | 12 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pathway", 3 | "description": "", 4 | "scripts": { 5 | }, 6 | "env": { 7 | "ADMIN_EMAIL": { 8 | "required": true 9 | }, 10 | "ADMIN_PASSWORD": { 11 | "required": true 12 | }, 13 | "GOOGLE_ANALYTICS_TRACKER": { 14 | "required": true 15 | }, 16 | "HEATMAP_THRESHOLD": { 17 | "required": true 18 | }, 19 | "HEROKU_POSTGRESQL_BLACK_URL": { 20 | "required": true 21 | }, 22 | "HEROKU_POSTGRESQL_ROSE_URL": { 23 | "required": true 24 | }, 25 | "LANG": { 26 | "required": true 27 | }, 28 | "MANDRILL_APIKEY": { 29 | "required": true 30 | }, 31 | "MANDRILL_USERNAME": { 32 | "required": true 33 | }, 34 | "RACK_ENV": { 35 | "required": true 36 | }, 37 | "RAILS_ENV": { 38 | "required": true 39 | }, 40 | "RAILS_SERVE_STATIC_FILES": { 41 | "required": true 42 | }, 43 | "SECRET_KEY_BASE": { 44 | "required": true 45 | } 46 | }, 47 | "formation": { 48 | }, 49 | "addons": [ 50 | "scheduler", 51 | "heroku-postgresql" 52 | ], 53 | "buildpacks": [ 54 | 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /app/models/organisation.rb: -------------------------------------------------------------------------------- 1 | class Organisation < ActiveRecord::Base 2 | 3 | has_many :users 4 | has_many :statistics, class_name: "OrganisationScore" 5 | 6 | validates :title, presence: true 7 | validates :title, uniqueness: true 8 | 9 | before_save :set_name 10 | 11 | def self.dgu 12 | Organisation.where("dgu_id is not null") 13 | end 14 | 15 | def self.all_organisations_group 16 | Organisation.find_by_title("All Organisations") 17 | end 18 | 19 | def self.all_dgu_organisations_group 20 | Organisation.find_by_title("All data.gov.uk organisations") 21 | end 22 | 23 | def to_s 24 | self.title 25 | end 26 | 27 | def as_json(options) 28 | { id: title, text: title } 29 | end 30 | 31 | def set_name 32 | self.name = self.title.parameterize if self.name.blank? 33 | end 34 | 35 | def parent? 36 | Organisation.where(parent: self.id).present? 37 | end 38 | 39 | def dgu_organisation? 40 | return dgu_id.present? 41 | end 42 | 43 | def latest_completed_assessment 44 | user = users.first 45 | return nil unless user.present? 46 | return user.latest_completed_assessment 47 | end 48 | 49 | end 50 | -------------------------------------------------------------------------------- /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 | before_filter :configure_permitted_parameters, if: :devise_controller? 7 | 8 | def index 9 | end 10 | 11 | protected 12 | 13 | def configure_permitted_parameters 14 | devise_parameter_sanitizer.for(:sign_up) << :associated_organisation 15 | devise_parameter_sanitizer.for(:account_update) << :associated_organisation 16 | devise_parameter_sanitizer.for(:sign_up) << :name 17 | devise_parameter_sanitizer.for(:account_update) << :name 18 | end 19 | 20 | rescue_from CanCan::AccessDenied do |exception| 21 | redirect_to(root_url, {:flash => { :alert => exception.message }}) 22 | end 23 | 24 | def after_sign_in_path_for(resource) 25 | if current_user.associated_country.blank? 26 | edit_user_registration_path 27 | else 28 | assessments_path 29 | end 30 | end 31 | 32 | def current_ability 33 | @current_ability ||= Ability.new(current_user, params[:token]) 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /app/views/assessments/_activity_tab.html.erb: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 | <%= render 'theme_label' %> 6 | <%= render 'activity_label' %> 7 | <%= render 'score_label' %> 8 | <%= render 'next_goal_label' %> 9 |
10 | 11 | <% for dimension in @dimensions %> 12 |
13 |

<%= dimension.title %>

14 | 24 |
25 | <% end %> 26 | 27 |
28 | 29 | ">Download activity scores 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/assets/stylesheets/targets.scss: -------------------------------------------------------------------------------- 1 | //SET GOALS 2 | 3 | #setGoals { 4 | 5 | header { 6 | .labelGroup {width: 70%; display: inline-block; 7 | .activityColLabel {width: 60%;} 8 | .answersColLabel {width: 15%; margin-left: -15px;} 9 | .goalColLabel {width: 15%; display: inline-block; margin-left: -15px;} 10 | } 11 | } 12 | 13 | h3 { font-size: 18px; display: inline-block; float: left; width: 60%; margin-top: 0; font-weight: 400;} 14 | 15 | ul.activities { 16 | width: 70%; 17 | li { 18 | .wrapScoreGoal { 19 | width: 25%; 20 | float: left; 21 | position: relative; 22 | top: -0.25em; 23 | .score, .goal {display: inline-block;} 24 | .goal { 25 | 26 | .less, .more { 27 | cursor: pointer; 28 | position: relative; 29 | 30 | color: $odiBlue; 31 | &:hover {color: $odiOrange;} 32 | } 33 | input { 34 | width: 2.5em; 35 | text-align: center; 36 | display: inline-block; 37 | } 38 | } 39 | .score { 40 | width: 50%; 41 | .yourScore { 42 | background: black; 43 | color: white; 44 | padding: 0.25em 0.5em; 45 | border-radius: 4px; 46 | } 47 | } 48 | } 49 | &:first-child { padding-top: 15px; margin-top: 0;} 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/views/devise/shared/_links.html.erb: -------------------------------------------------------------------------------- 1 | <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> 2 | <%= link_to "Forgot your password?", new_password_path(resource_name) %>
3 | <% end -%> 4 | 5 | <%- if controller_name != 'sessions' %> 6 | Already registered? <%= link_to t(:sign_in_now), new_session_path(resource_name) %>
7 | <% end -%> 8 | 9 | <%- if devise_mapping.registerable? && controller_name != 'registrations' %> 10 | <%= link_to t(:sign_up_now), new_registration_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 #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %>
24 | <% end -%> 25 | <% end -%> 26 | -------------------------------------------------------------------------------- /features/targets.feature: -------------------------------------------------------------------------------- 1 | Feature: Setting targets for future assessments 2 | 3 | Scenario: Navigating to set targets 4 | Given I am logged in as a user 5 | Given the test survey has been loaded 6 | Given I have completed an assessment 7 | When I go to "/assessments" 8 | Then I should see "Set goals for the next assessment" 9 | 10 | Scenario: Can only set targets when there is a completed assessment 11 | Given I am logged in as a user 12 | Given the test survey has been loaded 13 | Given the following assessments: 14 | | title | notes | start_date | completion_date | 15 | | 2014 Q4 | End of last year | 2015-02-10 11:07:10 | | 16 | And the current assessment is ready for completion 17 | When I go to "/assessments" 18 | Then I should not see "Set goals for the next assessment" 19 | 20 | Scenario: Changing targets 21 | Given I am logged in as a user 22 | Given the test survey has been loaded 23 | Given I have completed an assessment 24 | When I go to "/assessments" 25 | And I click on "Set goals for the next assessment" 26 | Then I should see "Goal" 27 | When I fill in "targets_1" with "4" 28 | And I press "submit-bottom" 29 | Then I should see "Successfully saved goals" 30 | -------------------------------------------------------------------------------- /app/views/devise/sessions/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %><%= t(:sign_in) %><% end %> 2 |
3 |
4 | 5 | <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> 6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true, data: { validation: "email", "validation-error-msg" => t(:enter_email) }, style: "width:40%;" %> 9 |
10 | 11 |
12 | <%= f.label :password %>
13 | <%= f.password_field :password, autocomplete: "off", data: { validation: "required" }, style: "width:40%;" %> 14 |
15 | 16 | <% if devise_mapping.rememberable? -%> 17 |
18 | <%= f.label :remember_me do %> 19 | <%= f.check_box :remember_me %> 20 | <%= t(:remember_me) %> 21 | <% end %> 22 |
23 | <% end -%> 24 | 25 |
26 |
27 | <%= f.submit t(:sign_in), class: "btn green" %> 28 |
29 |
30 | <%= render "devise/shared/links" %> 31 |
32 |
33 | <% end %> 34 | 35 | 36 | 37 |
38 | 39 |
-------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | 3 | def pretty_date(datetime) 4 | datetime.strftime("%A, #{datetime.day.ordinalize} %B %Y") unless datetime.blank? 5 | end 6 | 7 | def link_to_add_fields(name, f, association, opts={}) 8 | new_object = f.object.send(association).build 9 | id = new_object.object_id 10 | 11 | partial_location = opts[:partial_location] 12 | partial_location ||= "#{association}/#{association.to_s.singularize}_fields" 13 | 14 | fields = f.fields_for(association, new_object, child_index: id) do |builder| 15 | render(partial_location, {f: builder}.merge(opts)) 16 | end 17 | 18 | link_to(name, '#', class: 'add_fields moreLinks btn orange', data: { id: id, fields: fields.gsub('\n', '') }) 19 | end 20 | 21 | def breadcrumb(str=nil) 22 | breadcrumb = link_to "My assessments", assessments_path 23 | 24 | unless @assessment.blank? 25 | if @assessment.status.eql? :complete 26 | breadcrumb << " > #{link_to(@assessment.title, report_path(@assessment))}".html_safe 27 | else 28 | breadcrumb << " > #{link_to(@assessment.title, assessment_path(@assessment))}".html_safe 29 | end 30 | end 31 | 32 | breadcrumb << " > #{@activity.title}" if @activity 33 | breadcrumb << " > #{str}" unless str.blank? 34 | breadcrumb 35 | end 36 | 37 | end 38 | -------------------------------------------------------------------------------- /app/views/admin/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %>Administration<% end %> 2 | 3 |

Registered Users

4 | 5 |

6 | List of registered users, ordered by the date they registered. 7 |

8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | <% @users.each do |user| %> 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 37 | 38 | <% end %> 39 | 40 |
NameEmailOrganisationCountryRegisteredLast LoginAdmin?
<%= user.name %><%= link_to user.email, edit_user_path(user.id), :class => 'navbar-link' %><%= user.organisation.title if user.organisation.present? %><%= user.country.name if user.country.present? %><%= user.created_at.to_formatted_s(:db) %><%= user.last_sign_in_at.to_formatted_s(:db) if user.last_sign_in_at.present? %><%= user.admin? %> 33 | <% unless user.email == current_user.email %> 34 | <%= link_to "Delete User", user, data: {confirm: "Are you sure?"}, :method => :delete, class: "btn btn-danger" %> 35 | <% end %> 36 |
41 | -------------------------------------------------------------------------------- /app/controllers/user_controller.rb: -------------------------------------------------------------------------------- 1 | class UserController < ApplicationController 2 | load_and_authorize_resource param_method: :my_sanitizer 3 | 4 | def index 5 | @users = User.excludes(:id => current_user.id) 6 | end 7 | 8 | def new 9 | @user = User.new 10 | end 11 | 12 | def create 13 | @user = User.new(params[:user]) 14 | if @user.save 15 | flash[:notice] = "Successfully created User." 16 | redirect_to root_path 17 | else 18 | render :action => 'new' 19 | end 20 | end 21 | 22 | def edit 23 | @user = User.find(params[:id]) 24 | end 25 | 26 | def update 27 | @user = User.find(params[:id]) 28 | params[:user].delete(:password) if params[:user][:password].blank? 29 | params[:user].delete(:password_confirmation) if params[:user][:password].blank? and params[:user][:password_confirmation].blank? 30 | if @user.update_attributes( user_params ) 31 | flash[:notice] = "Successfully updated User." 32 | redirect_to root_path 33 | else 34 | render :action => 'edit' 35 | end 36 | end 37 | 38 | def destroy 39 | @user = User.find(params[:id]) 40 | if @user.destroy 41 | flash[:notice] = "Successfully deleted User." 42 | redirect_to admin_path 43 | end 44 | end 45 | 46 | def user_params 47 | params.require(:user).permit([:email, :admin, :name]) 48 | end 49 | 50 | 51 | end 52 | -------------------------------------------------------------------------------- /spec/models/question_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Question do 4 | 5 | describe "#prev" do 6 | it "should return the previous question" do 7 | q1 = FactoryGirl.create(:question, code: "q1") 8 | q2 = FactoryGirl.create(:question, code: "q2") 9 | expect(q2.prev).to eq(q1) 10 | end 11 | end 12 | 13 | describe "#next" do 14 | it "should return the next question" do 15 | q1 = FactoryGirl.create(:question, code: "q1") 16 | q2 = FactoryGirl.create(:question, code: "q2") 17 | expect(q1.next).to eq(q2) 18 | end 19 | end 20 | 21 | describe "creation" do 22 | 23 | context "valid attributes" do 24 | it "should be valid" do 25 | question = FactoryGirl.build(:question) 26 | question.should be_valid 27 | end 28 | end 29 | 30 | context "invalid attributes" do 31 | it "should not be valid" do 32 | question = FactoryGirl.build(:question, text: "") 33 | question.should_not be_valid 34 | 35 | question = FactoryGirl.build(:question, code: "") 36 | question.should_not be_valid 37 | 38 | end 39 | 40 | it "should not support duplicates" do 41 | question = FactoryGirl.build(:question) 42 | question.save 43 | question2 = FactoryGirl.build(:question) 44 | question2.should_not be_valid 45 | end 46 | end 47 | 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /app/views/assessment_answers/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %> 2 | <%= @assessment.title %> 3 | <% end %> 4 | <% content_for :breadcrumb do %> 5 | <%= breadcrumb() %> 6 | <% end %> 7 | 8 |
9 | 10 | <%= form_for @assessment_answer, url: assessment_edit_answer_path(@assessment, @assessment_answer) do |f| %> 11 | 12 |
13 |

Assessing: <%= @activity.title %>

14 |
15 | <%= f.submit "Save and exit", class: "btn" %> 16 | <%= f.submit "Next question »".html_safe, class: "btn green", id: "submit-top" %> 17 |
18 |
19 | 20 |
21 | 22 | <%= render 'form', f: f %> 23 | 24 |
25 | 26 |
27 | <%= link_to '« Back'.html_safe, assessment_edit_answer_path(@assessment, @previous_answer), class: "btn btn-default back" if @previous_answer %> 28 | <%= f.submit "Next question »".html_safe, class: "btn green next", id: "submit-bottom" %> 29 |
30 | 31 |
32 | 33 |
34 | 35 | <% end %> 36 | 37 |
38 | 39 | <% content_for :javascript_footer do %> 40 | $(document).ready(function(){ 41 | observe_fields_for_links(); 42 | }); 43 | <% end %> 44 | -------------------------------------------------------------------------------- /spec/factories/assessments.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | 3 | factory :assessment do 4 | user nil 5 | start_date "2014-12-10 11:07:10" 6 | completion_date "2014-12-17 11:07:10" 7 | title "2014 Q3 Assessment" 8 | notes "This is a test assessment" 9 | end 10 | 11 | factory :unfinished_assessment, class: Assessment do 12 | user nil 13 | start_date "2015-02-10 11:07:10" 14 | completion_date nil 15 | title "2014 Q4 Assessment" 16 | notes "This is another test assessment, I'm not done yet." 17 | end 18 | 19 | factory :assessment2, class: Assessment do 20 | user nil 21 | start_date "2014-12-10 11:07:10" 22 | completion_date "2014-12-17 11:07:10" 23 | title "2014 Q1 Assessment" 24 | notes "This is a test assessment" 25 | end 26 | 27 | factory :assessment3, class: Assessment do 28 | user 29 | start_date "2014-12-10 11:07:10" 30 | completion_date nil 31 | title "2014 Q3 Assessment" 32 | notes "This is a test assessment" 33 | end 34 | 35 | factory :assessment4, class: Assessment do 36 | user 37 | start_date "2015-12-10 11:07:10" 38 | completion_date nil 39 | title "2014 Q3 Assessment" 40 | notes "This is a test assessment" 41 | end 42 | 43 | factory :assessment5, class: Assessment do 44 | user nil 45 | start_date "2016-12-10 11:07:10" 46 | completion_date nil 47 | title "2014 Q3 Assessment" 48 | notes "This is a test assessment" 49 | end 50 | 51 | end 52 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | require 'csv' 5 | 6 | # Require the gems listed in Gemfile, including any gems 7 | # you've limited to :test, :development, or :production. 8 | Bundler.require(*Rails.groups) 9 | 10 | module ODMAT 11 | class Application < Rails::Application 12 | # Settings in config/environments/* take precedence over those specified here. 13 | # Application configuration should go into files in config/initializers 14 | # -- all .rb files in that directory are automatically loaded. 15 | 16 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 17 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 18 | # config.time_zone = 'Central Time (US & Canada)' 19 | 20 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 21 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 22 | # config.i18n.default_locale = :de 23 | 24 | # Do not swallow errors in after_commit/after_rollback callbacks. 25 | config.active_record.raise_in_transactional_callbacks = true 26 | 27 | config.middleware.use Rack::GoogleAnalytics, :tracker => ENV["GOOGLE_ANALYTICS_TRACKER"] 28 | 29 | config.autoload_paths += %W(#{config.root}/lib) 30 | 31 | HEATMAP_THRESHOLD= ENV["HEATMAP_THRESHOLD"].to_i || 5 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/models/answer_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Answer do 4 | describe "creation" do 5 | 6 | context "valid attributes" do 7 | it "should be valid" do 8 | answer = FactoryGirl.build(:answer) 9 | answer.should be_valid 10 | answer = FactoryGirl.build(:negative_answer) 11 | answer.should be_valid 12 | 13 | end 14 | end 15 | 16 | context "invalid attributes" do 17 | it "should not be valid" do 18 | answer = FactoryGirl.build(:answer, text: "") 19 | answer.should_not be_valid 20 | 21 | answer = FactoryGirl.build(:answer, code: "") 22 | answer.should_not be_valid 23 | 24 | end 25 | 26 | it "should not support duplicates" do 27 | answer = FactoryGirl.build(:answer) 28 | answer.save 29 | answer2 = FactoryGirl.build(:answer) 30 | answer2.should_not be_valid 31 | end 32 | 33 | it "should allow only legal scores" do 34 | answer = FactoryGirl.build(:answer, score: 6) 35 | answer.should_not be_valid 36 | 37 | answer = FactoryGirl.build(:answer, score: 0) 38 | answer.should_not be_valid 39 | 40 | end 41 | 42 | it "should require a score for negative answers" do 43 | answer = FactoryGirl.build(:negative_answer, score: nil) 44 | answer.should_not be_valid 45 | 46 | end 47 | end 48 | 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /spec/models/organisation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Organisation do 4 | 5 | describe "self.dgu" do 6 | it "should only return dgu Organisations" do 7 | FactoryGirl.create(:organisation, title: "Non-DGU organisation", dgu_id: nil) 8 | FactoryGirl.create(:organisation, title: "DGU orginisation", dgu_id: 123) 9 | 10 | expect(Organisation.dgu.count).to eq(1) 11 | expect(Organisation.dgu.first.title).to eq("DGU orginisation") 12 | end 13 | end 14 | 15 | describe "#set_name" do 16 | it "should set a name slug on create" do 17 | o = Organisation.new 18 | o.title = "Department of Stuff" 19 | o.save 20 | expect(o.name).to eq("department-of-stuff") 21 | end 22 | end 23 | 24 | describe "creation" do 25 | 26 | context "valid attributes" do 27 | it "should be valid" do 28 | organisation = FactoryGirl.build(:organisation) 29 | organisation.should be_valid 30 | end 31 | end 32 | 33 | context "invalid attributes" do 34 | it "should not be valid" do 35 | organisation = FactoryGirl.build(:organisation, title: "") 36 | organisation.should_not be_valid 37 | end 38 | 39 | it "should not support duplicates" do 40 | organisation = FactoryGirl.build(:organisation) 41 | organisation.save 42 | organisation2 = FactoryGirl.build(:organisation) 43 | organisation2.should_not be_valid 44 | end 45 | end 46 | 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /app/views/assessment_answers/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %> 2 | <%= @assessment.title %> 3 | <% end %> 4 | <% content_for :breadcrumb do %> 5 | <%= breadcrumb() %> 6 | <% end %> 7 |
8 | 9 | <%= form_for @assessment_answer, url: assessment_question_answer_path(@assessment, @question) do |f| %> 10 | 11 |
12 |

Assessing: <%= @activity.title %>

13 |
14 | <%= link_to "Exit", assessment_path(@assessment), data: {confirm: "Any changes made to this page will be lost"}, class: "btn" %> 15 | <%= f.submit "Next question »".html_safe, class: "btn green", id: "submit-top" %> 16 |
17 |
18 | 19 |
20 | 21 | <%= render 'form', f: f %> 22 | 23 |
24 | 25 |
26 | <%= link_to '« Back'.html_safe, assessment_edit_answer_path(@assessment, @previous_answer), class: "btn btn-default back" if @previous_answer %> 27 | <%= f.submit "Next question »".html_safe, class: "btn green next", id: "submit-bottom" %> 28 |
29 | 30 |
31 | 32 |
33 | 34 | <% end %> 35 | 36 |
37 | 38 | <% content_for :javascript_footer do %> 39 | $(document).ready(function(){ 40 | observe_fields_for_links(); 41 | }); 42 | <% end %> -------------------------------------------------------------------------------- /db/migrate/20150224140146_devise_create_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateUsers < ActiveRecord::Migration 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.string :current_sign_in_ip 20 | t.string :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 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/models/assessment_answer.rb: -------------------------------------------------------------------------------- 1 | class AssessmentAnswer < ActiveRecord::Base 2 | belongs_to :assessment, touch: true 3 | belongs_to :question 4 | belongs_to :answer 5 | has_many :links, dependent: :destroy 6 | 7 | accepts_nested_attributes_for :links, :reject_if => lambda { |a| a["link"].blank? }, allow_destroy: true 8 | 9 | validates :question_id, presence: true 10 | validates :answer_id, presence: true 11 | validates :assessment_id, presence: true 12 | validates :question_id, uniqueness: { scope: :assessment_id, message: " has already beeen answered for this quesion." } 13 | 14 | after_save :remove_invalidated_answers 15 | 16 | def prev 17 | previous_answers.order(:id).last 18 | end 19 | 20 | def next 21 | proceeding_answers.order(:id).first 22 | end 23 | 24 | 25 | def remove_invalidated_answers 26 | proceeding_answers.destroy_all unless answer.positive 27 | end 28 | 29 | def proceeding_answers 30 | activity_id = self.question.activity_id 31 | AssessmentAnswer.joins(:assessment, question: :activity).where(assessment: assessment, questions: {activity_id: activity_id}).where('question_id > ?', question_id) 32 | end 33 | 34 | def previous_answers 35 | activity_id = self.question.activity_id 36 | AssessmentAnswer.joins(:assessment, question: :activity).where(assessment: assessment, questions: {activity_id: activity_id}).where('question_id < ?', question_id) 37 | end 38 | 39 | def additional_info? 40 | return true if ( links.any? || notes.present? ) 41 | return false 42 | end 43 | 44 | end -------------------------------------------------------------------------------- /spec/controllers/organisations_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe OrganisationsController do 4 | 5 | it "should query an organisation by title" do 6 | FactoryGirl.create(:organisation, name: "my-terrrible-organisation", title: "My Terrible Organisation") 7 | FactoryGirl.create(:organisation, name: "my-fantastic-organisation", title: "My Fantastic Organisation") 8 | 9 | get "index", q: "fantastic", format: "json" 10 | 11 | results = JSON.parse(response.body) 12 | 13 | expect(results.count).to eq(1) 14 | expect(results.first["text"]).to eq("My Fantastic Organisation") 15 | end 16 | 17 | it "should be limited to DGU organisations" do 18 | FactoryGirl.create(:organisation, name: "my-fantastic-organisation", title: "My Fantastic Organisation") 19 | FactoryGirl.create(:organisation, name: "another-fantastic-organisation", title: "Another Fantastic Organisation", dgu_id: nil) 20 | 21 | get "index", q: "fantastic", format: "json" 22 | 23 | results = JSON.parse(response.body) 24 | 25 | expect(results.count).to eq(1) 26 | expect(results.first["text"]).to eq("My Fantastic Organisation") 27 | end 28 | 29 | it "replaces spaces with dashes" do 30 | FactoryGirl.create(:organisation, name: "my-fantastic-organisation", title: "My Fantastic Organisation") 31 | 32 | get "index", q: "my fant", format: "json" 33 | 34 | results = JSON.parse(response.body) 35 | 36 | expect(results.count).to eq(1) 37 | expect(results.first["text"]).to eq("My Fantastic Organisation") 38 | end 39 | 40 | end 41 | -------------------------------------------------------------------------------- /app/assets/javascripts/forms.js.erb: -------------------------------------------------------------------------------- 1 | var observe_deletes = function(){ 2 | $('.delete_association').click(function(event) { 3 | $(this).prevAll('input[type=hidden][id$=_destroy]').val('1'); 4 | $(this).closest('div.nested_object').hide(); 5 | return event.preventDefault(); 6 | }); 7 | $('.delete_attribute').click(function(event) { 8 | $(this).closest('div.nested_object').find('input').val(''); 9 | $(this).closest('div.nested_object').hide(); 10 | return event.preventDefault(); 11 | }); 12 | }; 13 | 14 | var observe_adds = function(){ 15 | $('.add_fields').click(function(event){ 16 | var regexp, time; 17 | time = new Date().getTime(); 18 | regexp = new RegExp($(this).data('id'), 'g'); 19 | $(this).before($(this).data('fields').replace(regexp, time)); 20 | observe_deletes(); 21 | return event.preventDefault(); 22 | }); 23 | $('.add_array_fields').click(function(event) { 24 | var inputs, time; 25 | time = new Date().getTime(); 26 | $(this).before($(this).data('fields')); 27 | inputs = $(this).parent().find('input'); 28 | inputs[inputs.length - 1].setAttribute('id', time); 29 | observe_deletes(); 30 | return event.preventDefault(); 31 | }); 32 | }; 33 | 34 | var observe_fields_for_links = function(){ 35 | observe_adds(); 36 | observe_deletes(); 37 | }; 38 | 39 | var observe_toggles = function(){ 40 | $('.toggle-target').each(function(){ 41 | $(this).click(function(){ 42 | var target = $(this).data('target'); 43 | $(target).toggle(); 44 | return false 45 | }); 46 | }); 47 | }; 48 | -------------------------------------------------------------------------------- /app/views/layouts/_footer.html.erb: -------------------------------------------------------------------------------- 1 | 31 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | # Include default devise modules. Others available are: 3 | # :confirmable, :lockable, :timeoutable and :omniauthable 4 | devise :database_authenticatable, :registerable, 5 | :recoverable, :rememberable, :trackable, :validatable 6 | 7 | belongs_to :organisation 8 | belongs_to :country 9 | has_many :assessments, dependent: :destroy 10 | 11 | validates :organisation_id, uniqueness: true, unless: "organisation_id.nil?" 12 | validates :name, presence: true 13 | validates :terms_of_service, acceptance: true 14 | 15 | def self.can_share?(user, assessment) 16 | return true if (user.present? && user.id == assessment.user.id) 17 | end 18 | 19 | def self.organisational_users 20 | return User.where("organisation_id is not null") 21 | end 22 | 23 | def self.with_no_country 24 | return User.where("country_id is null") 25 | end 26 | 27 | def current_assessment 28 | assessments.where(:completion_date => nil).first 29 | end 30 | 31 | def associated_organisation=(title) 32 | org = Organisation.where(title: title).first_or_create 33 | self.organisation = org 34 | end 35 | 36 | def associated_organisation 37 | self.organisation 38 | end 39 | 40 | def associated_country=(name) 41 | country = Country.where(name: name).first 42 | self.country = country 43 | end 44 | def associated_country 45 | self.country 46 | end 47 | 48 | def latest_completed_assessment 49 | return assessments.where("completion_date is not null").order(completion_date: :desc).first 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /app/views/assessment_answers/_form.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |
6 |

* <%= @question.text %>

7 | 8 | <%= render "shared/errors", object: f.object %> 9 | 10 | <% for answer in @question.answers %> 11 |
12 | <%= f.label :answer_id, value: answer.id do %> 13 | <%= f.radio_button :answer_id, answer.id %> <%= answer.text %> 14 | <% end %> 15 |
16 | <% end %> 17 | 18 |
19 | 20 | 21 | 22 |
23 | 24 | <%= f.text_area :notes, class: "form-control" %> 25 | 26 | 34 |
35 | 36 | 37 |
38 | 39 | 40 |
41 | <% if @question.notes.present? %> 42 |
43 |

Question help

44 |

<%= @question.notes.html_safe %>

45 |
46 | <% end %> 47 |
48 | 49 | 50 |
51 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /spec/controllers/countries_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe CountriesController, type: :controller do 4 | it "should query a country by name" do 5 | FactoryGirl.create(:country, name: "A Made up Country", code: "am") 6 | FactoryGirl.create(:country, name: "Another made up Island", code: "ai") 7 | 8 | get "index", q: "Ano", format: "json" 9 | 10 | results = JSON.parse(response.body) 11 | 12 | expect(results.count).to eq(1) 13 | expect(results.first["text"]).to eq("Another made up Island") 14 | end 15 | 16 | it "should query a country by name regardless of case" do 17 | FactoryGirl.create(:country, name: "A Made up Country", code: "am") 18 | FactoryGirl.create(:country, name: "Another made up Island", code: "ai") 19 | 20 | get "index", q: "ano", format: "json" 21 | 22 | results = JSON.parse(response.body) 23 | 24 | expect(results.count).to eq(1) 25 | expect(results.first["text"]).to eq("Another made up Island") 26 | end 27 | 28 | it "should return json keys text and id" do 29 | FactoryGirl.create(:country, name: "A Made up Country", code: "am") 30 | FactoryGirl.create(:country, name: "Another made up Island", code: "ai") 31 | 32 | get "index", q: "Ano", format: "json" 33 | 34 | results = JSON.parse(response.body) 35 | 36 | expect(results.count).to eq(1) 37 | expect(results.first.keys).to eq(["id", "text"]) 38 | end 39 | 40 | it "returns country name as it appears in database" do 41 | FactoryGirl.create(:country, name: "a made-up country", code: "am") 42 | 43 | get "index", q: "A mad", format: "json" 44 | 45 | results = JSON.parse(response.body) 46 | 47 | expect(results.count).to eq(1) 48 | expect(results.first["text"]).to eq("a made-up country") 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /app/views/layouts/_header.html.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.scss: -------------------------------------------------------------------------------- 1 | /* 2 | *= require select2 3 | *= require select2-bootstrap 4 | */ 5 | 6 | @import "bootstrap-sprockets"; 7 | @import "bootstrap"; 8 | @import "font-awesome"; 9 | //some ODI base styles and colour definitions 10 | @import "colours"; 11 | @import "basic"; 12 | 13 | // Custom colours 14 | $pathwayLightGrey: #f5f5f5; 15 | 16 | @import "buttons"; 17 | @import "report"; 18 | @import "my_assessments"; 19 | @import "question"; 20 | @import "targets"; 21 | @import "home"; 22 | @import "heatmap"; 23 | 24 | .odi-orange { 25 | .page-title, .site-title .status { 26 | background-color: $odiOrange; 27 | } 28 | .caret { 29 | border-top-color: $odiOrange; 30 | border-bottom-color: $odiOrange; 31 | } 32 | } 33 | 34 | .odi-blue { 35 | .page-title, .site-title .status { 36 | background-color: $odiBlue; 37 | } 38 | .caret { 39 | border-top-color: $odiBlue; 40 | border-bottom-color: $odiBlue; 41 | } 42 | } 43 | 44 | h1.site-title { 45 | font-size: 32px; 46 | margin: 10px 0; 47 | position: relative; 48 | a { 49 | color: #fff; 50 | &:hover { 51 | text-decoration: none; 52 | } 53 | } 54 | .label { 55 | position: absolute; 56 | font-size: 12px; 57 | top: -12px; 58 | right: -60px; 59 | padding: 5px; 60 | } 61 | } 62 | 63 | .navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus { 64 | color: #fff; 65 | background-color: $odiOrange; 66 | } 67 | 68 | div.navbar-static-top { margin-bottom: 0px; } 69 | 70 | hr { border-color: #333; } 71 | 72 | h4.breadcrumb { 73 | background: none; 74 | padding-left:0px; 75 | color:white; 76 | margin-bottom:0px; 77 | margin-top:2px; 78 | font-size:1em; 79 | 80 | a { color:white; } 81 | } 82 | 83 | label.required:after { 84 | content: " *"; 85 | color: red; 86 | } -------------------------------------------------------------------------------- /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/controllers/registrations_controller.rb: -------------------------------------------------------------------------------- 1 | class RegistrationsController < Devise::RegistrationsController 2 | before_filter :configure_permitted_parameters 3 | 4 | def new 5 | super 6 | end 7 | 8 | def create 9 | build_resource(sign_up_params) 10 | resource_saved = resource.save 11 | yield resource if block_given? 12 | if resource_saved 13 | if resource.active_for_authentication? 14 | set_flash_message :notice, :signed_up if is_flashing_format? 15 | sign_up(resource_name, resource) 16 | respond_with resource, location: after_sign_up_path_for(resource) 17 | else 18 | set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format? 19 | expire_data_after_sign_in! 20 | respond_with resource, location: after_inactive_sign_up_path_for(resource) 21 | end 22 | else 23 | clean_up_passwords resource 24 | @validatable = devise_mapping.validatable? 25 | if @validatable 26 | @minimum_password_length = resource_class.password_length.min 27 | end 28 | 29 | if resource.errors.include?(:organisation_id) 30 | redirect_to contact_organisation_admin_path(resource.organisation_id, email: resource.email) 31 | else 32 | respond_with resource 33 | end 34 | end 35 | end 36 | 37 | def configure_permitted_parameters 38 | devise_parameter_sanitizer.for(:sign_up) do |u| 39 | u.permit(:name, 40 | :email, :password, :password_confirmation, :associated_organisation, :associated_country, :terms_of_service) 41 | end 42 | devise_parameter_sanitizer.for(:account_update) do |u| 43 | u.permit(:name, 44 | :email, :password, :password_confirmation, :current_password, :associated_organisation, :associated_country, :terms_of_service) 45 | end 46 | end 47 | 48 | end 49 | -------------------------------------------------------------------------------- /app/assets/stylesheets/question.scss: -------------------------------------------------------------------------------- 1 | // THE ASSESSMENT 2 | 3 | #theAssessment { 4 | 5 | #assessmentHeader { 6 | h2 { 7 | float: left; 8 | margin-top: 0; 9 | font-weight: normal; 10 | color: $odiGrey; 11 | font-weight: 300; 12 | font-size: 21px; 13 | em { 14 | font-weight: 400; 15 | font-style: normal; 16 | } 17 | } 18 | .actions { 19 | float: right; 20 | margin-right: 15px; 21 | margin-bottom: 15px; 22 | a {margin-left: 0.5em;} 23 | } 24 | } 25 | 26 | .assessmentContent { 27 | 28 | >.row { margin-left: 0px !important; margin-right: 0px !important;} 29 | .row:last-child { padding: 1em;} 30 | 31 | border: 1px solid black; 32 | 33 | 34 | #question { 35 | border-right: 1px solid $odiGreyLight; 36 | padding: 1em 1em 1em 0; 37 | margin-bottom: 0; 38 | h3 {margin: 0;} 39 | } 40 | 41 | #additionalInfo { 42 | padding: 1em 1em 1em 0; 43 | border-right: 1px solid $odiGreyLight; 44 | margin-bottom: 0; 45 | textarea {margin-bottom: 1em;} 46 | a.moreLinks {float: right; margin-top: 0.5em; display: block; cursor: pointer;} 47 | } 48 | 49 | footer.row { 50 | border-top: 1px solid $odiGreyLight; 51 | .actionsFull { 52 | a.next {float: right;} 53 | } 54 | } 55 | 56 | #helpColumn { 57 | padding-left: 0; 58 | .helpWrapper { 59 | padding: 15px; 60 | margin: 15px 0; 61 | background: #f5f5f5; 62 | border: 1px solid #e3e3e3; 63 | border-radius: 3px; 64 | } 65 | } 66 | } 67 | 68 | } 69 | 70 | div.nested_object { 71 | 72 | fieldset { margin: 1em; margin-right: 0em; } 73 | a.delete_association { float:right; } 74 | label { display: inline-block; width: 10%; } 75 | input.form-control { width: 69%; display: inline-block; margin-bottom:0.5em; } 76 | 77 | } 78 | 79 | .alert { 80 | margin: 1em 0; 81 | } 82 | -------------------------------------------------------------------------------- /features/step_definitions/web_steps.rb: -------------------------------------------------------------------------------- 1 | When(/^I go to the homepage$/) do 2 | visit root_path 3 | end 4 | 5 | When(/^I go to the register page$/) do 6 | visit new_user_registration_path 7 | end 8 | 9 | When(/^I go to "(.*?)"$/) do |path| 10 | visit path 11 | end 12 | 13 | When(/^I fill in "([^"]*)" with "([^"]*)"$/) do |field, value| 14 | fill_in field, :with=>value 15 | end 16 | 17 | When(/^I check "(.*?)"$/) do |field| 18 | check field 19 | end 20 | 21 | 22 | When(/^I go back$/) do 23 | visit page.driver.request.env['HTTP_REFERER'] 24 | end 25 | 26 | When(/^I choose "([^"]*)"$/) do |value| 27 | choose(value) 28 | end 29 | 30 | Then(/^I should see a link called "(.*?)" to "(.*?)"$/) do |link, url| 31 | page.should have_link(link, :href => url) 32 | end 33 | 34 | Then(/^I should be on the homepage$/) do |text| 35 | assert page.current_path == root_path 36 | end 37 | 38 | Then(/^I should see "(.*?)"$/) do |text| 39 | page.body.should have_text(text) 40 | end 41 | 42 | Then(/^I should not see "(.*?)"$/) do |text| 43 | page.body.should_not have_text(text) 44 | end 45 | 46 | When(/^I click on "(.*?)"$/) do |link| 47 | if link[0].eql?('#') or link[0].eql?('.') 48 | page.execute_script "$('#{link}').trigger('click');" 49 | else 50 | click_link link 51 | end 52 | end 53 | 54 | When(/^I press "(.*?)"$/) do |button| 55 | click_button(button) 56 | end 57 | 58 | Then (/^(?:|I )should be on (.+)$/) do |page_name| 59 | current_path = URI.parse(current_url).path 60 | if current_path.respond_to? :should 61 | current_path.should == path_to(page_name) 62 | else 63 | assert_equal path_to(page_name), current_path 64 | end 65 | end 66 | 67 | Then(/^the page title should read "(.*?)"$/) do |title| 68 | page.has_title? title 69 | end 70 | 71 | Then(/^I should see the page heading "(.*?)"$/) do |title| 72 | expect(find('.page-title').find('h1')).to have_content(title) 73 | end 74 | -------------------------------------------------------------------------------- /features/sharing.feature: -------------------------------------------------------------------------------- 1 | Feature: Sharing reports 2 | As a user I want to share my reports with other people 3 | 4 | Background: 5 | Given the test survey has been loaded 6 | Given there is an organisation user 7 | Given the following assessments: 8 | | title | notes | start_date | completion_date | user_id | completed | 9 | | 2014 Q4 | End of last year | 2014-12-10 11:07:10 | | 1 | yes | 10 | | 2015 Q1 | Start of year | 2015-02-10 11:07:10 | | 1 | yes | 11 | 12 | Scenario: Attempting to view a report when not logged in 13 | When I go to "/assessments/1/report" 14 | Then I should see "You are not authorized to access this page." 15 | 16 | Scenario: Attempting to view a report when logged in 17 | Given I am logged in as a user 18 | When I go to "/assessments/1/report" 19 | Then I should see "You are not authorized to access this page." 20 | 21 | Scenario: Attempting to view a report with a token 22 | When I click on the sharing link for the "2015 Q1" assessment 23 | Then I should see "Maturity scores" 24 | Then I should see "Assessment answers" 25 | Then I should see "Suggested improvements" 26 | Then I should see "Background notes" 27 | Then I should not see "Share your report" 28 | 29 | Scenario: Attempting to download summary scores CSV with a token 30 | When I click on the sharing link for the "2015 Q1" assessment 31 | And I click on the "Download summary scores" link 32 | Then I should not see "You are not authorized to access this page." 33 | And I should see a CSV 34 | 35 | Scenario: Attempting to download activity scores CSV with a token 36 | When I click on the sharing link for the "2015 Q1" assessment 37 | And I click on the "Download activity scores" link 38 | Then I should not see "You are not authorized to access this page." 39 | And I should see a CSV 40 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static file server for tests with Cache-Control for performance. 16 | config.serve_static_files = true 17 | config.static_cache_control = 'public, max-age=3600' 18 | 19 | # Show full error reports and disable caching. 20 | config.consider_all_requests_local = true 21 | config.action_controller.perform_caching = false 22 | 23 | # Raise exceptions instead of rendering exception templates. 24 | config.action_dispatch.show_exceptions = false 25 | 26 | # Disable request forgery protection in test environment. 27 | config.action_controller.allow_forgery_protection = false 28 | 29 | # Tell Action Mailer not to deliver emails to the real world. 30 | # The :test delivery method accumulates sent emails in the 31 | # ActionMailer::Base.deliveries array. 32 | config.action_mailer.delivery_method = :test 33 | 34 | # Randomize the order test cases are executed. 35 | config.active_support.test_order = :random 36 | 37 | # Print deprecation notices to the stderr. 38 | config.active_support.deprecation = :stderr 39 | 40 | # Raises error for missing translations 41 | # config.action_view.raise_on_missing_translations = true 42 | 43 | config.after_initialize do 44 | ActiveRecord::Base.logger = nil 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/assessment_scorer.rb: -------------------------------------------------------------------------------- 1 | class AssessmentScorer 2 | 3 | def initialize(assessment) 4 | @assessment = assessment 5 | @calculator = ProgressCalculator.new(assessment) 6 | end 7 | 8 | def score_activity(activity) 9 | raise "Activity assessment not complete" unless @calculator.activity_completed?(activity) 10 | 11 | #find the assesssment_answers for all questions that are associated with this activity 12 | answers = AssessmentAnswer.joins(:answer, :assessment, question: :activity) \ 13 | .where(assessment: @assessment, questions: {activity_id: activity.id}) \ 14 | .order("answers.id DESC").limit(1) 15 | 16 | answers.first.answer.score 17 | end 18 | 19 | def score_activities(dimension = nil) 20 | scores = {} 21 | activities = dimension ? dimension.activities : Questionnaire.order("version desc").first.activities 22 | activities.each do |activity| 23 | scores[ activity.name ] = score_activity(activity) if activity.questions.length > 0 24 | end 25 | scores 26 | end 27 | 28 | def score_dimension(dimension) 29 | activities = score_activities(dimension) 30 | return { 31 | score: activities.values.inject(:+), 32 | max: activities.keys.size * 5 33 | } 34 | end 35 | 36 | def score_dimensions 37 | scores = {} 38 | Questionnaire.current.dimensions.each do |dimension| 39 | scores[ dimension.name] = score_dimension(dimension) 40 | end 41 | scores 42 | end 43 | 44 | def score_dimensions_from_saved_results 45 | scores = {} 46 | Questionnaire.current.dimensions.each do |dimension| 47 | scores[ dimension.name ] = { score: 0, max: 0 } 48 | dimension.activities.each do |activity| 49 | scores[ dimension.name ][:max] += 5 if activity.questions.length > 0 50 | saved_score = Score.where( assessment: @assessment, activity: activity).first 51 | scores[ dimension.name ][:score] += saved_score.score if saved_score 52 | end 53 | end 54 | scores 55 | end 56 | 57 | end -------------------------------------------------------------------------------- /features/step_definitions/question_steps.rb: -------------------------------------------------------------------------------- 1 | Given(/^the test survey has been loaded$/) do 2 | config = File.join( __dir__, "..", "..", "spec", "lib", "test-survey.xls" ) 3 | QuestionnaireImporter.load(1, config) 4 | Rails.logger.info "Loaded test survey with: #{Question.count} questions and #{Answer.count} answers.\n" 5 | end 6 | 7 | Given(/^I have started an assessment$/) do 8 | @assessment = FactoryGirl.create(:unfinished_assessment, user_id: @current_user.id) 9 | end 10 | 11 | Given(/^I have completed an assessment$/) do 12 | @assessment = FactoryGirl.create(:assessment, user_id: @current_user.id) 13 | q = Question.where(code: "Q1").first 14 | a = Answer.where(code: "Q1.2").first 15 | @assessment.assessment_answers.create(question: q, answer: a) 16 | @assessment.complete 17 | end 18 | 19 | When(/^I go to the first question$/) do 20 | first_question = Question.where(code: "Q1").first 21 | visit assessment_question_path(@assessment, first_question) 22 | end 23 | 24 | When(/^I go back to the first question$/) do 25 | visit assessment_edit_answer_path(@assessment, @assessment.assessment_answers.first) 26 | end 27 | 28 | Given(/^I have answered the first question including a link$/) do 29 | positive = Answer.where(code: "Q1.1").first 30 | first_question = Question.where(code: "Q1").first 31 | assessment_answer = @assessment.assessment_answers.create(answer: positive, question: first_question) 32 | assessment_answer.links.create(FactoryGirl.attributes_for(:link)) 33 | end 34 | 35 | Given(/^I have completed the first activity$/) do 36 | positive = Answer.where(code: "Q1.1").first 37 | first_question = Question.where(code: "Q1").first 38 | negative = Answer.where(code: "Q2.2").first 39 | second_question = Question.where(code: "Q2").first 40 | @assessment.assessment_answers.create(answer: positive, question: first_question) 41 | @assessment.assessment_answers.create(answer: negative, question: second_question, notes: "more info on q2") 42 | Rails.logger.info("\n ------------------------ \n #{negative.to_json} \n #{second_question.to_json} \n") 43 | end 44 | -------------------------------------------------------------------------------- /app/views/pages/cookie_policy.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %>Cookie Policy<% end %> 2 | 3 |

4 | Our website uses cookies to distinguish you from other users of our website. This helps us to provide you with a good 5 | experience when you browse our website and also allows us to improve our site. A cookie is a small file of letters and numbers 6 | that we store on your browser or the hard drive of your computer if you agree. Cookies contain information that is 7 | transferred to your computer’s hard drive. You can find more information about the individual cookies we use and the 8 | purposes for which we use them in the table below: 9 |

10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 35 | 41 | 42 | 43 |
Name(s)PurposeExpires
_ODMAT_sessionThis cookie is used to maintain your session with the application.2 weeks or until you explicitly logout
_utma
27 | _utmb
28 | _utmc
29 | _utmz
30 |
32 | These cookies allow us to collect anonymous information about our visitors such that we can improve the website and ensure it caters to peoples needs. 33 | More information. 34 | 36 | _utma - 2 years
37 | _utmb - 30 minutes
38 | _utmc - when you exit the browser
39 | _utmz - 6 months
40 |
44 | 45 |

46 | You can block these cookies by activating the setting on your browser that allows you to refuse the setting of all or some cookies. 47 | However, if you use your browser settings to block all cookies (including essential cookies) you may not be able to access all or parts of our site. 48 |

-------------------------------------------------------------------------------- /app/assets/stylesheets/home.scss: -------------------------------------------------------------------------------- 1 | #homeContent { 2 | 3 | #cta { 4 | 5 | margin: 1em 0; 6 | text-align: center; 7 | h1 {font-size: 55px; color: $odiGrey; margin-bottom: 30px; } 8 | p {font-size: 24px;} 9 | #takeAssessmnet { 10 | background: $pathwayLightGrey; 11 | border: $odiGrey; 12 | border-radius: 5px; 13 | padding: 25px; 14 | a { padding: 0.5em 1.5em; min-width: 270px; margin: 0 10px; 15 | h2 { margin: 0; font-size: 30px; font-weight: normal; } 16 | } 17 | } 18 | } 19 | 20 | #howItWorks { 21 | text-align: center; 22 | background: $odiOrange; 23 | padding: 2em 0; 24 | margin: 3em 0 ; 25 | color: white; 26 | 27 | .step { 28 | 29 | &.two {border-right: 1px solid darken($odiOrange, 15%); border-left: darken($odiOrange, 15%) 1px solid;} 30 | h4 { 31 | color:white; 32 | margin: 20px 0 20px; 33 | font-weight: normal; font-size: 30px; 34 | span { display: block; font-size: 30px; font-weight: 200; color: white;} 35 | } 36 | .highlight { 37 | font-weight: bold; 38 | text-transform: uppercase; 39 | background: white; 40 | color: $odiOrange; 41 | display: inline-block; 42 | margin: -1em 0 0 0; 43 | padding: 0.25em 0.5em; 44 | position: absolute; 45 | top: 0; 46 | right: 0; 47 | border-radius: 3px 0 0 3px; 48 | color: $odiBlue; 49 | border-right: 1px solid $odiOrange; 50 | } 51 | } 52 | } 53 | 54 | 55 | #benefits, #whatsnext { 56 | .wrapper { 57 | background: $pathwayLightGrey; 58 | border: $odiGrey; 59 | display: inline-block; 60 | border-radius: 5px; 61 | padding: 25px; 62 | display: block; 63 | } 64 | } 65 | 66 | #whatsnext { 67 | h3 {color: $odiBlue; margin-top: 0; font-weight: normal; font-size: 30px;} 68 | } 69 | 70 | #benefits { 71 | h3 {color: $odiBlue; margin-top: 0; font-weight: normal; font-size: 30px;} 72 | ul { 73 | list-style: none; 74 | margin: 0; 75 | padding: 0; 76 | li { 77 | margin-bottom: 5px; 78 | span.glyphicon {color: $odiColour5;} 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /features/step_definitions/authentication_steps.rb: -------------------------------------------------------------------------------- 1 | Given(/^I am logged in as an administrator$/) do 2 | 3 | user = FactoryGirl.create(:admin) 4 | @current_user = user 5 | 6 | visit '/users/sign_in' 7 | fill_in "user_email", :with => user.email 8 | fill_in "user_password", :with => user.password 9 | click_button "Sign in" 10 | 11 | end 12 | 13 | Given(/^I am logged in as a user$/) do 14 | 15 | user = FactoryGirl.create(:user) 16 | @current_user = user 17 | 18 | visit '/users/sign_in' 19 | fill_in "user_email", :with => user.email 20 | fill_in "user_password", :with => user.password 21 | click_button "Sign in" 22 | 23 | end 24 | 25 | Given(/^I visit the user admin page$/) do 26 | visit '/users/edit' 27 | end 28 | 29 | Given(/^I am logged in as an organisation user$/) do 30 | 31 | user = FactoryGirl.create(:organisation_user) 32 | @current_user = user 33 | 34 | visit '/users/sign_in' 35 | fill_in "user_email", :with => user.email 36 | fill_in "user_password", :with => user.password 37 | click_button "Sign in" 38 | 39 | end 40 | 41 | Given(/^there is a registered user$/) do 42 | FactoryGirl.create(:user) 43 | end 44 | 45 | Given(/^there is an organisation user$/) do 46 | org = FactoryGirl.create(:organisation) 47 | FactoryGirl.create(:organisation_user, organisation_id: org.id) 48 | end 49 | 50 | Given(/^there is a hierarchy of data.gov.uk organisations$/) do 51 | #1 52 | defra = FactoryGirl.create(:organisation) 53 | #2 54 | ea = FactoryGirl.create(:organisation, title: "Environment Agency", parent: defra.id) 55 | #3 56 | fc = FactoryGirl.create(:organisation, title: "Forestry Commission", parent: defra.id) 57 | 58 | FactoryGirl.create(:organisation_user, organisation_id: ea.id) 59 | @fc_user = FactoryGirl.create(:organisation_user, email: "another@example.org", organisation_id: fc.id) 60 | end 61 | 62 | Given(/^I am logged in as the forestry commission$/) do 63 | 64 | @current_user = @fc_user 65 | 66 | visit '/users/sign_in' 67 | fill_in "user_email", :with => @fc_user.email 68 | fill_in "user_password", :with => @fc_user.password 69 | click_button "Sign in" 70 | 71 | end 72 | -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require turbolinks 16 | //= require bootstrap-sprockets 17 | //= require_tree . 18 | //= require select2 19 | //= require jquery.form-validator 20 | 21 | var attachTypeAhead = function(){ 22 | $('.select2').each(function(i, e){ 23 | var select = $(e) 24 | options = { minimumInputLength: 3 } 25 | if (select.hasClass('ajax')) { 26 | options.ajax = { 27 | url: select.data('source'), 28 | dataType: 'json', 29 | data: function(term, page) { return { q: term } }, 30 | results: function(data, page) { return { results: data } } 31 | } 32 | options.dropdownCssClass = "bigdrop" 33 | options.createSearchChoice = function(term, data) { 34 | if ( $(data).filter( function() { 35 | return this.text.localeCompare(term)===0; 36 | }).length===0) { 37 | return {id:term, text:term}; 38 | } 39 | } 40 | options.initSelection = function (element, callback) { 41 | var data = []; 42 | callback({ id: element.val(), text: element.val() }); 43 | } 44 | } 45 | select.select2(options) 46 | }); 47 | }; 48 | 49 | $(document).ready(function() { 50 | $.validate({modules: 'security', form: "#new_user, #edit_user"}); 51 | $('[data-toggle="tooltip"]').tooltip(); 52 | 53 | $('.activities li a[data-toggle="tab"]').on('show.bs.tab', function (e) { 54 | $('.activities li.active').removeClass('active'); 55 | }) 56 | }); 57 | -------------------------------------------------------------------------------- /spec/models/activity_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Activity do 4 | 5 | describe "#next_question_for(assessment)" do 6 | let (:assessment) { FactoryGirl.create(:unfinished_assessment) } 7 | let (:activity) do 8 | activity = FactoryGirl.create(:activity) 9 | activity.questions.create(FactoryGirl.attributes_for(:question)) 10 | activity.questions.create(FactoryGirl.attributes_for(:question, code: "q2")) 11 | activity.questions.create(FactoryGirl.attributes_for(:question, code: "q3")) 12 | activity 13 | end 14 | let (:positive_answer) { FactoryGirl.create(:answer) } 15 | let (:negative_answer) { FactoryGirl.create(:negative_answer) } 16 | 17 | context 'when no questions have been answered' do 18 | it "should return the first question for the activity" do 19 | expect(activity.next_question_for(assessment)).to eq(activity.questions.order(:id).first) 20 | end 21 | end 22 | 23 | context 'when a question has been answered positively' do 24 | it "should return the second question" do 25 | assessment.assessment_answers.create(question: activity.questions.order(:id).first, answer: positive_answer) 26 | expect(activity.next_question_for(assessment)).to eq(activity.questions.order(:id).second) 27 | end 28 | end 29 | end 30 | 31 | describe "creation" do 32 | 33 | context "valid attributes" do 34 | it "should be valid" do 35 | activity = FactoryGirl.build(:activity) 36 | activity.should be_valid 37 | end 38 | end 39 | 40 | context "invalid attributes" do 41 | it "should not be valid" do 42 | activity = FactoryGirl.build(:activity, name: "") 43 | activity.should_not be_valid 44 | 45 | activity = FactoryGirl.build(:activity, title: "") 46 | activity.should_not be_valid 47 | end 48 | 49 | it "should not support duplicates" do 50 | activity = FactoryGirl.build(:activity) 51 | activity.save 52 | activity2 = FactoryGirl.build(:activity) 53 | activity2.should_not be_valid 54 | end 55 | end 56 | 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/progress_calculator.rb: -------------------------------------------------------------------------------- 1 | class ProgressCalculator 2 | 3 | attr_reader :assessment 4 | 5 | def initialize(assessment) 6 | @assessment = assessment 7 | end 8 | 9 | #is the assessment complete? 10 | def completed? 11 | @assessment.status == :complete 12 | end 13 | 14 | def activity_completed?(activity) 15 | return progress_for_activity(activity) == :complete 16 | end 17 | 18 | #progress for a single activity 19 | def progress_for_activity(activity) 20 | #if there are no questions, then skipped 21 | return :skipped if activity.questions.empty? 22 | 23 | #find the assesssment_answers for all questions that are associated with this activity 24 | assessment_answers = AssessmentAnswer.joins(:assessment, question: :activity).where(assessment: @assessment.id, questions: {activity_id: activity.id}) 25 | 26 | #if there are non, then not started 27 | return :not_started if assessment_answers.empty? 28 | 29 | #if there are same number as questions, then completed 30 | return :complete if assessment_answers.length == activity.questions.length 31 | 32 | #if there are any negative answers, then completed 33 | assessment_answers.each do |aa| 34 | return :complete if !aa.answer.positive? 35 | end 36 | 37 | #otherwise in progress 38 | :in_progress 39 | end 40 | 41 | #summary of progress for all activities 42 | def progress_for_all_activities 43 | progress = {} 44 | Questionnaire.current.activities.each do |activity| 45 | progress[ activity.name ] = progress_for_activity(activity) 46 | end 47 | progress 48 | end 49 | 50 | #percentage completion across the entire maturity assessment 51 | def percentage_progress 52 | progress = progress_for_all_activities.reject{ |k,v| v == :skipped } 53 | completed = progress.values.count {|state| state == :complete } 54 | return (completed.to_f / progress.values.length.to_f * 100).to_i 55 | end 56 | 57 | #can we mark the assessment as completed? 58 | def can_mark_completed? 59 | progress_for_all_activities.reject{ |k,v| v == :skipped || v == :complete }.size == 0 60 | end 61 | 62 | end -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | <%= favicon_link_tag 'favicon.ico' %> 15 | 16 | <%= t :site_title %> | <%= yield :title %> 17 | 18 | <%= stylesheet_link_tag "application", :media => "all" %> 19 | <%= javascript_include_tag 'application' %> 20 | <%= csrf_meta_tags %> 21 | 22 | 23 | 24 | 25 | <%= render partial: 'layouts/header', :locals => { :title => t(:site_title) } %> 26 | 27 |
28 | <% if content_for?(:header) %> 29 | <%= yield :header %> 30 | <% elsif content_for?(:title) %> 31 |
32 |
33 |

<%= yield :title %>

34 | <% if content_for?(:breadcrumb) %> 35 | 36 | <% end %> 37 |
38 |
39 | <% end %> 40 | 41 |
42 | <% if notice %> 43 |

<%= notice %>

44 | <% end %> 45 | <% if alert %> 46 |

<%= alert %>

47 | <% end %> 48 | 49 |
50 | <%= yield %> 51 |
52 |
53 | 54 |
55 | 56 | <%= render partial: 'layouts/footer' %> 57 | 58 | <%= javascript_tag do %> 59 | <%= yield :javascript_footer %> 60 | <% end %> 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /app/views/statistics/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %>Statistics<% end %> 2 | 3 |
4 | 5 |
6 | 7 | 22 | 23 | 24 |
25 |
26 | <%= render 'organisations_tab', title: "all organisations", 27 | scorer: @scorer, results: @all_organisations, note: "" %> 28 |
29 |
30 | <%= render 'organisations_tab', title: "data.gov.uk organisations", 31 | scorer: @scorer, results: @dgu_organisations, note: "" %> 32 |
33 | <% if @parent_organisation.present? %> 34 |
35 | <%= render 'organisations_tab', title: "all peer organisations", 36 | scorer: @scorer, 37 | results: @peer_organisations, 38 | note: "Peer organisations are those that are in the #{@parent_organisation.title} group on data.gov.uk" %> 39 |
40 | <% end %> 41 |
42 | 43 |
44 | 45 |
46 | 47 | <% content_for :javascript_footer do %> 48 | $('.heatmapResults').tooltip({ 49 | selector: "*[rel=tooltip]" 50 | }) 51 | 52 | <% end %> 53 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | ruby "2.4.1" 3 | 4 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 5 | gem 'rails', '~> 4.2' 6 | 7 | # Bootstrap! 8 | gem 'bootstrap-sass', '~> 3.3' 9 | gem 'sass-rails', '~> 5.0' 10 | gem "font-awesome-rails" 11 | 12 | # Use Uglifier as compressor for JavaScript assets 13 | gem 'uglifier', '>= 3.2.0' 14 | # Use CoffeeScript for .coffee assets and views 15 | gem 'coffee-rails', '~> 4.2' 16 | 17 | # See https://github.com/sstephenson/execjs#readme for more supported runtimes 18 | # gem 'therubyracer', platforms: :ruby 19 | 20 | # Use jquery as the JavaScript library 21 | gem 'jquery-rails' 22 | # Add form validator plugin 23 | gem 'jquery-form-validator-rails' 24 | # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks 25 | gem 'turbolinks' 26 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 27 | gem 'jbuilder', '~> 2.7' 28 | # bundle exec rake doc:rails generates the API under doc/api. 29 | gem 'sdoc', '~> 0.4', group: :doc 30 | 31 | # Use ActiveModel has_secure_password 32 | # gem 'bcrypt', '~> 3.1.7' 33 | 34 | # Use Unicorn as the app server 35 | # gem 'unicorn' 36 | 37 | # Use Capistrano for deployment 38 | # gem 'capistrano-rails', group: :development 39 | 40 | gem 'devise', '~> 3.5' 41 | gem 'bcrypt', '~> 3.1' 42 | gem 'cancancan', '~> 2.0' 43 | gem 'spreadsheet' 44 | 45 | gem 'select2-rails', '~> 3.5' 46 | gem 'rack-google-analytics' 47 | 48 | gem 'high_voltage', '~> 3.0' 49 | 50 | group :development do 51 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console 52 | gem 'byebug' 53 | # Access an IRB console on exception pages or by using <%= console %> in views 54 | gem 'web-console', '~> 3.3' 55 | end 56 | 57 | group :development, :test do 58 | # Use sqlite3 as the database for Active Record 59 | gem 'sqlite3' 60 | 61 | gem 'rspec-rails', '~> 3.6' 62 | gem 'cucumber-rails', require: false 63 | gem 'poltergeist' 64 | gem 'factory_girl_rails' 65 | gem 'database_cleaner' 66 | gem 'simplecov', :group => :test 67 | 68 | gem 'dotenv-rails' 69 | end 70 | 71 | group :production do 72 | # Postgres on Heroku in production 73 | gem 'pg', '0.21.0' 74 | gem 'rails_12factor' # For heroku 75 | end 76 | 77 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw] 78 | -------------------------------------------------------------------------------- /app/views/assessments/_assessment_summary.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 |
    3 | <% if assessment.blank? %> 4 |
    0% complete
    5 | <% else %> 6 | <% if current && %> 7 |
    <%= ProgressCalculator.new(assessment).percentage_progress %>% complete
    8 | <% else %> 9 | 10 | <% end %> 11 | <% end %> 12 |
    13 | 14 |
    15 | <% if assessment.blank? %> 16 | <%= content_tag :h2, "Start a new assessment", class: "assessmentTitle" %> 17 | <% else %> 18 | <%= content_tag :h2, assessment.title, class: "assessmentTitle" %> 19 | 20 | 21 | <%= content_tag :span, "Started: #{pretty_date(assessment.start_date)}" %> 22 | 23 | 24 | <% if current %> 25 | <%= content_tag :span, "Last updated: #{pretty_date(assessment.updated_at)}" %> 26 | <% else %> 27 | <%= content_tag :span, "Completed: #{pretty_date(assessment.completion_date)}" %> 28 | <% end %> 29 | <% end %> 30 |
    31 | 32 |
    33 | <% if assessment.blank? %> 34 | <%= link_to begin_assessment_path, class: "btn green" do %> 35 | Start assessment 36 | <% end %> 37 | <% else %> 38 | <% if current %> 39 | <%= link_to assessment_path(assessment), class: "btn green", role: "button" do %> 40 | Continue assessment » 41 | <% end %> 42 | <% else %> 43 | <%= link_to report_path(assessment), class: "btn btn-default", role: "button" do %> 44 | View assessment » 45 | <% end %> 46 | <% end %> 47 | <%= link_to assessment_path(assessment), method: :delete, data: { confirm: "Are you sure?" }, class: "btn red" do %> 48 | Delete this assessment 49 | <% end %> 50 | <% end %> 51 |
    52 |
  • 53 | -------------------------------------------------------------------------------- /spec/controllers/registrations_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe RegistrationsController do 4 | 5 | before(:each) do 6 | request.env['devise.mapping'] = Devise.mappings[:user] 7 | end 8 | 9 | describe "GET #new" do 10 | it "should new user to view the sign up page" do 11 | get :new 12 | expect(response).to be_success 13 | end 14 | end 15 | 16 | describe "POST #create" do 17 | attrs = FactoryGirl.attributes_for(:user, associated_organisation: "DoSAC") 18 | it "should allow a new user to be created with a new organisation" do 19 | expect{ 20 | post :create, user: attrs 21 | }.to change(User,:count).by(1) 22 | end 23 | 24 | it "should create a new organisation for the user" do 25 | attrs = FactoryGirl.attributes_for(:user, associated_organisation: "DoSAC") 26 | expect{ 27 | post :create, user: attrs 28 | }.to change(Organisation,:count).by(1) 29 | end 30 | 31 | it "should create a new user, but not a new country" do 32 | attrs = FactoryGirl.attributes_for(:user, associated_country: "foobar") 33 | expect{ 34 | post :create, user: attrs 35 | }.to change(User,:count).by(1).and change(Country,:count).by(0) 36 | end 37 | 38 | it "should allow a new user to be created with an existing organisation" do 39 | FactoryGirl.create(:organisation) 40 | expect{ 41 | post :create, user: FactoryGirl.attributes_for(:user), associated_organisation: "Department for Environment, Food and Rural Affairs" 42 | }.to change(User,:count).by(1) 43 | end 44 | 45 | it "should allow a new user to be created with an existing country" do 46 | FactoryGirl.create(:organisation) 47 | expect{ 48 | post :create, user: FactoryGirl.attributes_for(:user), associated_country: "United Kingdom" 49 | }.to change(User,:count).by(1) 50 | end 51 | 52 | it "should allow a new user to be created without an organisation" do 53 | expect{ 54 | post :create, user: FactoryGirl.attributes_for(:user), associated_organisation: "" 55 | }.to change(User,:count).by(1) 56 | end 57 | 58 | it "should allow a new user to be created without a country" do 59 | expect{ 60 | post :create, user: FactoryGirl.attributes_for(:user), associated_country: "" 61 | }.to change(User,:count).by(1) 62 | end 63 | end 64 | 65 | end 66 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports and disable caching. 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send. 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger. 20 | config.active_support.deprecation = :log 21 | 22 | # Raise an error on page load if there are pending migrations. 23 | config.active_record.migration_error = :page_load 24 | 25 | # Debug mode disables concatenation and preprocessing of assets. 26 | # This option may cause significant delays in view rendering with a large 27 | # number of complex assets. 28 | config.assets.debug = true 29 | 30 | # Asset digests allow you to set far-future HTTP expiration dates on all assets, 31 | # yet still be able to expire them through the digest params. 32 | config.assets.digest = true 33 | 34 | # Adds additional error checking when serving assets at runtime. 35 | # Checks for improperly declared sprockets dependencies. 36 | # Raises helpful error messages. 37 | config.assets.raise_runtime_errors = true 38 | 39 | # Raises error for missing translations 40 | # config.action_view.raise_on_missing_translations = true 41 | 42 | config.action_mailer.default_url_options = { :host => 'localhost:3000' } 43 | 44 | config.action_mailer.smtp_settings = { 45 | :address => "smtp.mandrillapp.com", 46 | :port => 2525, # ports 587 and 2525 are also supported with STARTTLS 47 | :enable_starttls_auto => true, # detects and uses STARTTLS 48 | :user_name => ENV["MANDRILL_USERNAME"], 49 | :password => ENV["MANDRILL_APIKEY"], # SMTP password is any valid API key 50 | :authentication => 'plain', # Mandrill supports 'plain' or 'login' 51 | } 52 | config.action_mailer.perform_deliveries = true 53 | config.action_mailer.raise_delivery_errors = true 54 | end 55 | -------------------------------------------------------------------------------- /app/controllers/assessments_controller.rb: -------------------------------------------------------------------------------- 1 | class AssessmentsController < ApplicationController 2 | def index 3 | @current_assessment = current_user.current_assessment 4 | @assessments = current_user.assessments.completed.order(completion_date: :desc) 5 | @last_assessment = @assessments.first 6 | end 7 | 8 | def begin 9 | if current_user.current_assessment.blank? 10 | authorize! :create, Assessment 11 | @assessment = current_user.assessments.create(title: "New assessment", start_date: Time.now) 12 | @dimensions = Questionnaire.current.dimensions 13 | @progress = ProgressCalculator.new(@assessment) 14 | render 'show' 15 | else 16 | redirect_to assessment_path(current_user.current_assessment) 17 | end 18 | end 19 | 20 | def edit 21 | @assessment = current_user.assessments.find(params[:id]) 22 | authorize! :update, @assessment 23 | end 24 | 25 | def update 26 | @assessment = current_user.assessments.find(params[:id]) 27 | authorize! :update, @assessment 28 | if @assessment.update_attributes(assessment_params) 29 | redirect_to assessment_path(@assessment) 30 | else 31 | render 'edit' 32 | end 33 | end 34 | 35 | def show 36 | @assessment = Assessment.find(params[:id]) 37 | authorize! :read, @assessment 38 | @dimensions = Questionnaire.current.dimensions 39 | @progress = ProgressCalculator.new(@assessment) 40 | end 41 | 42 | def destroy 43 | @assessment = current_user.assessments.find(params[:id]) 44 | authorize! :destroy, @assessment 45 | @assessment.destroy 46 | redirect_to assessments_path 47 | end 48 | 49 | def complete 50 | @assessment = current_user.assessments.find(params[:id]) 51 | authorize! :update, @assessment 52 | @assessment.complete 53 | redirect_to report_path(@assessment) 54 | end 55 | 56 | def report 57 | @assessment = Assessment.find(params[:id]) 58 | @dimensions = Questionnaire.current.dimensions 59 | @scorer = AssessmentScorer.new(@assessment) 60 | @token = params[:token] 61 | authorize! :read, @assessment 62 | 63 | respond_to do |format| 64 | format.html { 65 | render 'report' 66 | } 67 | format.csv { 68 | send_data @assessment.to_csv( params[:style].to_sym ), content_type: "text/csv; charset=utf-8" 69 | } 70 | end 71 | end 72 | 73 | private 74 | 75 | def assessment_params 76 | params.require(:assessment).permit(:title, :notes) 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /features/report.feature: -------------------------------------------------------------------------------- 1 | Feature: Viewing assessment reports 2 | 3 | Background: 4 | Given the test survey has been loaded 5 | Given I am logged in as a user 6 | Given the following assessments: 7 | | title | notes | start_date | completion_date | 8 | | 2014 Q4 | End of last year | 2015-02-10 11:07:10 | | 9 | And the current assessment is completed 10 | 11 | Scenario: I should see all the tabs 12 | When I go to "/assessments/1/report" 13 | Then I should see "Summary" 14 | And I should see "Maturity scores" 15 | And I should see "Assessment answers" 16 | And I should see "Suggested improvements" 17 | And I should see "Background notes" 18 | And I should see a link called "Download summary scores" to "/assessments/1/report.csv?style=dimension" 19 | 20 | Scenario: I should see the activity scores 21 | When I go to "/assessments/1/report" 22 | Then there should be "5" themes in the "activities" section 23 | And there should be "4" items listed in "#data-management-processes-activities" 24 | Then the element with id "#data-release-process-score" should have the content "1" 25 | And I should see a link called "Download activity scores" to "/assessments/1/report.csv?style=activity" 26 | 27 | Scenario: I should see the report detail 28 | When I go to "/assessments/1/report" 29 | Then the element with id "#Q1-text" should have the content "Have you published any open data?" 30 | And the element with id "#Q1-answer" should have the content "No, we have not yet published any open data" 31 | And there should be "4" items listed in "#data-management-processes-detail" 32 | 33 | Scenario: I should see the report improvements 34 | When I go to "/assessments/1/report" 35 | Then the element with id "#I1" should have the content "Publish at least one open dataset with an open data certificate" 36 | 37 | Scenario: I should see the report information 38 | When I go to "/assessments/1/report" 39 | Then the element with id "#assessor" should have the content "Peter Manion" 40 | Then the element with id "#start-date" should have the content "Tuesday, 10th February 2015" 41 | 42 | Scenario: Obtaining a sharing link 43 | When I go to "/assessments/1/report" 44 | Then I should see a link to share the report 45 | 46 | Scenario: Token doesn't show in report download query string when logged in 47 | When I go to "/assessments/1/report" 48 | Then the CSV link should not contain a token 49 | -------------------------------------------------------------------------------- /spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | ENV['RAILS_ENV'] ||= 'test' 3 | require File.expand_path('../../config/environment', __FILE__) 4 | require 'spec_helper' 5 | require 'rspec/rails' 6 | # Add additional requires below this line. Rails is not loaded until this point! 7 | 8 | # Requires supporting ruby files with custom matchers and macros, etc, in 9 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are 10 | # run as spec files by default. This means that files in spec/support that end 11 | # in _spec.rb will both be required and run as specs, causing the specs to be 12 | # run twice. It is recommended that you do not name files matching this glob to 13 | # end with _spec.rb. You can configure this pattern with the --pattern 14 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`. 15 | # 16 | # The following line is provided for convenience purposes. It has the downside 17 | # of increasing the boot-up time by auto-requiring all files in the support 18 | # directory. Alternatively, in the individual `*_spec.rb` files, manually 19 | # require only the support files necessary. 20 | # 21 | # Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } 22 | 23 | # Checks for pending migration and applies them before tests are run. 24 | # If you are not using ActiveRecord, you can remove this line. 25 | ActiveRecord::Migration.maintain_test_schema! 26 | 27 | RSpec.configure do |config| 28 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 29 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 30 | 31 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 32 | # examples within a transaction, remove the following line or assign false 33 | # instead of true. 34 | config.use_transactional_fixtures = true 35 | 36 | # RSpec Rails can automatically mix in different behaviours to your tests 37 | # based on their file location, for example enabling you to call `get` and 38 | # `post` in specs under `spec/controllers`. 39 | # 40 | # You can disable this behaviour by removing the line below, and instead 41 | # explicitly tag your specs with their type, e.g.: 42 | # 43 | # RSpec.describe UsersController, :type => :controller do 44 | # # ... 45 | # end 46 | # 47 | # The different available types are documented in the features, such as in 48 | # https://relishapp.com/rspec/rspec-rails/docs 49 | config.infer_spec_type_from_file_location! 50 | end 51 | -------------------------------------------------------------------------------- /app/views/targets/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %>Goals for next assessment<% end %> 2 | 3 |
    4 | 5 | <%= form_tag assessment_targets_path(@assessment), method: :patch do %> 6 | 7 |
    8 | <%= render 'assessments/theme_label' %> 9 | 10 | <%= render 'assessments/activity_label' %> 11 | <%= render 'assessments/score_label' %> 12 | <%= render 'assessments/next_goal_label' %> 13 | 14 |
    15 | 16 | <% for dimension in @dimensions %> 17 |
    18 |

    <%= dimension.title %>

    19 | 20 | 36 |
    37 | <% end %> 38 | 39 | <%= submit_tag "Save goals", class: "btn btn-primary next pull-right", id: "submit-bottom" %> 40 | <% end %> 41 |
    42 | 43 | <% content_for :javascript_footer do %> 44 | $(function() { 45 | $( "span.more" ).click(function() { 46 | if ( $(this).parent().children('input.yourGoal').val() < 5 ) { 47 | $(this).parent().children('input.yourGoal').val(function(i, oldval) { 48 | return ++oldval; 49 | }) 50 | } 51 | }); 52 | $( "span.less" ).click(function() { 53 | if ( $(this).parent().children('input.yourGoal').val() > 1 ) { 54 | $(this).parent().children('input.yourGoal').val(function(i, oldval) { 55 | return --oldval; 56 | }); 57 | } 58 | }) 59 | }) 60 | <% end %> 61 | -------------------------------------------------------------------------------- /spec/models/user_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require "cancan/matchers" 3 | 4 | describe User do 5 | 6 | describe "#associated_organisation=" do 7 | it "should create a valid organisation and associate it with the user" do 8 | user = FactoryGirl.build(:user) 9 | user.associated_organisation = "Department of Social Affairs and Citizenship" 10 | expect(user.associated_organisation.persisted?).to be_truthy 11 | end 12 | end 13 | 14 | describe "#associated_country=" do 15 | it "should create a valid country and associate it with the user" do 16 | user = FactoryGirl.build(:user) 17 | country = FactoryGirl.create(:country) 18 | user.country = country 19 | expect(user.associated_country.persisted?).to be_truthy 20 | end 21 | end 22 | 23 | describe '#current_assessment' do 24 | it "should return the asssessment that has not been completed" do 25 | user = FactoryGirl.create(:user) 26 | a = user.assessments.create(FactoryGirl.attributes_for(:unfinished_assessment)) 27 | expect(user.current_assessment).to eql(a) 28 | end 29 | 30 | it "should return nil when all assessments have been completed" do 31 | user = FactoryGirl.create(:user) 32 | a = user.assessments.create(FactoryGirl.attributes_for(:assessment)) 33 | expect(user.current_assessment).to eql(nil) 34 | end 35 | end 36 | 37 | describe "creation" do 38 | context "valid attributes" do 39 | it "should be valid" do 40 | user = FactoryGirl.build(:user) 41 | expect(user).to be_valid 42 | end 43 | end 44 | 45 | context "invalid attributes" do 46 | it "should not be valid" do 47 | user = FactoryGirl.build(:user, email: "") 48 | expect(user).to_not be_valid 49 | end 50 | 51 | it "should not allow more than one user to be associated with the same organisation" do 52 | user = FactoryGirl.build(:user) 53 | organisation = FactoryGirl.create(:organisation) 54 | user.organisation = organisation 55 | user.save 56 | 57 | user2 = FactoryGirl.build(:user, email: "user2@example.org") 58 | user2.associated_organisation = "Department for Environment, Food and Rural Affairs" 59 | expect(user2).to_not be_valid 60 | end 61 | end 62 | end 63 | 64 | describe 'abilities' do 65 | let(:user) { FactoryGirl.create(:user) } 66 | let(:assessment) { user.assessments.create(FactoryGirl.attributes_for(:assessment)) } 67 | 68 | subject(:ability) { Ability.new(user) } 69 | 70 | it { should be_able_to :manage, assessment } 71 | end 72 | 73 | end 74 | -------------------------------------------------------------------------------- /lib/tasks/cucumber.rake: -------------------------------------------------------------------------------- 1 | # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. 2 | # It is recommended to regenerate this file in the future when you upgrade to a 3 | # newer version of cucumber-rails. Consider adding your own code to a new file 4 | # instead of editing this one. Cucumber will automatically load all features/**/*.rb 5 | # files. 6 | 7 | 8 | unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks 9 | 10 | vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first 11 | $LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil? 12 | 13 | begin 14 | require 'cucumber/rake/task' 15 | 16 | namespace :cucumber do 17 | Cucumber::Rake::Task.new({:ok => 'test:prepare'}, 'Run features that should pass') do |t| 18 | t.binary = vendored_cucumber_bin # If nil, the gem's binary is used. 19 | t.fork = true # You may get faster startup if you set this to false 20 | t.profile = 'default' 21 | end 22 | 23 | Cucumber::Rake::Task.new({:wip => 'test:prepare'}, 'Run features that are being worked on') do |t| 24 | t.binary = vendored_cucumber_bin 25 | t.fork = true # You may get faster startup if you set this to false 26 | t.profile = 'wip' 27 | end 28 | 29 | Cucumber::Rake::Task.new({:rerun => 'test:prepare'}, 'Record failing features and run only them if any exist') do |t| 30 | t.binary = vendored_cucumber_bin 31 | t.fork = true # You may get faster startup if you set this to false 32 | t.profile = 'rerun' 33 | end 34 | 35 | desc 'Run all features' 36 | task :all => [:ok, :wip] 37 | 38 | task :statsetup do 39 | require 'rails/code_statistics' 40 | ::STATS_DIRECTORIES << %w(Cucumber\ features features) if File.exist?('features') 41 | ::CodeStatistics::TEST_TYPES << "Cucumber features" if File.exist?('features') 42 | end 43 | end 44 | desc 'Alias for cucumber:ok' 45 | task :cucumber => 'cucumber:ok' 46 | 47 | task :default => :cucumber 48 | 49 | task :features => :cucumber do 50 | STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***" 51 | end 52 | 53 | # In case we don't have the generic Rails test:prepare hook, append a no-op task that we can depend upon. 54 | task 'test:prepare' do 55 | end 56 | 57 | task :stats => 'cucumber:statsetup' 58 | rescue LoadError 59 | desc 'cucumber rake task not available (cucumber not installed)' 60 | task :cucumber do 61 | abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' 62 | end 63 | end 64 | 65 | end 66 | -------------------------------------------------------------------------------- /app/views/assessments/_overview.html.erb: -------------------------------------------------------------------------------- 1 |
    2 |
    Theme 6 | 7 |
    8 |
    9 |
    Activity 13 | 14 |
    15 |
    16 |
    17 | 18 | <% for dimension in @dimensions %> 19 |
    20 |
    21 |
    "><%= dimension.title %>
    25 |

    26 | <%= content_tag :span, "#{dimension.questions.count} questions", class: ""%> 27 |

    28 |
    29 |
    30 | 31 | <% for activity in dimension.activities %> 32 | <% status = progress.progress_for_activity(activity) %> 33 | <%= content_tag :div, class: "row activity #{status}" do %> 34 |
    <%= activity.title %>
    35 |
    36 | <% next_question = activity.next_question_for(@assessment) %> 37 | <% case status %> 38 | <% when :not_started %> 39 | <%= link_to t(status), assessment_question_path(@assessment, next_question), class: "btn green" %> 40 | <% when :in_progress %> 41 | <%= link_to t(status), assessment_question_path(@assessment, next_question), class: "btn orange" %> 42 | <% when :complete %> 43 | <% answer = @assessment.assessment_answers.where(question_id: activity.questions.order(:id).pluck(:id).first).first %> 44 | <%= link_to "Edit", assessment_edit_answer_path(@assessment, answer), class: "btn orange", title: t(status) %> 45 | <% end %> 46 | <% end %> 47 |
    48 | <% end %> 49 | 50 |
    51 |
    52 | <% end %> 53 | -------------------------------------------------------------------------------- /features/step_definitions/assessment_steps.rb: -------------------------------------------------------------------------------- 1 | Given(/^the following assessments:$/) do |table| 2 | table.hashes.each do |attributes| 3 | attributes.merge!(user_id: @current_user.id) unless attributes[:user_id].present? 4 | complete = attributes.delete("completed") 5 | assessment = FactoryGirl.create(:assessment, attributes) 6 | if complete == "yes" 7 | AssessmentAnswer.create( assessment: assessment, question: Question.first, answer: Answer.find_by_code("Q1.2") ) 8 | assessment.complete 9 | end 10 | end 11 | end 12 | 13 | Given(/^the current assessment is ready for completion$/) do 14 | AssessmentAnswer.create( assessment: @current_user.current_assessment, question: Question.first, answer: Answer.find_by_code("Q1.2") ) 15 | end 16 | 17 | When(/^I complete the assessment$/) do 18 | all('.complete').first.click 19 | end 20 | 21 | When(/^I delete an assessment$/) do 22 | all('.assessment')[0].first(:link, "Delete").click 23 | end 24 | 25 | Then(/^I should see "(.*?)" assessments$/) do |count| 26 | expect(page).to have_selector('.assessment', count: count) 27 | end 28 | 29 | Given(/^the current assessment is completed$/) do 30 | AssessmentAnswer.create( assessment: @current_user.current_assessment, question: Question.first, answer: Answer.find_by_code("Q1.2") ) 31 | @current_user.current_assessment.complete 32 | end 33 | 34 | Then(/^the element with id "(.*?)" should have the content "(.*?)"$/) do |selector, text| 35 | page.assert_selector(selector, :text => text) 36 | end 37 | 38 | When(/^there should be "(.*?)" themes in the "(.*?)" section$/) do |count, section| 39 | page.assert_selector(".activities .theme", :count => count.to_i) 40 | end 41 | 42 | Then(/^there should be "(.*?)" items listed in "(.*?)"$/) do |count, selector| 43 | page.assert_selector("#{selector} li", :count => count.to_i) 44 | end 45 | 46 | Then(/^I should see a link to share the report$/) do 47 | page.assert_selector("#share-report-link") 48 | end 49 | 50 | When(/^I click on the sharing link for the "(.*?)" assessment$/) do |title| 51 | assessment = Assessment.where(title: title).first 52 | path = "/assessments/#{assessment.id}/report?token=#{assessment.token}" 53 | visit path 54 | end 55 | 56 | When(/^I click on the "(.*?)" link$/) do |text| 57 | click_link text 58 | end 59 | 60 | Then(/^the response should be "(.*?)"$/) do |code| 61 | expect(page.status_code).to eq(code.to_i) 62 | end 63 | 64 | Then(/^I should see a CSV$/) do 65 | expect(page.response_headers['Content-Type']).to match /text\/csv/ 66 | end 67 | 68 | Then(/^the CSV link should not contain a token$/) do 69 | link = find("a", text: /Download summary scores/) 70 | 71 | expect(link[:href]).to_not match(/token=/) 72 | end 73 | -------------------------------------------------------------------------------- /app/views/devise/registrations/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %><%= t :sign_up_page %><% end %> 2 | 3 |
    4 |
    5 |
    6 | Register for the Open Data Pathway to record your maturity assessment scores and targets. 7 |
      8 |
    • Your results are private unless you decide to share. 9 |
    • Each organisation can have only one account. 10 |
    11 |
    12 | <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> 13 | <%= devise_error_messages! %> 14 |

    * Required field

    15 |
    16 | <%= f.label :associated_organisation %><%= t :organisation_registration %>
    17 | <%= f.hidden_field :associated_organisation, class: 'select2 ajax', data: { source: organisations_path(format: :json) }, style: "width:40%;" %> 18 |
    19 | 20 |
    21 | <%= f.label :associated_country, class: "required" %><%= t :country_registration %>
    22 | <%= f.hidden_field :associated_country, value: resource.country.to_s, "data-validation": "required", "data-validation-error-msg": t(:country_validation), class: 'select2 ajax', data: { source: countries_path(format: :json) }, style: "width:40%;" %> 23 |
    24 | 25 |
    26 | <%= f.label :name, class: "required" %>
    27 | <%= f.text_field :name, "data-validation": "required", "data-validation-error-msg": t(:name_validation), style: "width:40%;" %> 28 |
    29 | 30 |
    31 | <%= f.label :email, class: "required" %>
    32 | <%= f.email_field :email, "data-validation": "email", "data-validation-error-msg": t(:enter_email), style: "width:40%;" %> 33 |
    34 | 35 | <%= render "devise/shared/password", f: f %> 36 | 37 |
    38 | <%= f.label :terms_of_service do %> 39 | <%= f.check_box :terms_of_service, "data-validation": "required", "data-validation-error-msg": t(:accept_terms) %> 40 | I accept the Terms of use 41 | <% end %> 42 | 43 |
    44 | 45 |
    46 |
    47 | <%= f.submit t(:sign_up), class: "btn green" %> 48 |
    49 | 50 |
    51 | <%= render "devise/shared/links" %> 52 |
    53 |
    54 | <% end %> 55 | 56 | 57 |
    58 |
    59 | 60 | <% content_for :javascript_footer do %> 61 | $(document).ready(function(){ 62 | attachTypeAhead(); 63 | }); 64 | <% end %> 65 | -------------------------------------------------------------------------------- /lib/questionnaire_importer.rb: -------------------------------------------------------------------------------- 1 | class QuestionnaireImporter 2 | 3 | def self.load(version, config, notes="") 4 | questionnaire = create_questionnaire(version, notes) 5 | book = Spreadsheet.open config 6 | populate_activities(questionnaire, book.worksheet('activities') ) 7 | populate_answers(questionnaire, book.worksheet('questions') ) 8 | populate_improvements(questionnaire, book.worksheet('improvements') ) 9 | end 10 | 11 | def self.update(version, config) 12 | questionnaire = Questionnaire.find_by_version(version) 13 | book = Spreadsheet.open config 14 | populate_activities(questionnaire, book.worksheet('activities') ) 15 | populate_answers(questionnaire, book.worksheet('questions') ) 16 | populate_improvements(questionnaire, book.worksheet('improvements') ) 17 | end 18 | 19 | def self.create_questionnaire(version, notes="") 20 | Questionnaire.create(version: version, notes: notes) 21 | end 22 | 23 | def self.populate_activities(questionnaire, worksheet) 24 | worksheet.each 1 do |row| 25 | dimension = Dimension.find_or_create_by(questionnaire_id: questionnaire.id, name: create_slug(row[0])) 26 | dimension.title = row[0] 27 | dimension.save 28 | activity = Activity.find_or_create_by(questionnaire_id: questionnaire.id, dimension_id: dimension.id, name: create_slug(row[1])) 29 | activity.title = row[1] 30 | activity.save 31 | end 32 | end 33 | 34 | def self.populate_answers(questionnaire, worksheet) 35 | question = nil 36 | activity = nil 37 | worksheet.each 1 do |row| 38 | if !row[0].blank? 39 | activity = Activity.find_by_name( create_slug( row[2] ) ) 40 | question = Question.find_or_create_by(questionnaire_id: questionnaire.id, code: row[0], activity: activity) 41 | question.update_attributes( { 42 | text: row[3], 43 | notes: row[4], 44 | dependency_id: row[5].blank? ? nil : Question.find_by_code( row[5] ).id 45 | }) 46 | question.save 47 | end 48 | answer = Answer.find_or_create_by(questionnaire_id: questionnaire.id, question: question, code: row[6]) 49 | answer.update_attributes( { 50 | text: row[7], 51 | positive: row[8] == "Y", 52 | score: row[9].blank? ? nil : row[9].to_i 53 | }) 54 | answer.save! 55 | end 56 | end 57 | 58 | def self.populate_improvements(questionnaire, worksheet) 59 | worksheet.each 1 do |row| 60 | answer = Answer.find_by_code( row[1] ) 61 | improvement = Improvement.find_or_create_by( answer: answer, code: row[0] ) 62 | improvement.update_attributes({ 63 | notes: row[2] 64 | }) 65 | improvement.save 66 | end 67 | end 68 | 69 | def self.create_slug(title) 70 | title.parameterize 71 | end 72 | end -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Open Data Pathway 2 | 3 | Open Data Pathway is open source, and contributions are gratefully accepted! 4 | Details on how to contribute are below. By participating in this project, you agree to abide by our [Code of Conduct](https://github.com/theodi/pathway/blob/CODE_OF_CONDUCT.md). 5 | 6 | Before you start coding on an issue, please reach out to us either on our [gitter channel](https://gitter.im/theodi/toolbox) or leave a comment on the issue ticket you are interested in contributing towards to indicate your interest in helping. 7 | 8 | If this is your first time contributing to the ODI’s codebase you will need to [create a fork of this repository](https://help.github.com/articles/fork-a-repo/). 9 | 10 | Consult our [Getting Started Guide](https://github.com/theodi/toolbox/wiki/Developers-Guide:-Getting-Started) (if necessary) and then follow the [readme instructions](https://github.com/theodi/pathway/blob/master/README.md#development) to get your Development environment running locally 11 | 12 | Ensure that the [tests](https://github.com/theodi/pathway/blob/master/README.md#tests) pass before working on your contribution 13 | 14 | ## Code Review Process 15 | 16 | All contributions to the codebase - whether fork or pull request - will be reviewed per the below criteria. 17 | To increase your chances of your push being accepted please be aware of the following 18 | - Write [well formed commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 19 | - Follow our [style guide recommendations](https://github.com/theodi/toolbox/blob/README.md#code-style-guide) 20 | - Write tests for all changes (additions or refactors of existing code). 21 | - Of the github integrations we use two will be utilised to check appraise your contribution. In order of priority these are 22 | - Travis ensures that all tests (existing and additions) pass 23 | - Travis/Coveralls ensures that overall test coverage for lines of code meets a certain threshold. If this metric dips below what it previously was for the repository you’re pushing to then your PR will be rejected 24 | - Gemnasium ensures dependencies are up to date 25 | - Once your PR is published and passes the above checks a repository administrator will review your contribution. Where appropriate comments may be provided and amendments suggested before your PR is merged into Master. 26 | - Once your PR is accepted you will be granted push access to the repository you have contributed to! Congratulations on joining our community, you’ll no longer need to work from forks. 27 | 28 | If you make a contribution to another repository in the Toolbox you will be expected to repeat this process. Read more about that [here](https://github.com/theodi/toolbox/blob/master/README.md#push-access). 29 | 30 | ## Code Style Guide 31 | 32 | We follow the same code style conventions as detailed in Github’s [Ruby Style Guide](https://github.com/github/rubocop-github/blob/master/STYLEGUIDE.md) 33 | -------------------------------------------------------------------------------- /app/views/assessments/report.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title do %> 2 | <%= @assessment.user.organisation ? @assessment.user.organisation.title : "" %> <%= @assessment.title %> 3 | <% end %> 4 | <% content_for :breadcrumb do %> 5 | <%= breadcrumb("Report") %> 6 | <% end %> 7 | 8 | <% if User.can_share?(current_user, @assessment) %> 9 | <%= render 'share_modal', assessment: @assessment %> 10 | <% end %> 11 | 12 |
    13 | 14 |
    15 | 16 | 31 | 32 | 33 |
    34 |
    35 | <%= render 'summary_tab', assessment: @assessment, scorer: @scorer %> 36 |
    37 |
    38 | <%= render 'activity_tab', assessment: @assessment %> 39 |
    40 |
    41 | <%= render 'detail_tab', assessment: @assessment %> 42 |
    43 |
    44 | <%= render 'improvements_tab', assessment: @assessment %> 45 |
    46 |
    47 | <%= render 'information_tab', assessment: @assessment %> 48 |
    49 |
    50 | 51 |
    52 | 53 |
    54 | 55 | <% if User.can_share?(current_user, @assessment) %> 56 | <% content_for :javascript_footer do %> 57 | $(document).ready(function(){ 58 | $('#share-modal').modal() 59 | }); 60 | <% end %> 61 | <% end %> 62 | 63 | -------------------------------------------------------------------------------- /app/views/assessments/_improvements_tab.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 | <%= render 'theme_label' %> 5 |

    Activity

    6 |

    Improvements 11 | 12 |

    13 |
    14 | 15 | 16 |
    17 | <% @dimensions.each_with_index do |dimension, dim_index| %> 18 |
    19 |

    <%= dimension.title %>

    20 | 25 |
    26 | <% end %> 27 |
    28 | 29 |
    30 | <% @dimensions.each_with_index do |dimension, dim_index| %> 31 | <% dimension.activities.each_with_index do |activity, index| %> 32 |
    33 | 34 | <% activity.questions.each do |question| %> 35 | <% assessment_answer = assessment.answer_for_question(question) %> 36 | <% if assessment_answer && assessment_answer.answer.improvements.present? %> 37 |
    38 |

    <%= question.text %>

    39 |

    40 | <%= assessment_answer.answer.text %> 41 |

    42 | 43 |
    44 | <% if assessment_answer.answer.improvements.empty? %> 45 |

    No improvements necessary

    46 | <% else %> 47 |
      48 | <% assessment_answer.answer.improvements.order(:id).each do |improvement| %> 49 |
    1. <%= improvement.notes %>
    2. 50 | <% end %> 51 |
    52 | <% end %> 53 | 54 |
    55 |
    56 | <% end %> 57 | <% end %> 58 | 59 |
    60 | <% end %> 61 | <% end %> 62 |
    63 | 64 |
    -------------------------------------------------------------------------------- /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 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | site_title: "Open Data Pathway" 24 | 25 | #Authentication & Registration 26 | sign_up_page: "Registration" 27 | sign_up: "Register" 28 | sign_up_now: "Register now?" 29 | sign_in: "Sign in" 30 | sign_in_now: "Sign in here" 31 | sign_out: "Sign out" 32 | account: "Account" 33 | admin: "Admin" 34 | remember_me: "Keep me signed in" 35 | #Assessments 36 | my_assessments: "My assessments" 37 | 38 | not_started: "Start" 39 | in_progress: "Continue" 40 | complete: "Complete" 41 | 42 | enter_email: "Please enter a valid email address" 43 | accept_terms: "Please check this box if you want to proceed" 44 | name_validation: "Please enter your name" 45 | 46 | password_confirmation: "The password doesn't match" 47 | password_validation: "Your password must be at least 8 characters" 48 | country_validation: "Please enter your country" 49 | 50 | helpers: 51 | label: 52 | user: 53 | email: "Email" 54 | name: "Full name" 55 | associated_organisation: "Organisation" 56 | associated_country: "Country" 57 | 58 | organisation_registration: " (check if your organisation already has an account)" 59 | country_registration: " (we use your country to create aggregate statistics)" 60 | data-management-processes: "key business processes that underpin data management and publication, e.g. quality control, publication workflows, and the adoption of technical standards" 61 | knowledge-skills: "the culture of open data within an organisation by identifying the knowledge sharing, training and learning required to embed an understanding of the benefits of open data" 62 | customer-support-engagement: "the manner in which an organisation engages with both their data sources and their data re-users to provide sufficient support and feedback to make open data successful" 63 | investment-financial-performance: "the level of knowledge an organisation has about the value of their datasets and the budgetary and financial oversight required to support their publication. For data consumers, it covers their understanding of the costs and value associated with the reuse of third-party datasets" 64 | strategic-oversight: "an organisation's strategy for data sharing and reuse, and the leadership in place to deliver that strategy" 65 | --------------------------------------------------------------------------------