diff --git a/.gitignore b/.gitignore index 2b59cc6..d6d744a 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ # Ignore database configuration and token secrets config/database.yml config/secrets.yml +config/branding.yml # Ignore some of the initializers config/initializers/recaptcha.rb @@ -60,3 +61,7 @@ # ignore yard generated documents /doc/* !/doc/README_FOR_APP + +# ignore auto-generated gettext files when running gettext:find +config/locale/*/app.edit.po +config/locale/*/app.po.time_stamp \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index bc14e2d..453b68d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,10 +5,13 @@ before_script: - cp config/database_example.yml config/database.yml - cp config/secrets_example.yml config/secrets.yml + - cp config/branding_example.yml config/branding.yml - cp config/initializers/devise.rb.example config/initializers/devise.rb - cp config/initializers/recaptcha.rb.example config/initializers/recaptcha.rb - cp config/initializers/wicked_pdf.rb.example config/initializers/wicked_pdf.rb - - bundle exec rake db:migrate RAILS_ENV=test + - bundle exec rake db:drop RAILS_ENV=test + - bundle exec rake db:create RAILS_ENV=test + - bundle exec rake db:schema:load RAILS_ENV=test script: - bundle exec rake test diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c1617b1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,127 @@ +## Introduction +The goal of the DMPRoadmap project is to provide the community with a reliable and stable platform for managing data management plans. This means that all development efforts should adhere to some basic tenets to ensure that the system remains stable and provides functionality for the community as a whole. + +These guidelines are an attempt to ensure that we are able to provide the community with a reliable system, stable APIs, a clear roadmap, and a predictable release schedule. + +* If you would like to contribute to the project. Please follow these steps to submit a contribution: + * Comment on the Github issue (or create one if one does not exist) and let us know that you're working on it. + * Fork the project (if you have not already) or rebase your fork so that it is up to date with the current repository's '_**development**_' branch + * Create a new branch in your fork. This will ensure that you are able to work at your own pace and continue to pull in any updates made to this project. + * Make your changes in the new branch + * When you have finished your work, make sure that your version of the '_**development**_' branch is still up to date with this project. Then merge your new branch into your '_**development**_' branch. + * Then create a new Pull Request (PR) to this project's '_**contributions**_' branch in GitHub + * The project team will then review your PR and communicate with you to convey any additional changes that would ensure that your work adheres to our guidelines. + +Table of contents: +* [Github Workflow](#github-workflow) +* [Pull Requests](#pull-requests) +* [Testing Guidelines](#testing-guidelines) +* [Coding Style/Guidelines](#coding-style) + +## GitHub Workflow +A contribution consists of any work that is voluntarily submitted to the project. This includes bug fixes, enhancements and documentation that is intended as an improvement to the DMP Roadmap system. + +Any individual with a GitHub account may propose a Contribution by submitting a Pull Request (PR) to this project's '_**contributions**_' branch. The project team will evaluate each PR as time permits and communicate with the contributor via comments on the PR. We will not accept a contribution until it adheres to the guidelines outlined in this document. If your contribution fits well with the development roadmap, the team will merge it into the project and schedule it for the next upcoming release. + +![GitHub Workflow ](https://github.com/DMPRoadmap/roadmap/blob/master/public/github-contributor-infographic-final.png) + +## Pull Requests +Please use these checklists to help you prepare your Pull Request for submission. + +ALL Pull Requests MUST be made to the '_**contributions**_' branch! + +#### Checklist for changes to a database table and/or its corresponding model +* Did you include the appropriate database migration? ```> rails g migration AddTwitterIdToUsers``` +* Did you update/add the Unit tests? +* Did your change require you to transform data? For example moving data from one field to another like moving users.organisation_id to a join table called users_organisations. If so, did you include a rake task to help others migrate their data over to the new model (along with instructions)? +* Does the schema.rb include the changes? +* Did you remember to update the seeds.rb file to reflect the change? + +#### Checklist for changes to a controller +* Did you update/add the Functional tests? +* Did you update/add the Routing tests (if applicable)? +* Did you update the corresponding view(s)? +* Did you include any updates/additions to localisation text config/locales/pot file? + +#### Checklist for changes to a view +* Did you include any updates/additions to localisation text config/locales/pot file? +* Did you update the corresponding controller? +* Did you manually test the change in multiple browsers? +* Did your change require modifications to the CSS, JS or image files? If so did you include them in your branded file locations or in the core system files? For example: lib/assets/javascripts is the default javascript directory. app/assets/javascripts are specific to your local installation. (See [Branding](https://github.com/DMPRoadmap/roadmap/wiki/Branding) for more information) + +## Testing Guidelines +First and foremost, all of the existing tests must pass before we accept your contribution. If your work has made a change to an object that results in failed tests then you should update those tests so that they are accurate. + +To run the tests: +```shell +# Make sure that your test DB has all of the current database migrations: +> rake db:migrate RAILS_ENV=test + +# To run all of the tests: +> rake test +# To run all of a specific type of tests: +> rake test test/unit/ +# To run a specific test: +> rake test test/unit/users_test.rb +``` + +If you are adding a new feature to the system you must build out the appropriate tests before we will accept your contribution. For example, if I add a new field to the User table that stores the user's Twitter id, I should update the test/unit/users_test.rb Unit test. If my contribution included changes to the User Profile page that allowed the user to enter this new Twitter id then I should update the test/functional/registrations_controller_test.rb Functional controller test. + +DMP Roadmap uses the Travis CI framework to verify that are tests are passing. When you create your PR you will see a note stating that the tests are pending. Check back after a few minutes to give the Travis system time to run its tests. + +**Please Note:** We will not review your PR until the tests are passing and GitHub notes that there are no merge conflicts + +The original DMP Roadmap codebase did not include a full suite of tests. The project team has been busy adding them in when we can but we still have a long way to go. The requirements mentioned above are in place for pieces of the system that already have tests. For example, if your work involves an enhancement to an existing controller that has no functional test in the current codebase, we do not expect you to write tests for the entire controller (although we would welcome the help!). In cases like this, we only ask that you write tests for the endpoints that you have updated. + +We do not currently have testing for the UI components. We plan to add tests for these in the near future using a headless browser like PhantomJS. We welcome any contributors who are willing to begin work in this area! + +#### Unit tests: +* The model can be Created, Read/Loaded, Updated and Deleted (CRUD) +* Required fields are required and that the model cannot be saved without those fields +* Any other validations are working as expected (e.g. email address is in the email format) +* Associations are functioning properly. Use the helper methods in test/test_helper.rb +* All other functions that are defined within the model are tested +* You should update or create the corresponding fixtures for the model you are testing + +#### Functional Controller tests: +* The correct HTTP response was received (200 success, 302 redirect, 401 unauthorized, etc.) +* The user was redirected to the correct page (if applicable) +* All of the instance variables set within the controller were properly defined +* All flash messaging is correct + +#### Integration tests: +* Complex workflows that involve multiple pieces of the system should have an integration test. This can include interaction with gem dependencies or external services. For example email, login/logout, etc. + +#### Helper/Service tests: +* Each method within the helper or service should be tested for both success and failure conditions + +#### Routing tests: +New controller/API endpoints should have tests within the test/routing_test.rb + +#### General Notes and Advice: +* You should use the Rails URL and Path helpers instead of hard-coding them in your tests. (e.g. edit_plans_path(@plan) instead of '/plans/123/edit' +* You should use the I18n.t method to validate flash messaging rather than hard-coding messages in your tests +* You should include assertions that test both success and failure conditions + +## Coding style +We realize that every developer has their own style and we encourage a bit of individuality. However, we do impose some of the following rules to contributions to this project. + +* We quite like the principle of [DRY (Don't Repeat Yourself)](https://en.wikipedia.org/wiki/Don't_repeat_yourself) so please always look through the existing code to make sure you are not reinventing something that has already been done. Also clever bits of code or reuse of existing ones to avoid copying and pasting is always appreciated. +* Include database migrations when you are altering the database model. Use the following command to create a new migration and be specific about what it does in the name of the file + + ```shell + > rails g migration AddTwitterIdToUsers + ``` +* You do not need to comment every line of your code but we do expect to see inline comments explaining the intent of your if blocks and loops. +* We do not want to see Tab characters. Tabs should be converted to a double space. If you are working on a file that has Tabs already, please convert them for us before making your Pull Request +* If a line is going to go beyond 100 characters please break it out onto multiple lines. For example: + + ```ruby + # This is preferable + users = [{email: @user.email, password: 'bAd_pas$word1', remember_me: true}, + {email: 'unknown@institution.org', password: 'password123', remember_me: true}] + + # to this long line that requires scrolling + users = [{email: @user.email, password: 'bAd_pas$word1', remember_me: true}, {email: 'unknown@institution.org', password: 'password123', remember_me: true}] + ``` +* Finally, please make sure your code is properly indented as this enhances readability. diff --git a/Gemfile b/Gemfile index 2b41610..2d9b5b9 100644 --- a/Gemfile +++ b/Gemfile @@ -34,7 +34,7 @@ # ------------------------------------------------ # SUPER ADMIN SECTION -gem 'activeadmin', github: 'activeadmin' +gem "administrate", :github => 'thoughtbot/administrate', :branch =>'v0.7.0' # ------------------------------------------------ # USERS @@ -59,11 +59,13 @@ gem 'sass-rails' gem 'less-rails' # WE SHOULD PROBABLY USE SASS OR LESS NOT BOTH gem 'jquery-rails' +gem 'font-awesome-rails' gem 'twitter-bootstrap-rails', '2.2.8' gem 'tinymce-rails' # WYSIWYG EDITOR gem 'contact_us', '>= 1.2.0' # COULD BE EASILY REPLACED WITH OUR OWN CODE -gem 'recaptcha' +gem 'recaptcha', '>= 4.0' gem 'dragonfly' # LOGO UPLOAD +gem 'formtastic' # ------------------------------------------------ # EXPORTING @@ -72,14 +74,14 @@ gem 'wicked_pdf' gem 'htmltoword' gem 'feedjira' -gem 'caracal' # WORD DOC EXPORTING -gem 'caracal-rails' gem 'yaml_db', :git => 'https://github.com/vyruss/yaml_db.git' # ------------------------------------------------ # INTERNATIONALIZATION gem "i18n-js", ">= 3.0.0.rc11" #damodar added TODO: explain gem 'gettext_i18n_rails', '~> 1.8' +gem "gettext_i18n_rails_js", "~> 1.2.0" +gem 'gettext', '>=3.0.2', :require => false, :group => :development # ------------------------------------------------ # API diff --git a/Gemfile.lock b/Gemfile.lock index d430a3c..53bf3cf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,21 +1,20 @@ GIT - remote: git://github.com/activeadmin/activeadmin.git - revision: f8926831429fe635d26ac8043ea5d676fb6ee637 + remote: git://github.com/thoughtbot/administrate.git + revision: 6bc227907e8567ca9d8c51658abc92fc2b19ca2d + branch: v0.7.0 specs: - activeadmin (1.0.0.pre4) - arbre (~> 1.0, >= 1.0.2) - bourbon - coffee-rails - formtastic (~> 3.1) - formtastic_i18n - inherited_resources (~> 1.6) - jquery-rails - jquery-ui-rails - kaminari (~> 0.15) - railties (>= 3.2, < 5.1) - ransack (~> 1.3) - sass-rails - sprockets (< 4.1) + administrate (0.7.0) + actionpack (>= 4.2, < 5.1) + actionview (>= 4.2, < 5.1) + activerecord (>= 4.2, < 5.1) + autoprefixer-rails (~> 6.0) + datetime_picker_rails (~> 0.0.7) + jquery-rails (>= 4.0) + kaminari (>= 1.0) + momentjs-rails (~> 2.8) + normalize-rails (>= 3.0) + sass-rails (~> 5.0) + selectize-rails (~> 0.6) GIT remote: https://github.com/vyruss/yaml_db.git @@ -65,9 +64,9 @@ tzinfo (~> 1.1) addressable (2.4.0) ansi (1.5.0) - arbre (1.1.1) - activesupport (>= 3.0.0) arel (6.0.3) + autoprefixer-rails (6.7.7.2) + execjs bcrypt (3.1.11) better_errors (2.1.1) coderay (>= 1.0.0) @@ -75,9 +74,6 @@ rack (>= 0.9.0) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) - bourbon (4.2.7) - sass (~> 3.4) - thor (~> 0.19) builder (3.2.2) byebug (9.0.5) capybara (2.9.1) @@ -87,21 +83,7 @@ rack (>= 1.0.0) rack-test (>= 0.5.4) xpath (~> 2.0) - caracal (1.0.8) - nokogiri (~> 1.6) - rubyzip (~> 1.1) - tilt (>= 1.4) - caracal-rails (1.0.1) - caracal (~> 1.0) - rails (>= 3.2) coderay (1.1.1) - coffee-rails (4.2.1) - coffee-script (>= 2.2.0) - railties (>= 4.0.0, < 5.2.x) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.10.0) commonjs (0.2.7) concurrent-ruby (1.0.2) contact_us (1.2.0) @@ -109,6 +91,8 @@ crack (0.4.3) safe_yaml (~> 1.0.0) daemons (1.2.4) + datetime_picker_rails (0.0.7) + momentjs-rails (>= 2.8.1) debug_inspector (0.0.2) devise (4.2.0) bcrypt (~> 3.0) @@ -131,22 +115,31 @@ multipart-post (>= 1.2, < 3) faraday_middleware (0.10.0) faraday (>= 0.7.4, < 0.10) + fast_gettext (1.3.0) feedjira (2.0.0) faraday (~> 0.9) faraday_middleware (~> 0.9) loofah (~> 2.0) sax-machine (~> 1.0) flag_shih_tzu (0.3.15) + font-awesome-rails (4.7.0.1) + railties (>= 3.2, < 5.1) formtastic (3.1.4) actionpack (>= 3.2.13) - formtastic_i18n (0.6.0) friendly_id (5.1.0) activerecord (>= 4.0.0) + gettext (3.2.2) + locale (>= 2.0.5) + text (>= 1.3.0) + gettext_i18n_rails (1.8.0) + fast_gettext (>= 0.9.0) + gettext_i18n_rails_js (1.2.0) + gettext (>= 3.0.2) + gettext_i18n_rails (>= 0.7.1) + po_to_json (>= 1.0.0) + rails (>= 3.2.0) globalid (0.3.7) activesupport (>= 4.1.0) - has_scope (0.6.0) - actionpack (>= 3.2, < 5) - activesupport (>= 3.2, < 5) hashdiff (0.3.0) hashie (3.4.6) htmltoword (0.5.1) @@ -156,11 +149,6 @@ i18n (0.7.0) i18n-js (3.0.0.rc14) i18n (~> 0.6, >= 0.6.6) - inherited_resources (1.6.0) - actionpack (>= 3.2, < 5) - has_scope (~> 0.6.0.rc) - railties (>= 3.2, < 5) - responders jbuilder (2.6.0) activesupport (>= 3.0.0, < 5.1) multi_json (~> 1.2) @@ -168,13 +156,20 @@ rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - jquery-ui-rails (5.0.5) - railties (>= 3.2.16) json (1.8.3) jwt (1.5.6) - kaminari (0.17.0) - actionpack (>= 3.0.0) - activesupport (>= 3.0.0) + kaminari (1.0.1) + activesupport (>= 4.1.0) + kaminari-actionview (= 1.0.1) + kaminari-activerecord (= 1.0.1) + kaminari-core (= 1.0.1) + kaminari-actionview (1.0.1) + actionview + kaminari-core (= 1.0.1) + kaminari-activerecord (1.0.1) + activerecord + kaminari-core (= 1.0.1) + kaminari-core (1.0.1) ledermann-rails-settings (2.4.2) activerecord (>= 3.1) less (2.6.0) @@ -185,6 +180,7 @@ sprockets (> 2, < 4) tilt libv8 (3.16.14.15) + locale (2.1.2) loofah (2.0.3) nokogiri (>= 1.5.9) mail (2.6.4) @@ -213,6 +209,8 @@ builder minitest (>= 5.0) ruby-progressbar + momentjs-rails (2.17.1) + railties (>= 3.1) multi_json (1.12.1) multi_xml (0.5.5) multipart-post (2.0.0) @@ -220,6 +218,7 @@ nokogiri (1.6.8) mini_portile2 (~> 2.1.0) pkg-config (~> 1.1.7) + normalize-rails (4.1.1) oauth2 (1.2.0) faraday (>= 0.8, < 0.10) jwt (~> 1.0) @@ -239,8 +238,8 @@ orm_adapter (0.5.0) pg (0.19.0) pkg-config (1.1.7) - polyamorous (1.3.1) - activerecord (>= 3.0) + po_to_json (1.0.1) + json (>= 1.6.0) protected_attributes (1.1.3) activemodel (>= 4.0.1, < 5.0) pundit (1.1.0) @@ -275,13 +274,7 @@ rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rake (11.3.0) - ransack (1.8.2) - actionpack (>= 3.0) - activerecord (>= 3.0) - activesupport (>= 3.0) - i18n - polyamorous (~> 1.3) - recaptcha (3.3.0) + recaptcha (4.1.0) json redcarpet (3.3.4) ref (2.0.0) @@ -299,6 +292,7 @@ sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) sax-machine (1.3.2) + selectize-rails (0.12.4) simplecov (0.12.0) docile (~> 1.1.0) json (>= 1.8, < 3) @@ -315,6 +309,7 @@ swagger-docs (0.2.9) activesupport (>= 3) rails (>= 3) + text (1.3.1) therubyracer (0.12.2) libv8 (~> 3.16.14.0) ref @@ -357,19 +352,22 @@ ruby DEPENDENCIES - activeadmin! + administrate! better_errors binding_of_caller byebug - caracal - caracal-rails contact_us (>= 1.2.0) devise devise_invitable dragonfly feedjira flag_shih_tzu + font-awesome-rails + formtastic friendly_id + gettext (>= 3.0.2) + gettext_i18n_rails (~> 1.8) + gettext_i18n_rails_js (~> 1.2.0) htmltoword i18n-js (>= 3.0.0.rc11) jbuilder @@ -390,7 +388,7 @@ rack-test rails (= 4.2.7) railties - recaptcha + recaptcha (>= 4.0) redcarpet responders (~> 2.0) rolify @@ -414,4 +412,4 @@ ruby 2.2.2p95 BUNDLED WITH - 1.13.7 + 1.14.6 diff --git a/README.md b/README.md index 88ceaba..0ae2435 100644 --- a/README.md +++ b/README.md @@ -10,27 +10,89 @@ 4. To allow collaborative work when creating Data Management Plans. #### Current Release -v.0.1.0 +Official release coming soon! [![Build Status](https://travis-ci.org/DMPRoadmap/roadmap.svg)](https://travis-ci.org/DMPRoadmap/roadmap) #### Summary -#### Installation and Requirements -See the [Installation Guide](https://github.com/DMPRoadmap/roadmap/wiki/Installation) +#### Pre-requisites +Roadmap is a Ruby on Rails application and you will need to have: +* Ruby >= 2.2.2 +* Rails >= 4.2 +* MySql >= 5.0 OR PostgreSql #### Migrating data from a running instance of DMPOnline_v4 or DMPTool Migration instructions will be coming soon +Further details on how to install MySQL and create your first user and database. Be sure to follow the instructions for your particular environment. +* Install: http://dev.mysql.com/downloads/mysql/ +* Create a user: http://dev.mysql.com/doc/refman/5.7/en/create-user.html +* Create the database: http://dev.mysql.com/doc/refman/5.7/en/creating-database.html + +You may also find the following resources handy: + +* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html +* Ruby on Rails Tutorial Book: http://www.railstutorial.org/ + +#### Installation +* Create your database. Select UTF-8 Unicode (utf8) encoding. +* Clone this repository (or Fork the repository first if you plan on contributing) + +> > git clone https://github.com/[your organization]/roadmap.git + +> > cd roadmap + +* Make copies of the yaml configuration files and update the values for your installation + +> > cp config/database_example.yml config/database.yml +> > cp config/secrets_example.yml config/secrets.yml + +* Make copies of the example gem initializer files and update the values for your installation + +> > cp config/initializers/devise.rb.example config/initializers/devise.rb +> > cp config/initializers/recaptcha.rb.example config/initializers/recaptcha.rb +> > cp config/initializers/wicked_pdf.rb.example config/initializers/wicked_pdf.rb +> > cp config/locales/*.static.yml.example config/locales/*.static.yml + +* Create an environment variable for your instance's secret (as defined in config/secrets.yml). You should use the following command to generate secrets for each of your environments, storing the production one in the environment variable: + +> > rake secret + +* Run bundler and perform the DB migrations + +> > gem install bundler (if bundler is not yet installed) + +> > bundle install + +> > rake db:schema:load + +> > rake db:seed (Unless you are migrating data from an old DMPOnline system) + +* Start the application + +> > rails server + +* Verify that the site is running properly by going to http://localhost:3000 +* Login as the default administrator: 'super_admin@example.com' - 'password123' #### Troubleshooting -See the [Troubleshooting Guide](https://github.com/DMPRoadmap/roadmap/wiki/Troubleshooting) +See the [Troubleshooting Guide](https://github.com/DMPRoadmap/roadmap/wiki/Troubleshooting) on the Wiki #### Support Issues should be reported here on [Github Issues](https://github.com/DMPRoadmap/roadmap/issues) Please be advised though that we can only provide limited support for your local installations. #### Become a contributor -See the [Contributor Guide](https://github.com/DMPRoadmap/roadmap/wiki/Contributing) +If you would like to contribute to the project. Please follow these steps to submit a contribution: +* Comment on the Github issue (or create one if one does not exist) and let us know that you're working on it. +* Fork the project (if you have not already) or rebase your fork so that it is up to date with the current repository's '_**development**_' branch +* Create a new branch in your fork. This will ensure that you are able to work at your own pace and continue to pull in any updates made to this project. +* Make your changes in the new branch +* When you have finished your work, make sure that your version of the '_**development**_' branch is still up to date with this project. Then merge your new branch into your '_**development**_' branch. +* Then create a new Pull Request (PR) to this project's '_**contributions**_' branch in GitHub +* The project team will then review your PR and communicate with you to convey any additional changes that would ensure that your work adheres to our guidelines. + +See the [Contribution Guide](https://github.com/DMPRoadmap/roadmap/wiki/Contributing) on the Wiki for more details #### License The DMP Roadmap project uses the MIT License. diff --git a/app/admin/dashboard.rb b/app/admin/dashboard.rb deleted file mode 100644 index 3aa2b89..0000000 --- a/app/admin/dashboard.rb +++ /dev/null @@ -1,39 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - - -ActiveAdmin.register_page "Dashboard" do - - menu priority: 1, label: proc{ I18n.t("active_admin.dashboard") } - - content title: proc{ I18n.t("active_admin.dashboard") } do - #div class: "blank_slate_container", id: "dashboard_default_message" do - # span class: "blank_slate" do - # span I18n.t("active_admin.dashboard_welcome.welcome") - # small I18n.t("active_admin.dashboard_welcome.call_to_action") - # end - #end - - # Here is an example of a simple dashboard with columns and panels. - # - # columns do - # column do - # panel "Recent Posts" do - # ul do - # Post.recent(5).map do |post| - # li link_to(post.title, admin_post_path(post)) - # end - # end - # end - # end - - # column do - # panel "Info" do - # para "Welcome to ActiveAdmin." - # end - # end - # end - end # content -end \ No newline at end of file diff --git a/app/admin/guidance.rb b/app/admin/guidance.rb deleted file mode 100644 index f4400e9..0000000 --- a/app/admin/guidance.rb +++ /dev/null @@ -1,81 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register Guidance do - permit_params :text, :guidance_group_id, :question_id - - menu :priority => 13, :label => proc{ I18n.t('admin.guidance')}, :parent => "Guidance list" - - index do - column (:text) { |guidance| raw(guidance.text) } - column I18n.t('admin.theme') do |t| - (t.themes.map{|t_q| link_to t_q.title, [:admin, t_q]}).join(', ').html_safe - end - - column I18n.t('admin.question'), :sortable => :question_id do |que| - if !que.nil? then - que.question - else - '-' - end - end - - column I18n.t('admin.guidance_group') do |guidance| - (guidance.guidance_groups.map{|t_q| link_to t_q.name, [:admin, t_q]}).join(', ').html_safe - end - actions - end - - #show details of a question - show do - attributes_table do - row (:text) { |guidance| raw(guidance.text) } - - row I18n.t('admin.theme') do - (guidance.themes.map{|t_q| link_to t_q.title, [:admin, t_q]}).join(', ').html_safe - end - row I18n.t('admin.question'), :question_id do |question| - question.question - end - row I18n.t('admin.guidance_group') do |guidance| - (guidance.guidance_groups.map{|t_q| link_to t_q.name, [:admin, t_q]}).join(', ').html_safe - end - - row :created_at - row :updated_at - end - end - - #form - form do |f| - f.inputs "Details" do - f.input :text - f.input :question_id, :as => :select, - :collection => Question.order('text').map{|que|[que.text, que.id]} - f.input :guidance_group_ids, :label => I18n.t('admin.guidance_group'), - :as => :select, - :collection => GuidanceGroup.order('name').map{|gui|[gui.name, gui.id]} - - end - f.inputs "Themes" do - f.input :theme_ids, :label => I18n.t('admin.selected_themes'), - :as => :select, - :include_blank => I18n.t('admin.all_themes'), - :multiple => true, - :collection => Theme.order('title').map{|the| [the.title, the.id]}, - :hint => I18n.t('admin.choose_themes') - end - - f.actions - end - - controller do - def permitted_params - params.permit! - end - end - -end diff --git a/app/admin/guidance_group.rb b/app/admin/guidance_group.rb deleted file mode 100644 index c193af9..0000000 --- a/app/admin/guidance_group.rb +++ /dev/null @@ -1,80 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register GuidanceGroup do - permit_params :organisation_id, :name, :published, :optional_subset - - menu :priority => 2, :label => proc{I18n.t('admin.guidance_group')}, :parent => "Guidance list" - - index do - column I18n.t('admin.name'), :sortable => :name do |ggn| - link_to ggn.name, [:admin, ggn] - end - column I18n.t('admin.org_title'), :sortable => :organisation_id do |org_title| - link_to org_title.organisation.name, [:admin, org_title.organisation] - end - column I18n.t('admin.template') do |t| - (t.dmptemplates.map{|t_q| link_to t_q.title, [:admin, t_q]}).join(', ').html_safe - end - - actions - end - - #show details of guidance group - show do - attributes_table do - row :name - row :organisation_id do |org_title| - link_to org_title.organisation.name, [:admin, org_title.organisation] - end - row I18n.t('admin.template') do - (guidance_group.dmptemplates.map{|t_q| link_to t_q.title, [:admin, t_q]}).join(', ').html_safe - end - row :created_at - row :updated_at - end - end - - #guidance list - sidebar I18n.t('admin.guidance'), :only => :show, :if => proc { guidance_group.guidances.count >= 1} do - table_for guidance_group.guidances.order("text asc") do |guis| - column :text do |gtext| - link_to gtext.text.html_safe, [:admin, gtext] - end - column I18n.t('admin.theme') do |themelist| - (themelist.themes.map{|t_q| link_to t_q.title, [:admin, t_q]}).join(', ').html_safe - end - end - end - - #form - form do |f| - f.inputs "Details" do - f.input :name - f.input :organisation_id, :label => I18n.t('admin.org_title'), - :as => :select, - :collection => Org.order('name').map{|orgp|[orgp.name, orgp.id]} - f.input :published - f.input :optional_subset - end - - f.inputs "Templates" do - f.input :dmptemplate_ids, :label => I18n.t('admin.selected_templates'), - :as => :select, - :include_blank => I18n.t('admin.all_templates'), - :multiple => true, - :collection => Dmptemplate.order('title').map{|the| [the.title, the.id]}, - :hint => I18n.t('admin.choose_templates') - end - f.actions - end - - controller do - def permitted_params - params.permit! - end - end -end diff --git a/app/admin/language.rb b/app/admin/language.rb deleted file mode 100644 index 777478c..0000000 --- a/app/admin/language.rb +++ /dev/null @@ -1,45 +0,0 @@ -# [+Project:+] DMPonline -# [+Description:+] -# -# [+Created:+] 12/08/2016 -# [+Copyright:+] Digital Curation Centre - -ActiveAdmin.register Language do - permit_params :language_id, :name, :abbreviation, :default_language - - menu :priority => 10, :label => proc { I18n.t('admin.language') } - - index do - column I18n.t('admin.language_name'), :sortable => :name do |lang| - link_to lang.name, [:admin, lang] - end - column I18n.t('admin.language_abbreviation'), :sortable => :abbreviation do |lang| - link_to lang.abbreviation, [:admin, lang] - end - column I18n.t('admin.language_is_default'), :sortable => :default_language do |lang| - if lang[:default_language] - 'Yes' - else - 'No' - end - end - - actions - end - - show do - attributes_table do - row :name - row :abbreviation - row :default_language - row :description - end - end - - controller do - def permitted_params - params.permit! - end - end - -end \ No newline at end of file diff --git a/app/admin/option.rb b/app/admin/option.rb deleted file mode 100644 index cd68f1a..0000000 --- a/app/admin/option.rb +++ /dev/null @@ -1,79 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register QuestionOption do - permit_params :question_id, :text, :number, :is_default - menu :priority => 6, :label => proc{I18n.t('admin.multi_options')}, :parent => "Templates management" - - index do - column :text - column I18n.t('admin.questions'), :sortable => :question_id do |ques| - if !ques.question_id.nil? then - link_to ques.question.text, [:admin, ques.question] - end - end - column I18n.t('admin.sections'), :sortable => :question_id do |ques| - if !ques.question_id.nil? then - link_to ques.question.section.title, [:admin, ques.question.section] - end - end - column I18n.t('admin.template'), :sortable => :question_id do |ques| - if !ques.question_id.nil? then - link_to ques.question.section.version.phase.dmptemplate.title, [:admin, ques.question.section.version.phase.dmptemplate] - end - end - - actions - end - - #show details of a section - show do - attributes_table do - row :text - row :number - row I18n.t('admin.questions'), :question_id do |ques| - if !ques.question_id.nil? then - link_to ques.question.text, [:admin, ques.question] - end - end - row I18n.t('admin.sections'), :question_id do |ques| - if !ques.question_id.nil? then - link_to ques.question.section.title, [:admin, ques.question.section] - end - end - row I18n.t('admin.template'), :question_id do |ques| - if !ques.question_id.nil? then - link_to ques.question.section.version.phase.dmptemplate.title, [:admin, ques.question.section.version.phase.dmptemplate] - end - end - row :is_default - row :created_at - row :updated_at - end - end - - - #form - form do |f| - f.inputs "Details" do - f.input :text - f.input :number - f.input :question, - :as => :select, - :collection => Question.order('text').map{ |sec| ["#{truncate(sec.section.version.phase.dmptemplate.title, :lengh => 20)} - #{truncate(sec.section.title, :lengh => 50)} - #{truncate(sec.text, :lengh => 20)}", sec.id] } - f.input :is_default - end - - f.actions - end - - - controller do - def permitted_params - params.permit! - end - end -end diff --git a/app/admin/org.rb b/app/admin/org.rb deleted file mode 100644 index 7d9391b..0000000 --- a/app/admin/org.rb +++ /dev/null @@ -1,110 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register Org do - permit_params :abbreviation, :banner_file_id, :description, :logo_file_id, :name, :target_url, :organisation_type_id, :wayfless_entity, :parent_id - - menu :priority => 14, :label => proc{I18n.t('admin.org')}, :parent => "Organisations management" - - index do - column I18n.t('admin.org_title'), :sortable => :name do |ggn| - link_to ggn.name, [:admin, ggn] - end - column I18n.t('admin.abbrev'), :sortable => :abbreviation do |ggn| - if !ggn.abbreviation.nil? - link_to ggn.abbreviation, [:admin, ggn] - else - '-' - end - end - column I18n.t('admin.org_type'), :sortable => :organisation_type_id do |org_type| - if !org_type.organisation_type_id.nil? then - link_to org_type.organisation_type.name, [:admin, org_type] - end - end - - actions - end - - - #show details of an organisation - show do - resource.check_api_credentials - attributes_table do - row I18n.t('admin.org_title'), :sortable => :name do |gn| - if !gn.name.nil? then - link_to gn.name, [:admin, gn] - end - end - row I18n.t('admin.abbrev'), :abbreviation do |ggn| - if !ggn.abbreviation.nil? - link_to ggn.abbreviation, [:admin, ggn] - else - '-' - end - end - row :sort_name - row I18n.t('admin.org_type'), :organisation_type_id do |org_type| - if !org_type.organisation_type_id.nil? then - link_to org_type.organisation_type.name, [:admin, org_type] - end - end - row :banner_text do |banner| - if !banner.banner_text.nil? then - banner.banner_text.html_safe - end - end - # row :target_url - row :logo_file_name - row :wayfless_entity - row I18n.t('admin.token_permission_type') do - (organisation.token_permission_types.map{|tpt| link_to tpt.token_type, [:admin, tpt]}).join(', ').html_safe - end - row :created_at - row :updated_at - end - end - - #templates sidebar - sidebar I18n.t('admin.templates'), :only => :show, :if => proc { organisation.dmptemplates.count >= 1} do - table_for organisation.dmptemplates.order("title asc") do |temp| - column :title do |dmptemp| - link_to dmptemp.title, [:admin, dmptemp] - end - column :published - end - end - - #form - form do |f| - f.inputs "Details" do - f.input :name - f.input :abbreviation - f.input :sort_name - f.input :organisation_type_id, :label => I18n.t('admin.org_type'), :as => :select, :collection => OrganisationType.order('name').map{|orgt|[orgt.name, orgt.id]} - # f.input :target_url - f.input :banner_text - f.input :logo_file_name - f.input :wayfless_entity - f.input :token_permission_types, label: I18n.t('admin.token_permission_type'), - as: :select, multiple: true, include_blank: I18n.t('helpers.none'), - collection: TokenPermissionType.order(:token_type).map{|token| [token.token_type, token.id]}, - hint: I18n.t('admin.choose_api_permissions') - # f.input :parent_id, :label => I18n.t('admin.org_parent'), :as => :select, :collection => Org.find(:all, :order => 'name ASC').map{|orgp|[orgp.name, orgp.id]} - # f.input :stylesheet_file_id - end - f.actions - end - - - controller do - def permitted_params - params.permit! - end - end - - -end diff --git a/app/admin/perm.rb b/app/admin/perm.rb deleted file mode 100644 index 4401e31..0000000 --- a/app/admin/perm.rb +++ /dev/null @@ -1,60 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register Perm do - permit_params :name - - menu :priority => 5, :label => proc{I18n.t('admin.role')}, :parent => "User management" - - index do - column I18n.t('admin.title'), :sortable => :name do |role_name| - link_to role_name.name, [:admin, role_name] - end - - actions - end - - - show do - attributes_table do - row :name - row :created_at - row :updated_at - end - - table_for( (Perm.find(params[:id]).users)) do - column (:email){|user| link_to user.email, [:admin, user]} - column (:firstname){|user| user.firstname} - column (:surname){|user| user.surname} - column (:last_sign_in_at){|user| user.last_sign_in_at} - column (I18n.t('admin.org_title')){|user| - if !user.organisation.nil? then - if user.other_organisation.nil? || user.other_organisation == "" then - link_to user.organisation.name, [:admin, user.organisation] - else - I18n.t('helpers.org_type.org_name') + ' - ' + user.other_organisation - - end - end - } - end - - end - - form do |f| - f.inputs "Details" do - f.input :name - end - - f.actions - end - - controller do - def permitted_params - params.permit! - end - end -end diff --git a/app/admin/phase.rb b/app/admin/phase.rb deleted file mode 100644 index d7d061e..0000000 --- a/app/admin/phase.rb +++ /dev/null @@ -1,83 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register Phase do - permit_params :description, :number, :title, :dmptemplate_id - - menu :priority => 10, :label => proc{I18n.t('admin.phase')}, :parent => "Templates management" - - index do - column :title, :sortable => :title do |ph| - if !ph.title.nil? then - link_to ph.title, [:admin, ph] - end - end - column :number - column I18n.t('admin.template'), :sortable => :dmptemplate_id do |temp_title| - if !temp_title.nil? then - if !temp_title.dmptemplate.nil? then - link_to temp_title.dmptemplate.title, [:admin, temp_title.dmptemplate] - else - "-" - end - end - end - - actions - end - - #show details of a phase - show do - attributes_table do - row :title - row :number - row :description do |descr| - if !descr.description.nil? then - descr.description.html_safe - end - end - row I18n.t('admin.template'), :sortable => :dmptemplate_id do |temp_title| - link_to temp_title.dmptemplate.title, [:admin, temp_title.dmptemplate] - end - row :created_at - row :updated_at - end - - end - - #versions sidebar - sidebar I18n.t('admin.version'), :only => :show, :if => proc { phase.versions.count >= 1} do - table_for phase.versions.order("number asc") do |temp_phases| - column :number - column :title do |row| - link_to row.title, [:admin, row] - end - column :published - end - end - - - #form - form do |f| - f.inputs "Details" do - f.input :title - f.input :number - f.input :description - f.input :dmptemplate_id, :label => I18n.t('admin.template'), - :as => :select, - :collection => Dmptemplate.order('title').map{|temp|[temp.title, temp.id]} - - end - f.actions - end - - - controller do - def permitted_params - params.permit! - end - end -end diff --git a/app/admin/plan.rb b/app/admin/plan.rb deleted file mode 100644 index 574a7c2..0000000 --- a/app/admin/plan.rb +++ /dev/null @@ -1,39 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register Plan do - permit_params :template_id, :title, :org_id, :unit_id, :guidance_group_ids, :role_ids, :funder_id, :institution_id, :grant_number,:identifier, :description, :principal_investigator, :principal_investigator_identifier, :data_contact - - menu :priority => 25, :label => proc{I18n.t('admin.plans')} - - - index do - column :title - column I18n.t('admin.org_title'), :sortable => :org_id do |org_title| - if !org_title.organisation.nil? then - link_to org_title.organisation.name, [:admin, org_title.organisation] - else - '-' - end - end - column I18n.t('admin.template_title'), :sortable => :template_id do |dmptemp| - if !dmptemp.template.nil? then - link_to dmptemp.template.title, [:admin, dmptemp.template] - else - '-' - end - end - - actions - end - - - controller do - def permitted_params - params.permit! - end - end -end diff --git a/app/admin/question.rb b/app/admin/question.rb deleted file mode 100644 index 45d8e18..0000000 --- a/app/admin/question.rb +++ /dev/null @@ -1,101 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register Question do - permit_params :default_value, :dependency_id, :dependency_text, :guidance, :number, :suggested_answer, :text, :question_type, :section_id - - menu :priority => 7, :label => proc{I18n.t('admin.question')}, :parent => "Templates management" - - index do - column I18n.t('admin.question'), :sortable => :text do |descr| - if !descr.text.nil? then - descr.text.html_safe - end - end - column I18n.t('admin.section_title'), :sortable => :section_id do |dmptemplate| - if !dmptemplate.section_id.nil? then - link_to dmptemplate.section.title, [:admin, dmptemplate.section] - end - end - column :number, :sortable => :number do |question_n| - if !question_n.number.nil? then - question_n.number - end - end - column I18n.t('admin.template_title'), :sortable => true do |dmptemplate| - if !dmptemplate.section_id.nil? then - if !dmptemplate.section.version.phase.dmptemplate.nil? then - link_to dmptemplate.section.version.phase.dmptemplate.title, [:admin, dmptemplate.section.version.phase.dmptemplate] - else - "-" - end - end - end - actions - end - - - #show details of a question - show do - attributes_table do - row :text do |descr| - if !descr.text.nil? then - descr.text.html_safe - end - end - row :section_id do |question| - link_to question.section.title, [:admin, question.section] - end - row :number - row :default_value - row I18n.t('admin.question_format') do |format| - link_to format.question_format.title, [:admin, format.question_format] - end - row I18n.t('admin.themes') do - (question.themes.map{|t_q| link_to t_q.title, [:admin, t_q]}).join(', ').html_safe - end - row :created_at - row :updated_at - - end - end - - - #form - form do |f| - f.inputs "Details" do - f.input :text - f.input :number - f.input :section, - :as => :select, - :collection => Section.order('title').map{ |sec| ["#{sec.version.phase.dmptemplate.title} - #{sec.title}", sec.id] } - f.input :default_value - - end - f.inputs "Question Format" do - f.input :question_format_id, :label => I18n.t('admin.select_question_format'), - :as => :select, - :collection => QuestionFormat.order('title').map{|format| [format.title, format.id]} - end - f.inputs "Themes" do - f.input :theme_ids, :label => I18n.t('admin.selected_themes'), - :as => :select, - :multiple => true, - :include_blank => I18n.t('helpers.none'), - :collection => Theme.order('title').map{|the| [the.title, the.id]} , - :hint => I18n.t('admin.choose_themes') - - end - f.actions - end - - controller do - def permitted_params - params.permit! - end - end - -end diff --git a/app/admin/question_format.rb b/app/admin/question_format.rb deleted file mode 100644 index a5b9523..0000000 --- a/app/admin/question_format.rb +++ /dev/null @@ -1,39 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register QuestionFormat do - permit_params :description, :title - - menu :priority => 5, :label => proc{I18n.t('admin.question_format')}, :parent => "Templates management" - - index do - column I18n.t('admin.question_format'), :sortable => :title do |n| - link_to n.title, [:admin, n] - end - - actions - end - - # show Template details - show do - attributes_table do - row :title - row :description do |descr| - if !descr.description.nil? then - descr.description.html_safe - end - end - row :created_at - row :updated_at - end - end - - controller do - def permitted_params - params.permit! - end - end -end diff --git a/app/admin/role.rb b/app/admin/role.rb deleted file mode 100644 index 4fcf03b..0000000 --- a/app/admin/role.rb +++ /dev/null @@ -1,9 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register Role do - menu false -end diff --git a/app/admin/section.rb b/app/admin/section.rb deleted file mode 100644 index 4cc6c37..0000000 --- a/app/admin/section.rb +++ /dev/null @@ -1,93 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register Section do - permit_params :organisation_id, :description, :number, :title, :version_id - - menu :priority => 8, :label => proc{I18n.t('admin.section')}, :parent => "Templates management" - - filter :title - filter :organisation - filter :version - filter :created_at - filter :updated_at - - - index do - column :title , :sortable => :title do |section| - if !section.title.nil? then - link_to section.title, [:admin, section] - end - end - column I18n.t('admin.version'), :sortable => :version_id do |version_title| - if !version_title.version_id.nil? then - link_to version_title.version.title, [:admin, version_title.version] - end - end - column I18n.t('admin.org_title'), :sortable => :organisation_id do |org_title| - if !org_title.organisation_id.nil? then - link_to org_title.organisation.name, [:admin, org_title.organisation] - end - end - - actions - end - - #show details of a section - show do - attributes_table do - row :title - row :number - row :description do |descr| - if !descr.description.nil? then - descr.description.html_safe - end - end - row I18n.t('admin.version'), :sortable => :version_id do |version_title| - if !version_title.version_id.nil? then - link_to version_title.version.title, [:admin, version_title.version] - end - end - row I18n.t('admin.org_title'), :sortable => :organisation_id do |org_title| - if !org_title.organisation_id.nil? then - link_to org_title.organisation.name, [:admin, org_title.organisation] - end - end - row :created_at - row :updated_at - end - - end - - - #questions sidebar(:default_value, :dependency_id, :dependency_text, :guidance, :number, :parent_id, :suggested_answer, :text, :question_type, :section_id) - sidebar proc{I18n.t("admin.questions")}, :only => :show, :if => proc { (Question.where("section_id = ?", params[:id])).count >= 1} do - table_for( Question.where("section_id = ?", params[:id] ).order("number")) do - column (:number){|question| question.number} - column (I18n.t("admin.question")){|question| link_to question.text, [:admin, question]} - end - - end - - #form - form do |f| - f.inputs "Details" do - f.input :title - f.input :number - f.input :version, :collection => Version.all.map{ |ver| [ver.title, ver.id] } - f.input :organisation, :as => :select, :collection => Org.order('name').map{|orgp|[orgp.name, orgp.id]} - f.input :description - end - - f.actions - end - - controller do - def permitted_params - params.permit! - end - end -end diff --git a/app/admin/suggested_answer.rb b/app/admin/suggested_answer.rb deleted file mode 100644 index 9c46eab..0000000 --- a/app/admin/suggested_answer.rb +++ /dev/null @@ -1,33 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register SuggestedAnswer do - permit_params :question_id, :organisation_id - - menu :priority => 4, :label => proc{I18n.t('admin.sug_answer')}, :parent => "Templates management" - - - #form - form do |f| - f.inputs "Details" do - f.input :question_id, :label => I18n.t('admin.question'), - :as => :select, - :collection => Question.order('text').map{|ques|[ques.text, ques.id]} - f.input :organisation_id, :label => I18n.t('admin.org_title'), - :as => :select, - :collection => Org.order('name').map{|orgp|[orgp.name, orgp.id]} - f.input :text - f.input :is_example - end - f.actions - end - - controller do - def permitted_params - params.permit! - end - end -end diff --git a/app/admin/template.rb b/app/admin/template.rb deleted file mode 100644 index 2f2695b..0000000 --- a/app/admin/template.rb +++ /dev/null @@ -1,125 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register Template do - permit_params :title, :description, :organisation_id, :published, :is_default - - menu :priority => 11, :label => proc{ I18n.t('admin.template')}, :parent => "Templates management" - - # FIXME: The below member_actions only work on :export settings. - member_action :settings do - @template = resource - @settings = resource.settings(:export) - end - - member_action :update_settings, method: :put do - new_settings = params[:settings][:export] - - settings = resource.settings(:export).tap do |s| - s.formatting, s.max_pages = if params[:commit] != 'Reset' - [ - new_settings[:formatting].try(:deep_symbolize_keys), - new_settings[:max_pages].try(:to_i) - ] - else - [ nil, nil ] - end - end - - if settings.save - redirect_to(action: :show, flash: { notice: I18n.t('admin.settings_updated') }) - else - settings.formatting = nil - @template = resource - @settings = settings - render(action: :settings) - end - end - - action_item(:edit) do - link_to(I18n.t('helpers.settings.title'), settings_admin_template_path(resource.id)) - end - - index do - column :title do |dmptemp| - link_to dmptemp.title, [:admin, dmptemp] - end - column :description do |descr| - if !descr.description.nil? then - descr.description.html_safe - end - end - column I18n.t('admin.org_title'), :sortable => :organisation_id do |org_title| - if !org_title.organisation.nil? then - link_to org_title.organisation.name, [:admin, org_title.organisation] - else - '-' - end - end - column :published - column :is_default - - actions defaults: true do |template| - link_to(I18n.t('helpers.settings.title'), settings_admin_template_path(template.id)) - end - end - - - # show Template details - show do - attributes_table do - row :title - row :description do |descr| - if !descr.description.nil? then - descr.description.html_safe - end - end - row I18n.t('admin.org_title'), :sortable => :organisation_id do |org_title| - if !org_title.organisation.nil? then - link_to org_title.organisation.name, [:admin, org_title.organisation] - else - '-' - end - end - row :published - row :is_default - row :created_at - row :updated_at - end - end - - #phases sidebar - sidebar I18n.t('admin.phases'), :only => :show, :if => proc { template.phases.count >= 1} do - table_for template.phases.order("number asc") do |temp_phases| - column :number - column :title do |row| - link_to row.title, [:admin, row] - end - end - end - - #form - form do |f| - f.inputs "Details" do - f.input :title - f.input :description - f.input :organisation_id, :label => I18n.t('admin.org_title'), - :as => :select, - :collection => Org.order('name').map{|orgp|[orgp.name, orgp.id]} - f.input :published - f.input :is_default - end - f.actions - end - - controller do - def permitted_params - params.permit! - end - end - -end - diff --git a/app/admin/theme.rb b/app/admin/theme.rb deleted file mode 100644 index 913f32e..0000000 --- a/app/admin/theme.rb +++ /dev/null @@ -1,77 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register Theme do - permit_params :description, :title, :locale - - menu :priority => 12, :label => "Themes" - - index do - column :title , :sortable => :title do |theme| - link_to theme.title, [:admin, theme] - end - column :description do |descr| - if !descr.description.nil? then - descr.description.html_safe - end - end - - actions - end - - #show details of a theme - show do - attributes_table do - row :title - row :description - row :created_at - row :updated_at - end - - table_for( (Theme.find(params[:id]).questions).order('number')) do - column (:number){|question| question.number} - column (I18n.t("admin.question")){|question| link_to question.text, [:admin, question]} - column (I18n.t("admin.template")){|question| - if !question.section.nil? then - if !question.section.version.nil? then - if !question.section.version.phase.nil? then - if !question.section.version.phase.dmptemplate.nil? then - link_to question.section.version.phase.dmptemplate.title, [:admin, question.section.version.phase.dmptemplate] - else - I18n.t('admin.no_template') - end - else - I18n.t('admin.no_phase') - end - else - I18n.t('admin.no_version') - end - else - I18n.t('admin.no_section') - end - } - end - end - - - - #form - form do |f| - f.inputs "Details" do - f.input :title - f.input :description - end - f.actions - end - - - controller do - def permitted_params - params.permit! - end - end - -end diff --git a/app/admin/token_permission_type.rb b/app/admin/token_permission_type.rb deleted file mode 100644 index 5c804e8..0000000 --- a/app/admin/token_permission_type.rb +++ /dev/null @@ -1,33 +0,0 @@ -ActiveAdmin.register TokenPermissionType do - permit_params :token_type, :text_description - - menu priority: 40, label: proc{ I18n.t('admin.token_permission_type')}, parent: "Api" - - # TODO: Find better fix for the undefined method xxx_id_eq - remove_filter :org_token_permissions - - index do - column I18n.t('admin.token_permission_type'), sortable: :token_type do |n| - link_to n.token_type, [:admin, n] - end - column I18n.t('admin.permission_description') do |n| - link_to n.text_description, [:admin, n] - end - - actions - end - - show do - attributes_table do - row :token_type - row :text_description - end - end - - controller do - def permitted_params - params.permit! - end - end - -end diff --git a/app/admin/user.rb b/app/admin/user.rb deleted file mode 100644 index 1456f53..0000000 --- a/app/admin/user.rb +++ /dev/null @@ -1,99 +0,0 @@ -# [+Project:+] DMPRoadmap -# [+Description:+] -# -# [+Created:+] 03/09/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center - -ActiveAdmin.register User do - permit_params :api_token, :password_confirmation, :encrypted_password, :remember_me, :id, :email, :firstname, :orcid_id, :shibboleth_id, :user_status_id, :surname, :user_type_id, :organisation_id, :skip_invitation, :other_organisation, :accept_terms, :role_ids - - menu :priority => 15, :label => proc{ I18n.t('admin.user')}, :parent => "User management" - - filter :firstname - filter :surname - filter :email - filter :organisation - filter :created_at - filter :updated_at - - - - index do - - column I18n.t('admin.user_name'), :sortable => :email do |user_email| - link_to user_email.email, [:admin, user_email] - end - column I18n.t('admin.firstname'), :sortable => :firstname do |use_first| - link_to use_first.firstname, [:admin, use_first] - end - column I18n.t('admin.surname'), :sortable => :surname do |user| - link_to user.surname, [:admin, user] - end - column I18n.t('admin.last_logged_in'), :last_sign_in_at - - column I18n.t('admin.org_title'), :sortable => 'organisation.name' do |org_title| - if !org_title.organisation.nil? then - link_to org_title.organisation.name, [:admin, org_title.organisation] - end - end - - actions - end - - show do - attributes_table do - row :firstname - row :surname - row :email - row :orcid_id - row I18n.t('admin.org_title'), :organisation_id do |org_title| - if !org_title.organisation_id.nil? then - link_to org_title.organisation.name, [:admin, org_title.organisation] - end - end - row :other_organisation - row I18n.t('admin.user_role') do - (user.roles.map{|ro| link_to ro.name, [:admin, ro]}).join(', ').html_safe - end - # row :shibboleth_id - row :last_sign_in_at - row :sign_in_count - row :api_token - - end - end - - - form do |f| - f.inputs "Details" do - f.input :firstname - f.input :surname - f.input :email - f.input :orcid_id - f.input :api_token - # f.input :shibboleth_id - f.input :organisation_id, :label => I18n.t('admin.org_title'), - :as => :select, - :collection => Org.order('name').map{|orgp|[orgp.name, orgp.id]} - f.input :other_organisation - f.input :role_ids, :label => I18n.t('admin.user_role'), - :as => :select, - :multiple => true, - :include_blank => I18n.t('helpers.none'), - :collection => Role.order('name').map{|ro| [ro.name, ro.id]} - end - - f.actions - end - - - - controller do - - def permitted_params - params.permit! - end - - end - -end diff --git a/app/controllers/admin/annotations_controller.rb b/app/controllers/admin/annotations_controller.rb new file mode 100644 index 0000000..f0881d1 --- /dev/null +++ b/app/controllers/admin/annotations_controller.rb @@ -0,0 +1,21 @@ +module Admin + class AnnotationsController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Annotation. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Annotation.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/answers_controller.rb b/app/controllers/admin/answers_controller.rb new file mode 100644 index 0000000..8960f9f --- /dev/null +++ b/app/controllers/admin/answers_controller.rb @@ -0,0 +1,21 @@ +module Admin + class AnswersController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Answer. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Answer.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/application_controller.rb b/app/controllers/admin/application_controller.rb new file mode 100644 index 0000000..0018efc --- /dev/null +++ b/app/controllers/admin/application_controller.rb @@ -0,0 +1,25 @@ +# All Administrate controllers inherit from this `Admin::ApplicationController`, +# making it the ideal place to put authentication logic or other +# before_actions. +# +# If you want to add pagination or other controller-level concerns, +# you're free to overwrite the RESTful controller actions. +module Admin + class ApplicationController < Administrate::ApplicationController + before_action :authenticate_admin + + protect_from_forgery with: :exception + include Pundit + rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized + + def authenticate_admin + redirect_to root_path unless user_signed_in? && current_user.can_super_admin? + end + + # Override this value to specify the number of elements to display at a time + # on index pages. Defaults to 20. + # def records_per_page + # params[:per_page] || 20 + # end + end +end diff --git a/app/controllers/admin/exported_plans_controller.rb b/app/controllers/admin/exported_plans_controller.rb new file mode 100644 index 0000000..e4bde90 --- /dev/null +++ b/app/controllers/admin/exported_plans_controller.rb @@ -0,0 +1,21 @@ +module Admin + class ExportedPlansController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = ExportedPlan. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # ExportedPlan.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/guidance_groups_controller.rb b/app/controllers/admin/guidance_groups_controller.rb new file mode 100644 index 0000000..95d3e7c --- /dev/null +++ b/app/controllers/admin/guidance_groups_controller.rb @@ -0,0 +1,21 @@ +module Admin + class GuidanceGroupsController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = GuidanceGroup. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # GuidanceGroup.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/guidances_controller.rb b/app/controllers/admin/guidances_controller.rb new file mode 100644 index 0000000..1f2495f --- /dev/null +++ b/app/controllers/admin/guidances_controller.rb @@ -0,0 +1,21 @@ +module Admin + class GuidancesController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Guidance. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Guidance.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/identifier_schemes_controller.rb b/app/controllers/admin/identifier_schemes_controller.rb new file mode 100644 index 0000000..eb50d8a --- /dev/null +++ b/app/controllers/admin/identifier_schemes_controller.rb @@ -0,0 +1,21 @@ +module Admin + class IdentifierSchemesController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = IdentifierScheme. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # IdentifierScheme.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/languages_controller.rb b/app/controllers/admin/languages_controller.rb new file mode 100644 index 0000000..e58baa9 --- /dev/null +++ b/app/controllers/admin/languages_controller.rb @@ -0,0 +1,21 @@ +module Admin + class LanguagesController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Language. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Language.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/notes_controller.rb b/app/controllers/admin/notes_controller.rb new file mode 100644 index 0000000..db832f4 --- /dev/null +++ b/app/controllers/admin/notes_controller.rb @@ -0,0 +1,21 @@ +module Admin + class NotesController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Note. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Note.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/orgs_controller.rb b/app/controllers/admin/orgs_controller.rb new file mode 100644 index 0000000..d68f358 --- /dev/null +++ b/app/controllers/admin/orgs_controller.rb @@ -0,0 +1,21 @@ +module Admin + class OrgsController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Org. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Org.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/perms_controller.rb b/app/controllers/admin/perms_controller.rb new file mode 100644 index 0000000..99e9b95 --- /dev/null +++ b/app/controllers/admin/perms_controller.rb @@ -0,0 +1,21 @@ +module Admin + class PermsController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Perm. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Perm.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/phases_controller.rb b/app/controllers/admin/phases_controller.rb new file mode 100644 index 0000000..de6e3c3 --- /dev/null +++ b/app/controllers/admin/phases_controller.rb @@ -0,0 +1,21 @@ +module Admin + class PhasesController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Phase. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Phase.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/plan_guidance_groups_controller.rb b/app/controllers/admin/plan_guidance_groups_controller.rb new file mode 100644 index 0000000..0eeb458 --- /dev/null +++ b/app/controllers/admin/plan_guidance_groups_controller.rb @@ -0,0 +1,21 @@ +module Admin + class PlanGuidanceGroupsController < Admin::ApplicationController + # To customize the behavior of this controller, + # simply overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = PlanGuidanceGroup. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # PlanGuidanceGroup.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/plans_controller.rb b/app/controllers/admin/plans_controller.rb new file mode 100644 index 0000000..424389f --- /dev/null +++ b/app/controllers/admin/plans_controller.rb @@ -0,0 +1,21 @@ +module Admin + class PlansController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Plan. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Plan.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/question_formats_controller.rb b/app/controllers/admin/question_formats_controller.rb new file mode 100644 index 0000000..1338b69 --- /dev/null +++ b/app/controllers/admin/question_formats_controller.rb @@ -0,0 +1,21 @@ +module Admin + class QuestionFormatsController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = QuestionFormat. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # QuestionFormat.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/question_options_controller.rb b/app/controllers/admin/question_options_controller.rb new file mode 100644 index 0000000..103e543 --- /dev/null +++ b/app/controllers/admin/question_options_controller.rb @@ -0,0 +1,21 @@ +module Admin + class QuestionOptionsController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = QuestionOption. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # QuestionOption.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/questions_controller.rb b/app/controllers/admin/questions_controller.rb new file mode 100644 index 0000000..be5d2a7 --- /dev/null +++ b/app/controllers/admin/questions_controller.rb @@ -0,0 +1,21 @@ +module Admin + class QuestionsController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Question. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Question.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/regions_controller.rb b/app/controllers/admin/regions_controller.rb new file mode 100644 index 0000000..6e5627b --- /dev/null +++ b/app/controllers/admin/regions_controller.rb @@ -0,0 +1,21 @@ +module Admin + class RegionsController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Region. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Region.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/roles_controller.rb b/app/controllers/admin/roles_controller.rb new file mode 100644 index 0000000..748c165 --- /dev/null +++ b/app/controllers/admin/roles_controller.rb @@ -0,0 +1,21 @@ +module Admin + class RolesController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Role. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Role.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/sections_controller.rb b/app/controllers/admin/sections_controller.rb new file mode 100644 index 0000000..3b94a0a --- /dev/null +++ b/app/controllers/admin/sections_controller.rb @@ -0,0 +1,21 @@ +module Admin + class SectionsController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Section. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Section.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/splash_logs_controller.rb b/app/controllers/admin/splash_logs_controller.rb new file mode 100644 index 0000000..aa3fa22 --- /dev/null +++ b/app/controllers/admin/splash_logs_controller.rb @@ -0,0 +1,21 @@ +module Admin + class SplashLogsController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = SplashLog. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # SplashLog.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/templates_controller.rb b/app/controllers/admin/templates_controller.rb new file mode 100644 index 0000000..8ac79e1 --- /dev/null +++ b/app/controllers/admin/templates_controller.rb @@ -0,0 +1,21 @@ +module Admin + class TemplatesController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Template. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Template.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/themes_controller.rb b/app/controllers/admin/themes_controller.rb new file mode 100644 index 0000000..9617c6c --- /dev/null +++ b/app/controllers/admin/themes_controller.rb @@ -0,0 +1,21 @@ +module Admin + class ThemesController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = Theme. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # Theme.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/token_permission_types_controller.rb b/app/controllers/admin/token_permission_types_controller.rb new file mode 100644 index 0000000..37b3487 --- /dev/null +++ b/app/controllers/admin/token_permission_types_controller.rb @@ -0,0 +1,21 @@ +module Admin + class TokenPermissionTypesController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = TokenPermissionType. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # TokenPermissionType.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/user_identifiers_controller.rb b/app/controllers/admin/user_identifiers_controller.rb new file mode 100644 index 0000000..bdf5faa --- /dev/null +++ b/app/controllers/admin/user_identifiers_controller.rb @@ -0,0 +1,21 @@ +module Admin + class UserIdentifiersController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = UserIdentifier. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # UserIdentifier.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb new file mode 100644 index 0000000..70251c0 --- /dev/null +++ b/app/controllers/admin/users_controller.rb @@ -0,0 +1,21 @@ +module Admin + class UsersController < Admin::ApplicationController + # To customize the behavior of this controller, + # you can overwrite any of the RESTful actions. For example: + # + # def index + # super + # @resources = User. + # page(params[:page]). + # per(10) + # end + + # Define a custom finder by overriding the `find_resource` method: + # def find_resource(param) + # User.find_by!(slug: param) + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/controllers/annotations_controller.rb b/app/controllers/annotations_controller.rb new file mode 100644 index 0000000..e83366b --- /dev/null +++ b/app/controllers/annotations_controller.rb @@ -0,0 +1,116 @@ +class AnnotationsController < ApplicationController + respond_to :html + after_action :verify_authorized + + #create annotations + def admin_create + # authorize the question (includes to reduce queries) + @question = Question.includes(section: { phase: :template}).find(params[:question_id]) + authorize @question + if params[:example_answer_text].present? + example_answer = init_annotation(params[:example_answer_text], @question, current_user.org, Annotation.types[:example_answer]) + end + if params[:guidance_text].present? + guidance = init_annotation(params[:guidance_text], @question, current_user.org, Annotation.types[:guidance]) + end + # if they dont exist, no requirement for them to be saved + ex_save = example_answer.present? ? example_answer.save : true + guid_save = guidance.present? ? guidance.save : true + + if ex_save && guid_save + redirect_to admin_show_phase_path(id: @question.section.phase_id, section_id: @question.section_id, question_id: @question.id, edit: 'true'), notice: _('Information was successfully created.') + else + @section = @question.section + @phase = @section.phase + @open = true + @sections = @phase.sections + @section_id = @section.id + @question_id = @example_answer.question + if !ex_save && !guid_save + flash[:notice] = failed_create_error(example_answer, _('example answer')) + '\n' + + failed_create_error(gudiance, _('guidance')) + elsif !guid_save + flash[:notice] = failed_create_error(gudiance, _('guidance')) + elsif !ex_save + flash[:notice] = failed_create_error(example_answer, _('example answer')) + end + render "phases/admin_show" + end + end + + + #update a example answer of a template + def admin_update + @question = Question.includes(section: { phase: :template}).find(params[:question_id]) + if params[:guidance_id].present? + guidance = Annotation.includes(question: {section: {phase: :template}}).find(params[:guidance_id]) + authorize guidance + end + if params[:example_answer_id].present? + example_answer = Annotation.includes(question: {section: {phase: :template}}).find(params[:example_answer_id]) + authorize example_answer + end + verify_authorized + # if guidance present, update + if params[:guidance_text].present? + if guidance.present? + guidance.text = params[:guidance_text] + else + guidance = init_annotation(params[:guidance_text], @question, current_user.org, Annotation.types[:guidance]) + end + end + # if example answer present, update + if params[:example_answer_text].present? + if example_answer.present? + example_answer.text = params[:example_answer_text] + else + example_answer = init_annotation(params[:example_answer_text], @question, current_user.org, Annotation.types[:example_answer]) + end + end + # only required to save if we updated/created one + ex_save = example_answer.present? ? example_answer.save : true + guid_save = guidance.present? ? guidance.save : true + + @section = @question.section + @phase = @section.phase + if ex_save && guid_save + redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id, question_id: @question.id, edit: 'true'), notice: _('Information was successfully updated.') + else + if !ex_save && !guid_save + flash[:notice] = failed_create_error(example_answer, _('example answer')) + '\n' + + failed_create_error(gudiance, _('guidance')) + elsif !guid_save + flash[:notice] = failed_create_error(gudiance, _('guidance')) + elsif !ex_save + flash[:notice] = failed_create_error(example_answer, _('example answer')) + end + render action: "phases/admin_show" + end + end + + #delete an annotation + def admin_destroy + @example_answer = Annotation.includes(question: { section: {phase: :template}}).find(params[:id]) + authorize @example_answer + @question = @example_answer.question + @section = @question.section + @phase = @section.phase + if @example_answer.destroy + redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id, edit: 'true'), notice: _('Information was successfully deleted.') + else + redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id, edit: 'true'), notice: flash[:notice] = failed_destroy_error(@example_answer, _('example answer')) + end + end + + private + + def init_annotation(text, question, org, type) + annotation = Annotation.new + annotation.org = org + annotation.question = question + annotation.text = text + annotation.type = type + return annotation + end + +end \ No newline at end of file diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb index 8ef2500..7d48ddf 100644 --- a/app/controllers/answers_controller.rb +++ b/app/controllers/answers_controller.rb @@ -2,49 +2,54 @@ after_action :verify_authorized respond_to :html - ## - # PUT/PATCH /[:locale]/answer/[:id] + # PUT/PATCH /answers/[:id] def update - # create a new answer based off the passed params - - ans_params = params[:answer] - plan_id = ans_params[:plan_id] - user_id = ans_params[:user_id] - question_id = ans_params[:question_id] - @answer = Answer.find_by( - plan_id: plan_id, - user_id: user_id, - question_id: question_id) - if @answer.nil? - @answer = Answer.new(params[:answer]) + p_params = permitted_params() + @answer = Answer.find_by({plan_id: p_params[:plan_id], question_id: p_params[:question_id], }) + begin + if @answer + authorize @answer + @answer.update(p_params) + if p_params[:question_option_ids].present? + @answer.touch() # Saves the record with the updated_at set to the current time. Needed if only answer.question_options is updated + end + else + @answer = Answer.new(p_params) + @answer.lock_version = 1 + authorize @answer + @answer.save() # NOTE, there is a chance to create multiple answer associated for a plan/question (IF any concurrent thread) INSERTS an answer after checking the existence of an answer (Line 8) + # In order to avoid that edge-case, it is recommended to create answers whenever a new plan is created (e.g. after_create callback) + end + rescue ActiveRecord::StaleObjectError + @stale_answer = @answer + @answer = Answer.find_by({plan_id: p_params[:plan_id], question_id: p_params[:question_id]}) end + + @plan = Plan.includes({ + sections: { + questions: [ + :answers, + :question_format + ] + } + }).find(p_params[:plan_id]) + @question = @answer.question + @section = @plan.get_section(@question.section_id) - authorize @answer + respond_to do |format| + format.js {} + end + end # End update -puts params.inspect - - @answer.text = params["answer-text-#{@answer.question_id}".to_sym] - - #TODO: check for optimistic locking - - # Is this validation necessary? -# if (@answer.question.question_format.title == I18n.t("helpers.checkbox") || -# @answer.question.question_format.title == I18n.t("helpers.multi_select_box") || -# @answer.question.question_format.title == I18n.t("helpers.radio_buttons") || -# @answer.question.question_format.title == I18n.t("helpers.dropdown")) then -# if (old_answer.nil? && @answer.option_ids.count > 0) || ((!old_answer.nil?) && (old_answer.option_ids - @answer.option_ids).count != 0 && (@answer.option_ids - old_answer.option_ids).count != 0) then -# proceed = true -# end -# end - -# if proceed - if @answer.save - redirect_to :back, status: :found, notice: I18n.t('helpers.project.answer_recorded') - else - redirect_to :back, notice: I18n.t('helpers.project.answer_error') - end -# else -# redirect_to :back, notice: I18n.t('helpers.project.answer_no_change') -# end - end + private + def permitted_params + permitted = params.require(:answer).permit(:id, :text, :plan_id, :user_id, :question_id, :lock_version, :question_option_ids => []) + if !params[:answer][:question_option_ids].nil? && !permitted[:question_option_ids].present? #If question_option_ids has been filtered out because it was a scalar value (e.g. radiobutton answer) + permitted[:question_option_ids] = [params[:answer][:question_option_ids]] # then convert to an Array + end + if !permitted[:id].present? + permitted.delete(:id) + end + return permitted + end # End permitted_params end diff --git a/app/controllers/api/v0/base_controller.rb b/app/controllers/api/v0/base_controller.rb index 631983e..c8edddd 100644 --- a/app/controllers/api/v0/base_controller.rb +++ b/app/controllers/api/v0/base_controller.rb @@ -117,31 +117,9 @@ def render_bad_credentials self.headers['WWW-Authenticate'] = "Token realm=\"\"" - render json: I18n.t("api.bad_credentials"), status: 401 + render json: _("Bad Credentials"), status: 401 end - def has_auth (auth_type) - #auth = false - # not sure if initial if is necissary, but it works with it there... refactor later? - # if !TokenPermission.where(api_token: @token).nil? - # TokenPermission.where(api_token: @token).find_each do |permission| - # if permission.token_permission_type.token_type == auth_type - # auth = true - # logger.info "we have auth" - # end - # end - # end - - #OrgTokenPermission.where(org_id: @user.org_id).find_each do |org_token_permission| - # logger.debug "#{org_token_permission.token_permission_type.token_type}" - # if org_token_permission.token_permission_type.token_type == auth_type - # auth= true - # end - #end - #return auth - tpt = TokenPermissionType.find_by(token_type: auth) - org.token_permission_types.include?(tpt) - end end end diff --git a/app/controllers/api/v0/guidance_groups_controller.rb b/app/controllers/api/v0/guidance_groups_controller.rb index d300b39..65899b9 100644 --- a/app/controllers/api/v0/guidance_groups_controller.rb +++ b/app/controllers/api/v0/guidance_groups_controller.rb @@ -2,29 +2,16 @@ module V0 class GuidanceGroupsController < Api::V0::BaseController before_action :authenticate - - def show - # check if the user has permission to use the guidances api - if has_auth(constant("token_permission_types.guidances")) - # determine if they have authorization to view this guidance group - if GuidanceGroup.can_view?(@user, params[:id]) - respond_with get_resource - else - render json: I18n.t("api.bad_resource"), status: 401 - end - else - render json: I18n.t("api.no_auth_for_endpoint"), status: 401 - end - end + #after_action :verify_authorized def index - if has_auth(constant("token_permission_types.guidances")) - @all_viewable_groups = GuidanceGroup.all_viewable(@user) - respond_with @all_viewable_groups - else - #render unauthorised - render json: I18n.t("api.no_auth_for_endpoint"), status: 401 - end + raise Pundit::NotAuthorizedError unless Api::V0::GuidanceGroupPolicy.new(@user, :guidance_group).index? + @all_viewable_groups = GuidanceGroup.all_viewable(@user) + respond_with @all_viewable_groups + end + + def pundit_user + return @user end diff --git a/app/controllers/api/v0/guidances_controller.rb b/app/controllers/api/v0/guidances_controller.rb deleted file mode 100644 index 2803ea6..0000000 --- a/app/controllers/api/v0/guidances_controller.rb +++ /dev/null @@ -1,59 +0,0 @@ -module Api - module V0 - class GuidancesController < Api::V0::BaseController - before_action :authenticate - - swagger_controller :guidances, 'Guidances' - - swagger_api :show do - summary 'Returns a single guidance item' - notes 'Notes...' - param :path, :id, :integer, :required, "Guidance Id" - param :header, 'Authentication-Token', :string, :required, 'Authentication-Token' - response :ok, "success", :Guidance - response :unauthorized - response :not_found - end - - # TODO: impliment auth on show/index - # for both, first validate that the user has the permission to use this api - # then for show, display iff they have permissions for that resource - # for index, compile the list of all groups they have permissions to view, then return - - def show - # ensure use has auth for guidances api - if has_auth("guidance") - if Guidance.can_view?(@user, params[:id]) - respond_with get_resource - else - render json: I18n.t("api.bad_resource"), status: 401 - end - else - render I18n.t("api.no_auth_for_endpoint"), status: 401 - end - end - - swagger_api :index do - summary 'Returns a list of all viewable guidances' - notes 'Notes...' - param :header, 'Authentication-Token', :string, :required, 'Authentication-Token' - response :unauthorized - end - - def index - if has_auth("guidance") - @all_viewable_guidances = Guidance.all_viewable(@user) - respond_with @all_viewable_guidances - else - render json I18n.t("api.no_auth_for_endpoint"), status: 401 - end - end - - - private - def query_params - params.permit(:id) - end - end - end -end diff --git a/app/controllers/api/v0/plans_controller.rb b/app/controllers/api/v0/plans_controller.rb index c96d174..23ae557 100644 --- a/app/controllers/api/v0/plans_controller.rb +++ b/app/controllers/api/v0/plans_controller.rb @@ -1,104 +1,48 @@ module Api module V0 - class ProjectsController < Api::V0::BaseController + class PlansController < Api::V0::BaseController before_action :authenticate - swagger_controller :projects, 'Plans' - - swagger_api :create do |api| - summary 'Returns a single guidance group item' - notes 'Notes...' - param :header, 'Authentication-Token', :string, :required, 'Authentication-Token' - response :unauthorized - response :not_found - end - ## - # Creates a new project based on the information passed in JSON to the API + # Creates a new plan based on the information passed in JSON to the API def create - # find the user's api_token permissions - # then ensure that they have the permission associated with creating plans - if has_auth(constant("api_endpoint_types.plans")) - #params[:organization_id] = Org.where(name: params[:template][:organization]) - # find_by returns nil if none found, find_by! raises an ActiveRecord error - org = Org.find_by name: params[:template][:organisation] - - # if organization exists - if !org.nil? - # if organization is funder - if org.funder? - # if organization has only 1 template - if org.templates.length == 1 - # set template id - template = org.templates.first - # else if params.template.name specified && params.template.name == one of organization's tempates - elsif !org.templates.find_by title: params[:template][:name].nil? - # set template id - template = org.templates.find_by title: params[:template][:name] - # else error: organization has more than one template and template name unspecified - else - render json: I18n.t("api.org_multiple_templates"), status: 400 and return - end - # else error: organization specified is not a funder - else - render json: I18n.t("api.org_not_funder"), status: 400 and return - end - # else error: organization does not exist - else - render json: I18n.t("api.org_dosent_exist"), status: 400 and return - end + @template = Template.live(params[:template_id]) + raise Pundit::NotAuthorizedError unless Api::V0::PlansPolicy.new(@user, @template).create? - all_groups = [] - # Check to see if the user specified guidances - if !params[:guidance].nil? - # for each specified guidance, see if it exists - params[:guidance][:name].each do |guidance_name| - group = GuidanceGroup.find_by(name: guidance_name) - # if it exists, add it to the guidances for the new project - if !group.nil? - all_groups = all_groups + [group] - end - end - end + plan_user = User.find_by(email: params[:plan][:email]) + # ensure user exists + if plan_user.blank? + User.invite!({email: params[:plan][:email]}, ( @user)) + plan_user = User.find_by(email: params[:plan][:email]) + plan_user.org = @user.org + plan_user.save + end + # ensure user's organisation is the same as api user's + raise Pundit::NotAuthorizedError, _("user must be in your organisation") unless plan_user.org == @user.org - # cant invite a user without having a current user because of devise :ivitable - # after we have auth, will be able to assign an :invited_by_id - user = User.find_by email: params[:project][:email] - # if user does not exist - if user.nil? - # invite user to DMPRoadmap - User.invite!({email: params[:project][:email]}, ( @user)) - # set project owner to user associated w/email - user = (User.find_by email: params[:project][:email]) - end - - # create new project with specified parameters - @project = Plan.new - @project.title = params[:project][:title] - @project.template = template - @project.slug = params[:project][:title] - #@project.organisation = @user.organisations.first - @project.assign_creator(user.id) - @project.guidance_groups = all_groups - - # if save successful, render success, otherwise show error - if @project.save - #render json: @project ,status: :created - render :show, status: :created - else - render json: get_resource.errors, status: :unprocessable_entity - end + # initialize the plan + @plan = Plan.new + @plan.principal_investigator = plan_user.surname.blank? ? nil : "#{plan_user.firstname} #{plan_user.surname}" + @plan.data_contact = plan_user.email + # set funder name to template's org, or original template's org + if @template.customization_of.nil? + @plan.funder_name = @template.org.name else - - render json: I18n.t("api.no_auth_for_endpoint"), status: 400 and return + @plan.funder_name = Template.where(dmptemplate_id: @template.customization_of).first.org.name + end + @plan.template = @template + @plan.title = params[:plan][:title] + if @plan.save + @plan.assign_creator(plan_user) + respond_with @plan + else + # the plan did not save + self.headers['WWW-Authenticate'] = "Token realm=\"\"" + render json: _("Bad Parameters"), status: 400 end end - # private - # def project_params - # params.require(:template).permit(:organisation, :name) - # params.require(:project).permit(:title, :email) - # end + end end end diff --git a/app/controllers/api/v0/statistics_controller.rb b/app/controllers/api/v0/statistics_controller.rb index a09bec3..b3b95a4 100644 --- a/app/controllers/api/v0/statistics_controller.rb +++ b/app/controllers/api/v0/statistics_controller.rb @@ -8,19 +8,16 @@ # @return a count of users who joined DMPonline between the optional specified dates # users are scoped to the organisation of the user initiating the call def users_joined - if has_auth(constant("token_permission_types.statistics")) - users = restrict_date_range(@user.org.users) - confirmed_users = [] - users.each do |user| - unless user.confirmed_at.blank? - confirmed_users += [user] - end + raise Pundit::NotAuthorizedError unless Api::V0::StatisticsPolicy.new(@user, :statistics).users_joined? + users = restrict_date_range(@user.org.users) + confirmed_users = [] + users.each do |user| + unless user.confirmed_at.blank? + confirmed_users += [user] end - @users_count = confirmed_users.count - respond_with @users_count - else - render json: I18n.t("api.no_auth_for_endpoint"), status: 401 end + @users_count = confirmed_users.count + respond_with @users_count end @@ -29,17 +26,26 @@ # @return the number of DMPs using the specified template between the optional specified dates # ensures that the template is owned/created by the caller's organisation def using_template - if has_auth(constant("token_permission_types.statistics")) - template = Dmptemplate.find(params[:id]) - if template.org == @user.org - @template_count = restrict_date_range(template.plans).count - respond_with @template_count + org_templates = @user.org.templates.where(customization_of: nil) + raise Pundit::NotAuthorizedError unless Api::V0::StatisticsPolicy.new(@user, org_templates.first).using_template? + @templates = {} + org_templates.each do |template| + if @templates[template.title].blank? + @templates[template.title] = {} + @templates[template.title][:title] = template.title + @templates[template.title][:id] = template.dmptemplate_id + if template.plans.present? + @templates[template.title][:uses] = restrict_date_range(template.plans).length + else + @templates[template.title][:uses] = 0 + end else - #no auth to view statistics for this template + if template.plans.present? + @templates[template.title][:uses] += restrict_date_range(template.plans).length + end end - else - render json: I18n.t("api.no_auth_for_endpoint"), status: 401 end + respond_with @templates end ## @@ -48,20 +54,29 @@ # the uses are restricted to DMPs created by users of the same organisation # as the user who ititiated the call def plans_by_template - if has_auth(constant("token_permission_types.statistics")) - @org_projects = [] - @user.org.users.each do |user| - user.plans.each do |plan| - unless @org_projects.include? plan - @org_projects += [plan] - end + raise Pundit::NotAuthorizedError unless Api::V0::StatisticsPolicy.new(@user, :statistics).plans_by_template? + org_projects = [] + @user.org.users.each do |user| + user.plans.each do |plan| + unless org_projects.include? plan + org_projects += [plan] end end - @org_projects = restrict_date_range(@org_projects) - respond_with @org_projects - else - render json: I18n.t("api.no_auth_for_endpoint"), status: 401 end + org_projects = restrict_date_range(org_projects) + @templates = {} + org_projects.each do |plan| + # if hash exists + if @templates[plan.template.title].blank? + @templates[plan.template.title] = {} + @templates[plan.template.title][:title] = plan.template.title + @templates[plan.template.title][:id] = plan.template.dmptemplate_id + @templates[plan.template.title][:uses] = 1 + else + @templates[plan.template.title][:uses] += 1 + end + end + respond_with @templates end ## @@ -70,20 +85,17 @@ # DMPs must be owned by a user who's organisation is the same as the user # who generates the call def plans - if has_auth(constant("token_permission_types.statistics")) - @org_projects = [] - @user.org.users.each do |user| - user.plans.each do |plan| - unless @org_projects.include? plan - @org_projects += [plan] - end + raise Pundit::NotAuthorizedError unless Api::V0::StatisticsPolicy.new(@user, :statistics).plans? + @org_plans = [] + @user.org.users.each do |user| + user.plans.each do |plan| + unless @org_plans.include? plan + @org_plans += [plan] end end - @org_projects = restrict_date_range(@org_projects) - respond_with @org_projects - else - render json: I18n.t("api.no_auth_for_endpoint"), status: 401 end + @org_plans = restrict_date_range(@org_plans) + respond_with @org_plans end diff --git a/app/controllers/api/v0/templates_controller.rb b/app/controllers/api/v0/templates_controller.rb index 3ab1207..8560068 100644 --- a/app/controllers/api/v0/templates_controller.rb +++ b/app/controllers/api/v0/templates_controller.rb @@ -9,26 +9,39 @@ # @return a list of templates ordered by organisation def index # check if the user has permissions to use the templates API - if has_auth(constant("api_endpoint_types.templates")) - @org_templates = {} - published_templates = Template.includes(:org).where(customization_of: nil, published: true).order(:org_id, :version) - published_templates.all.each do |temp| - if @org_templates[temp.org].present? - if @org_templates[temp.org][temp.dmptemplate_id].nil? - @org_templates[temp.org][temp.dmptemplate_id] = temp - end - else - @org_templates[temp.org] = {} - @org_templates[temp.org][temp.dmptemplate_id] = temp - end - end - respond_with @org_templates - else - #render unauthorised - render json: I18n.t("api.no_auth_for_endpoint"), status: 401 - end + raise Pundit::NotAuthorizedError unless Api::V0::TemplatePolicy.new(@user, :guidance_group).index? - end + @org_templates = {} + + published_templates = Template.includes(:org).valid.where(customization_of: nil, published: true).order(:org_id, :version) + customized_templates = Template.includes(:org).valid.where(org_id: @user.org_id, published: true).where.not(customization_of: nil) + + published_templates.each do |temp| + if @org_templates[temp.org].present? + if @org_templates[temp.org][:own][temp.dmptemplate_id].nil? + @org_templates[temp.org][:own][temp.dmptemplate_id] = temp + end + else + @org_templates[temp.org] = {} + @org_templates[temp.org][:own] = {} + @org_templates[temp.org][:cust] = {} + @org_templates[temp.org][:own][temp.dmptemplate_id] = temp + end + end + customized_templates.each do |temp| + if @org_templates[temp.org].present? + if @org_templates[temp.org][:cust][temp.dmptemplate_id].nil? + @org_templates[temp.org][:cust][temp.dmptemplate_id] = temp + end + else + @org_templates[temp.org] = {} + @org_templates[temp.org][:own] = {} + @org_templates[temp.org][:cust] = {} + @org_templates[temp.org][:cust][temp.dmptemplate_id] = temp + end + end + respond_with @org_templates + end end end end \ No newline at end of file diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index a02811c..2d3dcb0 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -8,44 +8,42 @@ include Pundit helper_method GlobalHelpers.instance_methods - # Override build_footer method in ActiveAdmin::Views::Pages - require 'active_admin_views_pages_base.rb' rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized def user_not_authorized - redirect_to root_url, alert: I18n.t('unauthorized') + if user_signed_in? + redirect_to plans_url, notice: _('You are not authorized to perform this action.') + else + redirect_to root_url, alert: _('You need to sign in or sign up before continuing.') + end end before_filter :set_gettext_locale after_filter :store_location + # Sets FastGettext locale for every request made def set_gettext_locale - if params[:locale] and FastGettext.default_available_locales.include?(params[:locale]) - FastGettext.locale = params[:locale] - elsif user_signed_in? and !current_user[:language_id].nil? - FastGettext.locale = Language.find_by_id(current_user[:language_id]).abbreviation #Relies on successful db call - elsif user_signed_in? and current_user.org.present? and !current_user.org[:language_id].nil? - FastGettext.locale = Language.find_by_id(current_user.org[:language_id]).abbreviation #Relies on successful db call - else - FastGettext.locale = FastGettext.default_locale - end - puts 'FastGettext.locale = '+FastGettext.locale + FastGettext.locale = session[:locale] || FastGettext.default_locale end - # Added setting for passing local params across pages - def default_url_options(options = {}) - { locale: I18n.locale }.merge options + # PATCH /locale/:locale REST method + def set_locale_session + if FastGettext.default_available_locales.include?(params[:locale]) + session[:locale] = params[:locale] + end + redirect_to(request.referer || root_path) #redirects the user to URL where she/he was when the request to this resource was made or root if none is encountered end def store_location # store last url - this is needed for post-login redirect to whatever the user last visited. - if (request.fullpath != "/users/sign_in" && \ - request.fullpath != "/users/sign_up" && \ - request.fullpath != "/users/password" && \ - request.fullpath != "/users/sign_up?nosplash=true" && \ - !request.xhr?) # don't store ajax calls + unless ["/users/sign_in", + "/users/sign_up", + "/users/password", + "/users/invitation/accept", + ].any? { |ur| request.fullpath.include?(ur) } \ + or request.xhr? # don't store ajax calls session[:previous_url] = request.fullpath end end @@ -71,23 +69,16 @@ redirect_to root_path unless user_signed_in? && (current_user.can_add_orgs? || current_user.can_change_org? || current_user.can_super_admin?) end - def get_plan_list_columns - if user_signed_in? - @selected_columns = current_user.settings(:plan_list).columns + def failed_create_error(obj, obj_name) + "#{_('Could not create your %{o}.') % {o: obj_name}} #{errors_to_s(obj)}" + end - # handle settings saved and stored using an older version of the settings gem - if @selected_columns.kind_of? Hash - unless @selected_columns['elements'].nil? - @selected_columns = @selected_columns['elements'].collect{|k,v| puts "#{k} - #{v}"; k} - end - end - - # If the settings are missing or stored in the wrong format for some reason - # then use the defaults columns - @selected_columns = Settings::PlanList::DEFAULT_COLUMNS if @selected_columns.empty? - - @all_columns = Settings::PlanList::ALL_COLUMNS - end + def failed_update_error(obj, obj_name) + "#{_('Could not update your %{o}.') % {o: obj_name}} #{errors_to_s(obj)}" + end + + def failed_destroy_error(obj, obj_name) + "#{_('Could not delete the %{o}.') % {o: obj_name}} #{errors_to_s(obj)}" end private @@ -101,4 +92,32 @@ def prepend_view_paths prepend_view_path "app/views/branded" end + + def errors_to_s(obj) + if obj.errors.count > 0 + msg = "
" + obj.errors.each do |e,m| + if m.include?('empty') || m.include?('blank') + msg += "#{_(e)} - #{_(m)}
" + else + msg += "'#{obj[e]}' - #{_(m)}
" + end + end + msg + end + end + + ## + # Sign out of Shibboleth SP local session too. + # ------------------------------------------------------------- + def after_sign_out_path_for(resource_or_scope) + if Rails.application.config.shibboleth_enabled + return Rails.application.config.shibboleth_logout_url + root_url + super + else + super + end + end + # ------------------------------------------------------------- + end diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb deleted file mode 100644 index 8070b25..0000000 --- a/app/controllers/confirmations_controller.rb +++ /dev/null @@ -1,9 +0,0 @@ -class ConfirmationsController < Devise::ConfirmationsController - - protected - - def after_confirmation_path_for(resource_name, resource) - root_path - end - -end \ No newline at end of file diff --git a/app/controllers/contacts_controller.rb b/app/controllers/contacts_controller.rb deleted file mode 100644 index 36fa10f..0000000 --- a/app/controllers/contacts_controller.rb +++ /dev/null @@ -1,28 +0,0 @@ -class ContactsController < ContactUs::ContactsController - respond_to :html - - ## - # create - # - # POST - Create a Contact Request - def create - @contact = ContactUs::Contact.new(params[:contact_us_contact]) - if (!user_signed_in?) - if verify_recaptcha(message: "You have not added the validation words correctly") && @contact.save - flash[:notice] = t('contact_us.notices.success') - redirect_to(root_path) - else # recaptcha invalid or contact failed to save - flash[:alert] = t('contact_us.notices.error') - render_new_page - end - else # no user signed in - if @contact.save - flash[:notice] = t('contact_us.notices.success') - redirect_to :controller => 'projects', :action => 'index' - else # contact failed to save - flash[:alert] = t('contact_us.notices.error') - render_new_page - end - end - end -end \ No newline at end of file diff --git a/app/controllers/guidance_groups_controller.rb b/app/controllers/guidance_groups_controller.rb index 3729dd7..ce09688 100644 --- a/app/controllers/guidance_groups_controller.rb +++ b/app/controllers/guidance_groups_controller.rb @@ -9,11 +9,11 @@ end - # GET add new guidance groups - def admin_new + # GET add new guidance groups + def admin_new @guidance_group = GuidanceGroup.new authorize @guidance_group - end + end # POST /guidance_groups @@ -27,45 +27,48 @@ end if @guidance_group.save - redirect_to admin_index_guidance_path, notice: I18n.t('org_admin.guidance_group.created_message') + redirect_to admin_index_guidance_path, notice: _('Guidance group was successfully created.') else - render action: "new" + flash[:notice] = failed_create_error(@guidance_group, _('guidance group')) + render 'admin_new' end end # GET /guidance_groups/1/edit def admin_edit - @guidance_group = GuidanceGroup.find(params[:id]) - authorize @guidance_group + @guidance_group = GuidanceGroup.find(params[:id]) + authorize @guidance_group end # PUT /guidance_groups/1 def admin_update - @guidance_group = GuidanceGroup.find(params[:id]) + @guidance_group = GuidanceGroup.find(params[:id]) authorize @guidance_group @guidance_group.org_id = current_user.org_id + @guidance_group.published = true unless params[:save_publish].nil? if @guidance_group.update_attributes(params[:guidance_group]) - redirect_to admin_index_guidance_path(params[:guidance_group]), notice: I18n.t('org_admin.guidance_group.updated_message') + redirect_to admin_index_guidance_path(params[:guidance_group]), notice: _('Guidance group was successfully updated.') else - render action: "edit" + flash[:notice] = failed_update_error(@guidance_group, _('guidance group')) + render 'admin_edit' end end - +# TODO: This does not have a route in config/routes.rb and is unreachable! # PUT /guidance_groups/1 def admin_update_publish - @guidance_group = GuidanceGroup.find(params[:id]) + @guidance_group = GuidanceGroup.find(params[:id]) authorize @guidance_group @guidance_group.org.id = current_user.org.id @guidance_group.published = true if @guidance_group.update_attributes(params[:guidance_group]) - redirect_to admin_index_guidance_path(params[:guidance_group]), notice: I18n.t('org_admin.guidance_group.updated_message') + redirect_to admin_index_guidance_path(params[:guidance_group]), notice: _('Guidance group was successfully updated.') else - render action: "edit" + redirect_to admin_index_guidance_path(@guidance_group), notice: failed_update_error(@guidance_group, _('guidance group')) end end @@ -73,11 +76,13 @@ # DELETE /guidance_groups/1 # DELETE /guidance_groups/1.json def admin_destroy - @guidance_group = GuidanceGroup.find(params[:id]) + @guidance_group = GuidanceGroup.find(params[:id]) authorize @guidance_group - @guidance_group.destroy - - redirect_to admin_index_guidance_path, notice: I18n.t('org_admin.guidance_group.destroyed_message') - end + if @guidance_group.destroy + redirect_to admin_index_guidance_path, notice: _('Guidance group was successfully deleted.') + else + redirect_to admin_index_guidance_path, notice: failed_destroy_error(@guidance_group, _('guidance group')) + end + end end \ No newline at end of file diff --git a/app/controllers/guidances_controller.rb b/app/controllers/guidances_controller.rb index 75c0808..9cfcfc5 100644 --- a/app/controllers/guidances_controller.rb +++ b/app/controllers/guidances_controller.rb @@ -13,112 +13,45 @@ ## # GET /guidances/1 def admin_show - @guidance = Guidance.includes(:guidance_group, :question, :themes).find(params[:id]) + @guidance = Guidance.eager_load(:guidance_group, :themes).find(params[:id]) authorize @guidance end def admin_new @guidance = Guidance.new authorize @guidance - - #@templates = Template.funders_and_own_templates(current_user.org_id) - # Replacing weird accessor on Template - @templates = (Org.funders.collect{|o| o.templates } + current_user.org.templates).flatten - - @phases = nil - @templates.includes(:phases).each do |template| - if @phases.nil? then - @phases = template.phases.all.order('number') - else - @phases = @phases + template.phases.all.order('number') - end - end - @sections = nil - @phases.each do |phase| - if @sections.nil? then - @sections = phase.sections.all.order('number') - else - @sections = @sections + phase.sections.all.order('number') - end - end - @questions = nil - @sections.each do |section| - if @questions.nil? then - @questions = section.questions.all.order('number') - else - @questions = @questions + section.questions.all.order('number') - end - end @themes = Theme.all.order('title') @guidance_groups = GuidanceGroup.where(org_id: current_user.org_id).order('name ASC') end - #setup variables for use in the dynamic updating - def update_phases - authorize Guidance - # updates phases, versions, sections and questions based on template selected - dmptemplate = Template.find(params[:dmptemplate_id]) - # map to title and id for use in our options_for_select - @phases = dmptemplate.phases.map{|a| [a.title, a.id]}.insert(0, I18n.t('helpers.select_phase')) - @versions = dmptemplate.versions.map{|s| [s.title, s.id]}.insert(0, I18n.t('helpers.select_version')) - @sections = dmptemplate.sections.map{|s| [s.title, s.id]}.insert(0, I18n.t('helpers.select_section')) - @questions = dmptemplate.questions.map{|s| [s.text, s.id]}.insert(0, I18n.t('helpers.select_question')) - end - - def update_versions - authorize Guidance - # updates versions, sections and questions based on phase selected - phase = Phase.find(params[:phase_id]) - # map to name and id for use in our options_for_select - @versions = phase.versions.map{|s| [s.title, s.id]}.insert(0, I18n.t('helpers.select_version')) - @sections = phase.sections.map{|s| [s.title, s.id]}.insert(0, I18n.t('helpers.select_section')) - @questions = phase.questions.map{|s| [s.text, s.id]}.insert(0, I18n.t('helpers.select_question')) - end - - def update_sections - authorize Guidance - # updates sections and questions based on version selected - version = Version.find(params[:version_id]) - # map to name and id for use in our options_for_select - @sections = version.sections.map{|s| [s.title, s.id]}.insert(0, I18n.t('helpers.select_section')) - @questions = version.questions.map{|s| [s.text, s.id]}.insert(0, I18n.t('helpers.select_question')) - end - - def update_questions - authorize Guidance - # updates songs based on artist selected - section = Section.find(params[:section_id]) - @questions = section.questions.map{|s| [s.text, s.id]}.insert(0, I18n.t('helpers.select_question')) - end - ## # GET /guidances/1/edit def admin_edit - @guidance = Guidance.includes(:themes, :guidance_group).find(params[:id]) + @guidance = Guidance.eager_load(:themes, :guidance_group).find(params[:id]) authorize @guidance - @guidance_groups = GuidanceGroup.where(org_id: current_user.org_id).order('name ASC') @themes = Theme.all.order('title') + @guidance_groups = GuidanceGroup.where(org_id: current_user.org_id).order('name ASC') end ## # POST /guidances def admin_create - @guidance = Guidance.new(params[:guidance]) + @guidance = Guidance.new(guidance_params) authorize @guidance @guidance.text = params["guidance-text"] - @guidance.question_id = params["question_id"] - if @guidance.published == true then - @gg = GuidanceGroup.find(@guidance.guidance_group_ids).first - if @gg.published == false || @gg.published.nil? then - @gg.published = true - @gg.save - end + + @guidance.themes = [] + if !guidance_params[:theme_ids].nil? + guidance_params[:theme_ids].map{|t| @guidance.themes << Theme.find(t.to_i) unless t.empty? } end if @guidance.save - redirect_to admin_show_guidance_path(@guidance), notice: I18n.t('org_admin.guidance.created_message') + redirect_to admin_show_guidance_path(@guidance), notice: _('Guidance was successfully created.') else - render action: "new" + flash[:notice] = failed_create_error(@guidance, _('guidance')) + @themes = Theme.all.order('title') + @guidance_groups = GuidanceGroup.where(org_id: current_user.org_id).order('name ASC') + render action: "admin_new" end end @@ -128,12 +61,14 @@ @guidance = Guidance.find(params[:id]) authorize @guidance @guidance.text = params["guidance-text"] - @guidance.question_id = params["question_id"] - - if @guidance.update_attributes(params[:guidance]) - redirect_to admin_show_guidance_path(params[:guidance]), notice: I18n.t('org_admin.guidance.updated_message') + if @guidance.update_attributes(guidance_params) + redirect_to admin_show_guidance_path(params[:guidance]), notice: _('Guidance was successfully updated.') else - render action: "edit" + flash[:notice] = failed_update_error(@guidance, _('guidance')) + @themes = Theme.all.order('title') + @guidance_groups = GuidanceGroup.where(org_id: current_user.org_id).order('name ASC') + + render action: "admin_edit" end end @@ -142,9 +77,17 @@ def admin_destroy @guidance = Guidance.find(params[:id]) authorize @guidance - @guidance.destroy - - redirect_to admin_index_guidance_path + if @guidance.destroy + redirect_to admin_index_guidance_path, notice: _('Guidance was successfully deleted.') + else + redirect_to admin_index_guidance_path, notice: failed_destroy_error(@guidance, _('guidance')) + end end + + private + def guidance_params + # The form on the page is weird. The text and template/section/question stuff is outside of the normal form params + params.require(:guidance).permit(:guidance_group_id, :published, theme_ids: []) + end end \ No newline at end of file diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index a311c09..7a75e3c 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -11,6 +11,8 @@ def index if user_signed_in? name = current_user.name(false) +# TODO: Investigate if this is even relevant anymore. The name var will never be blank here because the logic in +# User says to return the email if the firstname and surname are empty regardless of the flag passed in if name.blank? redirect_to edit_user_registration_path else diff --git a/app/controllers/notes_controller.rb b/app/controllers/notes_controller.rb index 8a400f6..474281a 100644 --- a/app/controllers/notes_controller.rb +++ b/app/controllers/notes_controller.rb @@ -2,18 +2,19 @@ after_action :verify_authorized respond_to :html - ## - # POST /notes + require "pp" + def create @note = Note.new user_id = params[:new_note][:user_id] @note.user_id = user_id - answer_id = params[:new_note][:answer_id] question_id = params[:new_note][:question_id] plan_id = params[:new_note][:plan_id] + + # create answer if we dont already have one if answer_id.present? - answer = Answer.find(@note.answer_id) + answer = Answer.find(answer_id) else answer = Answer.new answer.plan_id = plan_id @@ -23,49 +24,59 @@ end @note.answer= answer - @note.text = params["#{params[:new_note][:answer_id]}new_note_text"] + @note.text = params["#{question_id}new_note_text"] authorize @note @plan = answer.plan - @phase = answer.question.section.phase + @answer = answer + @question = Question.find(question_id) if @note.save - session[:question_id_notes] = answer.question_id - redirect_to edit_plan_phase_path(@plan, @phase), status: :found, notice: I18n.t("helpers.comments.note_created") + @status = true + @notice = _('Comment was successfully created.') + else + @status = false + @notice = failed_create_error(@note, _('note')) end + notes = answer.notes.all + @num_notes = notes.count end - ## - # PUT /notes/1 + + def update @note = Note.find(params[:note][:id]) authorize @note @note.text = params["#{params[:note][:id]}_note_text"] - @plan = Plan.find(@note.plan_id) - @project = Project.find(@plan.project_id) + @answer = @note.answer + @question = @answer.question + @plan = @answer.plan if @note.update_attributes(params[:note]) - session[:question_id_notes] = @note.question_id - redirect_to edit_project_plan_path(@project, @plan), status: :found, notice: I18n.t("helpers.comments.note_updated") + @notice = _('Comment was successfully saved.') + else + @notice = failed_update_error(@note, _('note')) end end - ## - # ARCHIVE /notes/1 + + def archive @note = Note.find(params[:note][:id]) authorize @note @note.archived = true @note.archived_by = params[:note][:archived_by] - @plan = Plan.find(@note.plan_id) - @project = Project.find(@plan.project_id) + @answer = @note.answer + @question = @answer.question + @plan = @answer.plan if @note.update_attributes(params[:note]) - session[:question_id_notes] = @note.question_id - redirect_to edit_project_plan_path(@project, @plan), status: :found, notice: I18n.t("helpers.comments.note_removed") + @notice = _('Comment removed.') + else + @notice = failed_destroy_error(@note, _('note')) end end end diff --git a/app/controllers/orgs_controller.rb b/app/controllers/orgs_controller.rb index 905fd06..d0f5a8e 100644 --- a/app/controllers/orgs_controller.rb +++ b/app/controllers/orgs_controller.rb @@ -20,24 +20,33 @@ ## # PUT /organisations/1 def admin_update + attrs = org_params @org = Org.find(params[:id]) authorize @org @org.banner_text = params["org_banner_text"] - @org.logo = params[:org][:logo] if params[:org][:logo] - assign_params = params[:org].dup - assign_params.delete(:logo) - assign_params.delete(:contact_email) unless params[:org][:contact_email].present? + @org.logo = org_params[:logo] if org_params[:logo] begin - if @org.update_attributes(assign_params) - redirect_to admin_show_org_path(params[:id]), notice: I18n.t("admin.org_updated_message") + if @org.update_attributes(org_params) + redirect_to admin_show_org_path(params[:id]), notice: _('Organisation was successfully updated.') else - flash[:notice] = @org.errors.collect{|e| e.message}.join('
').html_safe + # For some reason our custom validator returns as a string and not a hash like normal activerecord + # errors. We followed the example provided in the Rails guides when building the validator so + # its unclear why its doing this. Placing a check here for the data type. We should reasses though + # when doing a broader eval of the look/feel of the site and we come up with a standardized way of + # displaying errors + flash[:notice] = failed_update_error(@org, _('organisation')) render action: "admin_edit" end rescue Dragonfly::Job::Fetch::NotFound => dflye - flash[:notice] = I18n.t("admin.org_bad_logo") + flash[:notice] = _('There seems to be a problem with your logo. Please upload it again.') render action: "admin_edit" end end + + private + def org_params + params.require(:org).permit(:name, :abbreviation, :target_url, :is_other, :banner_text, :language_id, + :region_id, :logo, :contact_email, :remove_logo) + end end diff --git a/app/controllers/phases_controller.rb b/app/controllers/phases_controller.rb index b65f33f..21084a9 100644 --- a/app/controllers/phases_controller.rb +++ b/app/controllers/phases_controller.rb @@ -3,44 +3,82 @@ after_action :verify_authorized - TEXTAREA = QuestionFormat.where(title: "Text area").first.id - TEXTFIELD = QuestionFormat.where(title: "Text field").first.id - RADIO = QuestionFormat.where(title: "Radio buttons").first.id - CHECKBOX = QuestionFormat.where(title: "Check box").first.id - DROPDOWN = QuestionFormat.where(title: "Dropdown").first.id - MULTI = QuestionFormat.where(title: "Multi select box").first.id - - # GET /plans/PLANID/phases/PHASEID/edit - def edit - - @textarea = TEXTAREA - @textfield = TEXTFIELD - @radio = RADIO - @checkbox = CHECKBOX - @dropdown = DROPDOWN - @multi = MULTI - @plan = Plan.find(params[:plan_id]) + # GET /plans/:plan_id/phases/:id/edit + def edit + + @plan = Plan.eager_load2(params[:plan_id]) + # authorization done on plan so found in plan_policy authorize @plan - @plan_data = @plan.to_hash - phase_id = params[:id].to_i - @phase = Phase.find(phase_id) - @phase_data = @plan_data["template"]["phases"].select {|p| p["id"] == phase_id}.first + @phase = @plan.template.phases.select {|p| p.id == phase_id}.first + @readonly = !@plan.editable_by?(current_user.id) + + # Now we need to get all the themed guidance for the plan. + # TODO: think this through again, there may be a better way to do this. + # + # Ultimately we are heading to a map from question id to theme to guidance. + # + # get the ids of the dynamically selected guidance groups + # and keep a map of them so we can extract the names later + guidance_groups_ids = @plan.guidance_groups.map{|pgg| pgg.id} + guidance_groups = GuidanceGroup.includes({guidances: :themes}).where(published: true, id: guidance_groups_ids) + + # create a map from theme to array of guidances + # where guidance is a hash with the text and the org name + theme_guidance = {} + + guidance_groups.includes(guidances:[:themes]).each do |guidance_group| + guidance_group.guidances.each do |guidance| + if guidance.published + guidance.themes.each do |theme| + title = theme.title + if !theme_guidance.has_key?(title) + theme_guidance[title] = Array.new + end + theme_guidance[title] << { + text: guidance.text, + org: guidance_group.name + ':' + } + end + end + end + end + + # create hash from question id to theme to guidance array + # so when we arerendering a question we can grab the guidance out of this + # + # question_guidance = { + # question.id => { + # theme => [ {text: "......", org: "....."} ] + # } + # } + @question_guidance = {} + @plan.questions.each do |question| + qg = {} + question.themes.each do |t| + title = t.title + qg[title] = theme_guidance[title] if theme_guidance.has_key?(title) + end + if !@question_guidance.has_key?(question.id) + @question_guidance[question.id] = Array.new + end + @question_guidance[question.id] = qg + end if !user_signed_in? then respond_to do |format| - format.html { redirect_to edit_user_registration_path } - end - end + format.html { redirect_to edit_user_registration_path } + end + end - end - - - # GET /plans/PLANID/phases/PHASEID/status.json + end + + + # GET /plans/PLANID/phases/PHASEID/status.json def status - @plan = Plan.find(params[:plan_id]) + @plan = Plan.eager_load(params[:plan_id]) authorize @plan if user_signed_in? && @plan.readable_by?(current_user.id) then respond_to do |format| @@ -52,4 +90,138 @@ end + + #show and edit a phase of the template + def admin_show + @phase = Phase.eager_load(:sections).find_by('phases.id = ?', params[:id]) + authorize @phase + + @current = Template.current(@phase.template.dmptemplate_id) + @edit = (@phase.template.org == current_user.org) && (@phase.template == @current) + #@edit = params[:edit] == "true" ? true : false + + #verify if there are any sections if not create one + @sections = @phase.sections + if !@sections.any?() || @sections.count == 0 + @section = @phase.sections.build + @section.phase = @phase + @section.title = '' + @section.number = 1 + @section.published = true + @section.modifiable = true + @section.save + @new_sec = true + end + #verify if section_id has been passed, if so then open that section + if params.has_key?(:section_id) + @open = true + @section_id = params[:section_id].to_i + end + if params.has_key?(:question_id) + @question_id = params[:question_id].to_i + end + if @phase.template.customization_of.present? + @original_org = Template.where(dmptemplate_id: @phase.template.customization_of).first.org + else + @original_org = @phase.template.org + end + end + + + #preview a phase + def admin_preview + @phase = Phase.find(params[:id]) + authorize @phase + @template = @phase.template + end + + + #add a new phase to a passed template + def admin_add + @template = Template.find(params[:id]) + @phase = Phase.new + @phase.template = @template + authorize @phase + @phase.number = @template.phases.count + 1 + end + + + #create a phase + def admin_create + @phase = Phase.new(params[:phase]) + authorize @phase + + @phase.description = params["phase-desc"] + @phase.modifiable = true + if @phase.save + @phase.template.dirty = true + @phase.template.save! + + redirect_to admin_show_phase_path(id: @phase.id, edit: 'true'), notice: _('Information was successfully created.') + else + flash[:notice] = failed_create_error(@phase, _('phase')) + @template = @phase.template + render "admin_add" + end + end + + + #update a phase of a template + def admin_update + @phase = Phase.find(params[:id]) + authorize @phase + @phase.description = params["phase-desc"] + if @phase.update_attributes(params[:phase]) + @phase.template.dirty = true + @phase.template.save! + + redirect_to admin_show_phase_path(@phase), notice: _('Information was successfully updated.') + else + @sections = @phase.sections + @template = @phase.template + # These params may not be available in this context so they may need + # to be set to true without the check + @edit = true + @open = !params[:section_id].nil? + @section_id = (params[:section_id].nil? ? nil : params[:section_id].to_i) + @question_id = (params[:question_id].nil? ? nil : params[:question_id].to_i) + flash[:notice] = failed_update_error(@phase, _('phase')) + if @phase.template.customization_of.present? + @original_org = Template.where(dmptemplate_id: @phase.template.customization_of).first.org + else + @original_org = @phase.template.org + end + render 'admin_show' + end + end + + #delete a phase + def admin_destroy + @phase = Phase.find(params[:phase_id]) + authorize @phase + @template = @phase.template + if @phase.destroy + @template.dirty = true + @template.save! + + redirect_to admin_template_template_path(@template), notice: _('Information was successfully deleted.') + else + @sections = @phase.sections + + # These params may not be available in this context so they may need + # to be set to true without the check + @edit = true + @open = !params[:section_id].nil? + @section_id = (params[:section_id].nil? ? nil : params[:section_id].to_i) + @question_id = (params[:question_id].nil? ? nil : params[:question_id].to_i) + flash[:notice] = failed_destroy_error(@phase, _('phase')) + if @phase.template.customization_of.present? + @original_org = Template.where(dmptemplate_id: @phase.template.customization_of).first.org + else + @original_org = @phase.template.org + end + render 'admin_show' + end + end + end diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb index edae8f5..f7edc1f 100644 --- a/app/controllers/plans_controller.rb +++ b/app/controllers/plans_controller.rb @@ -1,17 +1,8 @@ class PlansController < ApplicationController require 'pp' - #Uncomment the line below in order to add authentication to this page - users without permission will not be able to add new plans - #load_and_authorize_resource - # - before_filter :get_plan_list_columns, only: %i( index ) - after_action :verify_authorized + helper SettingsTemplateHelper - TEXTAREA = QuestionFormat.where(title: "Text area").first.id - TEXTFIELD = QuestionFormat.where(title: "Text field").first.id - RADIO = QuestionFormat.where(title: "Radio buttons").first.id - CHECKBOX = QuestionFormat.where(title: "Check box").first.id - DROPDOWN = QuestionFormat.where(title: "Dropdown").first.id - MULTI = QuestionFormat.where(title: "Multi select box").first.id + after_action :verify_authorized def index authorize Plan @@ -21,88 +12,90 @@ # GET /plans/new + # ------------------------------------------------------------------------------------ def new - if user_signed_in? then - @plan = Plan.new - authorize @plan - @funders = Org.funders.all + @plan = Plan.new + authorize @plan - respond_to do |format| - format.html # new.html.erb - end - else - respond_to do |format| - format.html { redirect_to edit_user_registration_path } - end - end + # Get all of the available funders and non-funder orgs + @funders = Org.funders.joins(:templates).where(templates: {published: true}).uniq.sort{|x,y| x.name <=> y.name } + @orgs = (Org.institutions + Org.managing_orgs).flatten.uniq.sort{|x,y| x.name <=> y.name } + + # Get the current user's org + @default_org = current_user.org if @orgs.include?(current_user.org) + + respond_to :html end - + # POST /plans + # ------------------------------------------------------------------- def create - if user_signed_in? then - @plan = Plan.new - authorize @plan - @plan.save + @plan = Plan.new + authorize @plan - funder_id = params[:plan][:funder_id] - if !funder_id.blank? - # get all funder @templates - funder = Org.find(params[:plan][:funder_id]) - @templates = get_most_recent( funder.templates.where("published = ?", true).all ) + @plan.principal_investigator = current_user.surname.blank? ? nil : "#{current_user.firstname} #{current_user.surname}" + @plan.data_contact = current_user.email + @plan.funder_name = plan_params[:funder_name] - orgtemplates = current_user.org.templates.all - replacements = [] + # If a template hasn't been identified look for the available templates + if plan_params[:template_id].blank? + template_options(plan_params[:org_id], plan_params[:funder_id]) - # replace any that are customised by the org - orgtemplates.each do |orgt| - base_template = orgt.customization_of - @templates.delete(base_template) - replacements << orgt + # Return the 'Select a template' section + respond_to do |format| + format.js {} + end + + # Otherwise create the plan + else + @plan.template = Template.find(plan_params[:template_id]) + + if plan_params[:title].blank? + @plan.title = current_user.firstname.blank? ? _('My Plan') + '(' + @plan.template.title + ')' : + current_user.firstname + "'s" + _(" Plan") + else + @plan.title = plan_params[:title] + end + + if @plan.save + @plan.assign_creator(current_user) + + # pre-select org's guidance + ggs = GuidanceGroup.where(org_id: plan_params[:org_id], + optional_subset: false, + published: true) + if !ggs.blank? then @plan.guidance_groups << ggs end + + default = Template.find_by(is_default: true) + + msg = "#{_('Plan was successfully created.')} " + + if !default.nil? && default == @plan.template + # We used the generic/default template + msg += _('This plan is based on the default template.') + + elsif !@plan.template.customization_of.nil? + # We used a customized version of the the funder template + msg += "#{_('This plan is based on the')} #{plan_params[:funder_name]} #{_('template with customisations by the')} #{plan_params[:org_name]}" + + else + # We used the specified org's or funder's template + msg += "#{_('This plan is based on the')} #{@plan.template.org.name} template." end - @templates + replacements + + flash[:notice] = msg + + respond_to do |format| + format.js { render js: "window.location='#{plan_url(@plan)}?editing=true'" } + end else - # get all org @templates which are not customisations - @templates = current_user.org.templates.where(customization_of: nil) - - # if none of these get the basic dcc template - if @templates.blank? - @templates = Template.find_by_is_default(true) + # Something went wrong so report the issue to the user + flash[:notice] = failed_create_error(@plan, 'Plan') + respond_to do |format| + format.js {} end end - - # if we have more than one template then back to the user - # using the 'create' template - # to choose otherwise just create the plan - # and go to the plan/show template - if @templates.length > 1 - return - end - - @plan.template = @templates[0] - - @plan.principal_investigator = current_user.name - - @plan.title = I18n.t('helpers.project.my_project_name')+' ('+@plan.template.title+')' - - @plan.assign_creator(current_user.id) - - @plan.set_possible_guidance_groups - - @selected_guidance_groups = @plan.guidance_groups.map{ |pgg| [pgg.name, pgg.id, :checked => false] } - @selected_guidance_groups.sort! - - respond_to do |format| - if @plan.save - #format.html { redirect_to({:action => "show", :id => @plan.slug, :show_form => "yes"}, {:notice => I18n.t('helpers.project.success')}) } - format.html { redirect_to({:action => "show", :id => @plan.id, :editing => true }, {:notice => I18n.t('helpers.project.success')}) } - else - @error = "Something went wrong" - format.html { render action: "new" } - end - end - else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) end end @@ -110,30 +103,31 @@ # GET /plans/show def show - @plan = Plan.find(params[:id]) + @plan = Plan.eager_load(params[:id]) authorize @plan + @editing = (!params[:editing].nil? && @plan.administerable_by?(current_user.id)) - @plan_data = @plan.to_hash + # Get all Guidance Groups applicable for the plan and group them by org + @all_guidance_groups = @plan.get_guidance_group_options + @all_ggs_grouped_by_org = @all_guidance_groups.sort.group_by(&:org) - @editing = params[:editing] && @plan.administerable_by?(current_user.id) - @selected_guidance_groups = [] - all_guidance_groups = @plan_data["plan_guidance_groups"] - @selected_guidance_groups = all_guidance_groups.map{ |pgg| [ pgg["guidance_group"]["name"], pgg["guidance_group"]["id"], :checked => pgg["selected"] ] } - @selected_guidance_groups.sort! - - if user_signed_in? && @plan.readable_by?(current_user.id) then - respond_to do |format| - format.html # show.html.erb - end - elsif user_signed_in? then - respond_to do |format| - format.html { redirect_to projects_url, notice: I18n.t('helpers.settings.plans.errors.no_access_account') } - end - else - respond_to do |format| - format.html { redirect_to edit_user_registration_path } + # Important ones come first on the page - we grab the user's org's GGs and "Organisation" org type GGs + @important_ggs = [] + @important_ggs << [current_user.org, @all_ggs_grouped_by_org.delete(current_user.org)] + @all_ggs_grouped_by_org.each do |org, ggs| + if org.organisation? + @important_ggs << [org,ggs] + @all_ggs_grouped_by_org.delete(org) end end + + # Sort the rest by org name for the accordion + @all_ggs_grouped_by_org = @all_ggs_grouped_by_org.sort_by {|org,gg| org.name} + + @selected_guidance_groups = @plan.guidance_groups.pluck(:id) + @based_on = (@plan.template.customization_of.nil? ? @plan.template : Template.where(dmptemplate: @plan.template.customization_of).first) + + respond_to :html end @@ -148,49 +142,29 @@ # # GET /plans/1/edit def edit - @textarea = TEXTAREA - @textfield = TEXTFIELD - @radio = RADIO - @checkbox = CHECKBOX - @dropdown = DROPDOWN - @multi = MULTI - @plan = Plan.find(params[:id]) - - @phase = nil - if params[:phase] - @phase = Phase.find(params[:phase]) - end - authorize @plan - @readonly = @plan.editable_by?(current_user.id) - if !user_signed_in? then - respond_to do |format| - format.html { redirect_to edit_user_registration_path } - end - elsif !@plan.readable_by?(current_user.id) then - respond_to do |format| - format.html { redirect_to projects_url, notice: I18n.t('helpers.settings.plans.errors.no_access_account') } - end - end + # If there was no phase specified use the template's 1st phase + @phase = (params[:phase].nil? ? @plan.template.phases.first : Phase.find(params[:phase])) + @readonly = !@plan.editable_by?(current_user.id) + respond_to :html end + # PUT /plans/1 # PUT /plans/1.json def update @plan = Plan.find(params[:id]) authorize @plan - if user_signed_in? && @plan.editable_by?(current_user.id) then - respond_to do |format| - if @plan.update_attributes(params[:plan]) - format.html { redirect_to @plan, :editing => false, notice: I18n.t('helpers.project.success_update') } - format.json { head :no_content } - else - format.html { render action: "edit" } - end + + respond_to do |format| + if @plan.update_attributes(params[:plan]) + format.html { redirect_to @plan, :editing => false, notice: _('Plan was successfully updated.') } + format.json { head :no_content } + else + flash[:notice] = failed_update_error(@plan, _('plan')) + format.html { render action: "edit" } end - else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) end end @@ -199,49 +173,46 @@ def update_guidance_choices @plan = Plan.find(params[:id]) authorize @plan - if user_signed_in? && @plan.editable_by?(current_user.id) then - guidance_ids = params[:plan][:plan_guidance_group_ids] - @plan.plan_guidance_groups.each do |pgg| - pgg.selected = guidance_ids.include?(pgg.guidance_group_id.to_s) - pgg.save! + guidance_group_ids = params[:guidance_group_ids].blank? ? [] : params[:guidance_group_ids].map(&:to_i) + all_guidance_groups = @plan.get_guidance_group_options + plan_groups = @plan.guidance_groups + guidance_groups = GuidanceGroup.where( id: guidance_group_ids) + all_guidance_groups.each do |group| + # case where plan group exists but not in selection + if plan_groups.include?(group) && ! guidance_groups.include?(group) + # remove from plan groups + @plan.guidance_groups.delete(group) end - @plan.save! - - respond_to do |format| - format.json { head :no_content } + # case where plan group dosent exist and in selection + if !plan_groups.include?(group) && guidance_groups.include?(group) + # add to plan groups + @plan.guidance_groups << group end - else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) end + @plan.save + flash[:notice] = _('Guidance choices saved.') + redirect_to action: "show" end def share @plan = Plan.find(params[:id]) authorize @plan - @plan_data = @plan.to_hash - if !user_signed_in? then - respond_to do |format| - format.html { redirect_to edit_user_registration_path } - end - elsif !@plan.editable_by?(current_user.id) then - respond_to do |format| - format.html { redirect_to plans_url, notice: I18n.t('helpers.settings.plans.errors.no_access_account') } - end - end + #@plan_data = @plan.to_hash end def destroy @plan = Plan.find(params[:id]) authorize @plan - if user_signed_in? && @plan.editable_by?(current_user.id) then - @plan.destroy - + if @plan.destroy respond_to do |format| - format.html { redirect_to plans_url } + format.html { redirect_to plans_url, notice: _('Plan was successfully deleted.') } end else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) + respond_to do |format| + flash[:notice] = failed_create_error(@plan, _('plan')) + format.html { render action: "edit" } + end end end @@ -250,164 +221,76 @@ def status @plan = Plan.find(params[:id]) authorize @plan - if user_signed_in? && @plan.readable_by(current_user.id) then - respond_to do |format| - format.json { render json: @plan.status } - end - else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) - end - end - - def section_answers - @plan = Plan.find(params[:id]) - authorize @plan - if user_signed_in? && @plan.readable_by(current_user.id) then - respond_to do |format| - format.json { render json: @plan.section_answers(params[:section_id]) } - end - else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) - end - end - - def locked - @plan = Plan.find(params[:id]) - authorize @plan - if !@plan.nil? && user_signed_in? && @plan.readable_by(current_user.id) then - respond_to do |format| - format.json { render json: @plan.locked(params[:section_id],current_user.id) } - end - else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) - end - end - - def delete_recent_locks - @plan = Plan.find(params[:id]) - authorize @plan - if user_signed_in? && @plan.editable_by(current_user.id) then - respond_to do |format| - if @plan.delete_recent_locks(current_user.id) - format.html { render action: "edit" } - else - format.html { render action: "edit" } - end - end - else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) - end - end - - def unlock_all_sections - @plan = Plan.find(params[:id]) - authorize @plan - if user_signed_in? && @plan.editable_by(current_user.id) then - respond_to do |format| - if @plan.unlock_all_sections(current_user.id) - format.html { render action: "edit" } - else - format.html { render action: "edit" } - end - end - else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) - end - end - - def lock_section - @plan = Plan.find(params[:id]) - authorize @plan - if user_signed_in? && @plan.editable_by(current_user.id) then - respond_to do |format| - if @plan.lock_section(params[:section_id], current_user.id) - format.html { render action: "edit" } - else - format.html { render action: "edit" } - format.json { render json: @plan.errors, status: :unprocessable_entity } - end - end - else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) - end - end - - def unlock_section - @plan = Plan.find(params[:id]) - authorize @plan - if user_signed_in? && @plan.editable_by(current_user.id) then - respond_to do |format| - if @plan.unlock_section(params[:section_id], current_user.id) - format.html { render action: "edit" } - - else - format.html { render action: "edit" } - end - end - else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) + respond_to do |format| + format.json { render json: @plan.status } end end def answer @plan = Plan.find(params[:id]) authorize @plan - if user_signed_in? && @plan.readable_by(current_user.id) then + if !params[:q_id].nil? respond_to do |format| format.json { render json: @plan.answer(params[:q_id], false).to_json(:include => :options) } end else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) + respond_to do |format| + format.json { render json: {} } + end end end + def show_export + @plan = Plan.find(params[:id]) + authorize @plan + render 'show_export' + end + + + def export @plan = Plan.find(params[:id]) authorize @plan - if user_signed_in? && @plan.readable_by?(current_user.id) then - @exported_plan = ExportedPlan.new.tap do |ep| - ep.plan = @plan - ep.user = current_user - #ep.format = request.format.try(:symbol) - ep.format = request.format.to_sym - plan_settings = @plan.settings(:export) + # If no format is specified, default to PDF + params[:format] = 'pdf' if params[:format].nil? - Settings::Template::DEFAULT_SETTINGS.each do |key, value| - ep.settings(:export).send("#{key}=", plan_settings.send(key)) - end + @exported_plan = ExportedPlan.new.tap do |ep| + ep.plan = @plan + ep.phase_id = params[:phase_id] + ep.user = current_user + ep.format = params[:format].to_sym + plan_settings = @plan.settings(:export) + + Settings::Template::DEFAULT_SETTINGS.each do |key, value| + ep.settings(:export).send("#{key}=", plan_settings.send(key)) end + end - @exported_plan.save! # FIXME: handle invalid request types without erroring? - file_name = @exported_plan.project_name + begin + @exported_plan.save! + file_name = @exported_plan.settings(:export)[:value]['title'].gsub(/ /, "_") respond_to do |format| format.html - format.xml - format.json - format.csv { send_data @exported_plan.as_csv, filename: "#{file_name}.csv" } - format.text { send_data @exported_plan.as_txt, filename: "#{file_name}.txt" } - format.docx { headers["Content-Disposition"] = "attachment; filename=\"#{file_name}.docx\""} + format.csv { send_data @exported_plan.as_csv, filename: "#{file_name}.csv" } + format.text { send_data @exported_plan.as_txt, filename: "#{file_name}.txt" } + format.docx { render docx: 'export', filename: "#{file_name}.docx" } format.pdf do @formatting = @plan.settings(:export).formatting render pdf: file_name, margin: @formatting[:margin], footer: { - center: t('helpers.plan.export.pdf.generated_by'), + center: _('This document was generated by %{application_name}') % {application_name: Rails.configuration.branding[:application][:name]}, font_size: 8, spacing: (@formatting[:margin][:bottom] / 2) - 4, right: '[page] of [topage]' } end end - elsif !user_signed_in? then - respond_to do |format| - format.html { redirect_to edit_user_registration_path } - end - elsif !@plan.editable_by(current_user.id) then - respond_to do |format| - format.html { redirect_to projects_url, notice: I18n.t('helpers.settings.plans.errors.no_access_account') } - end + rescue ActiveRecord::RecordInvalid => e + redirect_to show_export_plan_path(@plan), notice: _('%{format} is not a valid exporting format. Available formats to export are %{available_formats}.') % + {format: params[:format], available_formats: ExportedPlan::VALID_FORMATS.to_s} end end @@ -415,13 +298,19 @@ private + def plan_params + params.require(:plan).permit(:org_id, :org_name, :funder_id, :funder_name, :template_id, :title) + end + # different versions of the same template have the same dmptemplate_id + # but different version numbers so for each set of templates with the + # same dmptemplate_id choose the highest version number. def get_most_recent( templates ) groups = Hash.new templates.each do |t| k = t.dmptemplate_id if !groups.has_key?(k) - groups[k] =t + groups[k] = t else other = groups[k] if other.version < t.version @@ -443,7 +332,7 @@ ghash = {} plan["guidance_groups"].map{|g| ghash[g["id"]] = g} - plan["plan_guidance_groups"].each do |pgg| + plan["plans_guidance_groups"].each do |pgg| pgg["guidance_group"] = ghash[ pgg["guidance_group_id"] ] end @@ -476,4 +365,49 @@ plan.delete(src_plan_key) end + # Collect all of the templates available for the org+funder combination + # -------------------------------------------------------------------------- + def template_options(org_id, funder_id) + @templates = [] + + if !org_id.blank? || !funder_id.blank? + if funder_id.blank? + # Load the org's template(s) + unless org_id.nil? + org = Org.find(org_id) + @templates = Template.valid.where(published: true, org: org, customization_of: nil).to_a + @msg = _("We found multiple DMP templates corresponding to the research organisation.") if @templates.count > 1 + end + + else + funder = Org.find(funder_id) + # Load the funder's template(s) + @templates = Template.valid.where(published: true, org: funder).to_a + + unless org_id.blank? + org = Org.find(org_id) + + # Swap out any organisational cusotmizations of a funder template + @templates.each do |tmplt| + customization = Template.valid.find_by(published: true, org: org, customization_of: tmplt.dmptemplate_id) + unless customization.nil? + @templates.delete(tmplt) + @templates << customization + end + end + end + + msg = _("We found multiple DMP templates corresponding to the funder.") if @templates.count > 1 + end + end + + # If no templates were available use the generic templates + if @templates.empty? + @msg = _("Using the generic Data Management Plan") + @templates << Template.where(is_default: true, published: true).first + end + + @templates = @templates.sort{|x,y| x.title <=> y.title } if @templates.count > 1 + end + end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb deleted file mode 100644 index 5b98dd2..0000000 --- a/app/controllers/projects_controller.rb +++ /dev/null @@ -1,401 +0,0 @@ -class ProjectsController < ApplicationController - before_filter :get_plan_list_columns, only: %i( index ) - after_action :verify_authorized - - # GET /projects - # GET /projects.json - def index - authorize Project - ## TODO: Is this A magic String? the "Show_shib_link?" as we define it and users dont see cookies - if user_signed_in? then - if (current_user.shibboleth_id.nil? || current_user.shibboleth_id.length == 0) && !cookies[:show_shib_link].nil? && cookies[:show_shib_link] == "show_shib_link" then - flash.notice = "Would you like to #{view_context.link_to I18n.t('helpers.shibboleth_to_link_text'), user_omniauth_shibboleth_path}".html_safe - end - - @projects = current_user.projects.filter(params[:filter]) - @has_projects = current_user.projects.any? # unfiltered count - - respond_to do |format| - format.html # index.html.erb - end - else - respond_to do |format| - format.html { redirect_to edit_user_registration_path } - end - end - end - - # GET /projects/1 - # GET /projects/1.json - def show - @project = Project.find(params[:id]) - authorize @project - @show_form = false - if params[:show_form] == "yes" then - @show_form = true - end - if user_signed_in? && @project.readable_by(current_user.id) then - respond_to do |format| - format.html # show.html.erb - end - elsif user_signed_in? then - respond_to do |format| - format.html { redirect_to projects_url, notice: I18n.t('helpers.settings.plans.errors.no_access_account') } - end - else - respond_to do |format| - format.html { redirect_to edit_user_registration_path } - end - end - end - - def new - if user_signed_in? then - @plan = Plan.new - authorize @plan - @funders = Org.funder.all - - respond_to do |format| - format.html # new.html.erb - end - else - respond_to do |format| - format.html { redirect_to edit_user_registration_path } - end - end - end - - - # GET /projects/1/edit - # Should this be removed? - def edit - @project = Project.find(params[:id]) - authorize @project - if !user_signed_in? then - respond_to do |format| - format.html { redirect_to edit_user_registration_path } - end - elsif !@project.editable_by(current_user.id) then - respond_to do |format| - format.html { redirect_to projects_url, notice: I18n.t('helpers.settings.plans.errors.no_access_account') } - end - end - end - - def share - @project = Project.find(params[:id]) - authorize @project - if !user_signed_in? then - respond_to do |format| - format.html { redirect_to edit_user_registration_path } - end - elsif !@project.editable_by(current_user.id) then - respond_to do |format| - format.html { redirect_to projects_url, notice: I18n.t('helpers.settings.plans.errors.no_access_account') } - end - end - end - - def export - @project = Project.find(params[:id]) - authorize @project - if !user_signed_in? then - respond_to do |format| - format.html { redirect_to edit_user_registration_path } - end - else - respond_to do |format| - format.html { render action: "export" } - - end - end - end - - # POST /projects - def create - puts params - return - if user_signed_in? then - @plan = Plan.new(params[:plan]) - authorize @project - if @project.dmptemplate.nil? && params[:project][:funder_id] != "" then # this shouldn't be necessary - see setter for funder_id in project.rb - funder = Org.find(params[:project][:funder_id]) - if funder.dmptemplates.count == 1 then - @project.dmptemplate = funder.published_templates.first - end - elsif @project.dmptemplate.nil? || params[:default_tag] == 'true' then - if @project.organisation.nil? || params[:default_tag] == 'true' || @project.organisation.published_templates.first.nil? then - @project.dmptemplate = Dmptemplate.find_by_is_default(true) - else - @project.dmptemplate = @project.organisation.published_templates.first - end - end - @project.principal_investigator = current_user.name(false) - - @project.title = I18n.t('helpers.project.my_project_name')+' ('+@project.dmptemplate.title+')' - @project.assign_creator(current_user.id) - respond_to do |format| - if @project.save - format.html { redirect_to({:action => "show", :id => @project.slug, :show_form => "yes"}, {:notice => I18n.t('helpers.project.success')}) } - else - format.html { render action: "new" } - end - end - else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) - end - end - - # PUT /projects/1 - # PUT /projects/1.json - def update - @project = Project.find(params[:id]) - authorize @project - if user_signed_in? && @project.editable_by(current_user.id) then - if @project.update_attributes(params[:project]) - respond_to do |format| - format.html { redirect_to({:action => "show", :id => @project.slug, notice: I18n.t('helpers.project.success_update') }) } - end - else - respond_to do |format| - format.html { render action: "edit" } - end - end - else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) - end - end - - # DELETE /projects/1 - # DELETE /projects/1.json - def destroy - @project = Project.find(params[:id]) - authorize @project - if user_signed_in? && @project.editable_by(current_user.id) then - @project.destroy - - respond_to do |format| - format.html { redirect_to projects_url } - end - else - render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) - end - end - - # returns to AJAX call from frontend - # difficult to secure as it passes through params, and dosent curate data based - # on what the user can "view" or is public - - # GET /projects/possible_templates.json - def possible_templates - if !params[:funder].nil? && params[:funder] != "" && params[:funder] != "undefined" then - funder = Org.find(params[:funder]) - else - funder = nil - end - if !params[:institution].nil? && params[:institution] != "" && params[:institution] != "undefined" then - institution = Org.find(params[:institution]) - else - institution = nil - end - templates = {} - unless funder.nil? then - funder.published_templates.each do |t| - templates[t.id] = t.title - end - end - if templates.count == 0 && !institution.nil? then - institution.published_templates.each do |t| - templates[t.id] = t.title - end - institution.children.each do |o| - o.published_templates.each do |t| - templates[t.id] = t.title - end - end - end - respond_to do |format| - format.json { render json: templates.to_json } - end - end - - # returns to AJAX call from frontend - # difficult to secure as it passes through params, and dosent curate data based - # on what the user can "view" or is public - # ----------------------------------------------------------- - def possible_guidance - authorize @project - - if !params[:template].nil? && params[:template] != "" && params[:template] != "undefined" then - template = Dmptemplate.find(params[:template]) - else - template = nil - end - if !params[:institution].nil? && params[:institution] != "" && params[:institution] != "undefined" then - institution = Org.find(params[:institution]) - else - institution = nil - end - excluded_orgs = Org.funders + Org.institutions - guidance_groups = {} - ggs = GuidanceGroup.guidance_groups_excluding(excluded_orgs) - - ggs.each do |gg| - guidance_groups[gg.id] = gg.name - end - - #subset guidance that belong to the institution - unless institution.nil? then - authorize Project - optional_gg = GuidanceGroup.where("optional_subset = ? AND organisation_id = ?", true, institution.id) - optional_gg.each do|optional| - guidance_groups[optional.id] = optional.name - end - - institution.children.each do |o| - o.guidance_groups.each do |gg| - include = false - gg.guidances.each do |g| - if g.dmptemplate.nil? || g.dmptemplate_id == template.id then - include = true - break - end - end - if include then - guidance_groups[gg.id] = gg.name - end - end - end - end - - #If template belongs to a funder and that funder has subset guidance display then. - if !template.nil? && template.organisation.organisation_type.name == constant("organisation_types.funder") then - optional_gg = GuidanceGroup.where("optional_subset = ? AND organisation_id = ?", true, template.organisation_id) - optional_gg.each do|optional| - guidance_groups[optional.id] = optional.name - end - end - - - respond_to do |format| - format.json { render json: guidance_groups.to_json } - end - end - - private - def project_params - params.require(:project).permit(:title, :grant_number, :identifier, :description, - :principal_investigator, :principal_investigator_identifier, - :data_contact, :funder_name, :visibility, - :dmptemplate_id, :organisation_id, :funder_id, :institution_id, - :guidance_group_ids, :project_group_ids) - end - - def orgs_of_type(org_type_name, published_templates = false) - org_type = OrganisationType.find_by_name(org_type_name) - all_such_orgs = org_type.organisations - if published_templates then - with_published = Array.new - all_such_orgs.each do |o| - if o.published_templates.count > 0 then - with_published << o - end - end - return with_published.sort_by {|o| [o.sort_name, o.name] } - else - return all_such_orgs.sort_by {|o| [o.sort_name, o.name] } - end - end - - # ----------------------------------------------------------- - def get_available_templates - Template.find_by(published: true) - end - - # ----------------------------------------------------------- - # Some guidance is always available to the user regardless of - # the template or institution. - # - # TODO: Reevaluate this. We should probably only do this for - # guidance groups who have guidance attached to themes - # ----------------------------------------------------------- - def get_always_available_guidance - # Exclude Funders, Institutions, or children of Institutions - excluded_orgs = orgs_of_type(constant("organisation_types.funder")) + - orgs_of_type(constant("organisation_types.institution")) + - Org.orgs_with_parent_of_type(constant("organisation_types.institution")) - - GuidanceGroup.guidance_groups_excluding(excluded_orgs) - end - - # ----------------------------------------------------------- - # This is a simplified version of the old possible_guidance method - # above. It sends all possible guidance to the client instead of - # forcing the client to make ajax calls to change the available - # guidance list (that is now handled via JS clientside) - # - # TODO: Reevaluate whether or not this logic makes sense once the - # DB has been cleaned up - # ----------------------------------------------------------- - def get_available_guidance - guidance_groups = [] - - #subset guidance that belong to an institution - optional_gg = GuidanceGroup.where("optional_subset = ? AND organisation_id IS NOT NULL", true) - optional_gg.each do|optional| - guidance_groups << optional.id - - optional.organisation.children.each do |o| - o.guidance_groups.each do |gg| - guidance_groups << gg.id - end - end - end - - # If template belongs to a funder and is an optional_subset - optional_gg = GuidanceGroup.where("optional_subset = ? AND organisation_id IN (?)", true, orgs_of_type(constant("organisation_types.funder"))) - optional_gg.each do|optional| - guidance_groups << optional.id - end - - GuidanceGroup.where(id: guidance_groups) - end - - # ----------------------------------------------------------- - def generate_export - @exported_plan = ExportedPlan.new.tap do |ep| - ep.plan = @plan - ep.user = current_user ||= nil - #ep.format = request.format.try(:symbol) - ep.format = request.format.to_sym - plan_settings = @plan.settings(:export) - - Settings::Dmptemplate::DEFAULT_SETTINGS.each do |key, value| - ep.settings(:export).send("#{key}=", plan_settings.send(key)) - end - end - - @exported_plan.save! # FIXME: handle invalid request types without erroring? - file_name = @exported_plan.project_name - - respond_to do |format| - format.html - format.xml - format.json - format.csv { send_data @exported_plan.as_csv, filename: "#{file_name}.csv" } - format.text { send_data @exported_plan.as_txt, filename: "#{file_name}.txt" } - format.docx { headers["Content-Disposition"] = "attachment; filename=\"#{file_name}.docx\""} - format.pdf do - @formatting = @plan.settings(:export).formatting - render pdf: file_name, - margin: @formatting[:margin], - footer: { - center: t('helpers.plan.export.pdf.generated_by'), - font_size: 8, - spacing: (@formatting[:margin][:bottom] / 2) - 4, - right: '[page] of [topage]' - } - end - end - end -end diff --git a/app/controllers/questions_controller.rb b/app/controllers/questions_controller.rb new file mode 100644 index 0000000..f3250bb --- /dev/null +++ b/app/controllers/questions_controller.rb @@ -0,0 +1,132 @@ +class QuestionsController < ApplicationController + respond_to :html + after_action :verify_authorized + + #create a question + def admin_create + begin + @question = Question.new(question_params) + authorize @question + @question.modifiable = true + if @question.question_format.textfield? + @question.default_value = params["question-default-value-textfield"] + elsif @question.question_format.textarea? + @question.default_value = params["question-default-value-textarea"] + end + if @question.save + @question.section.phase.template.dirty = true + @question.section.phase.template.save! + if params[:example_answer].present? + example_answer = Annotation.new({question_id: @question.id, org_id: current_user.org_id, text: params[:example_answer], type: Annotation.types[:example_answer]}) + example_answer.save + end + if params[:guidance].present? + guidance = Annotation.new({question_id: @question.id, org_id: current_user.org_id, text: params[:guidance], type: Annotation.types[:guidance]}) + guidance.save + end + redirect_to admin_show_phase_path(id: @question.section.phase_id, section_id: @question.section_id, question_id: @question.id, edit: 'true'), notice: _('Information was successfully created.') + else + @edit = (@question.section.phase.template.org == current_user.org) + @open = true + @phase = @question.section.phase + @section = @question.section + @sections = @phase.sections + @section_id = @question.section.id + @question_id = @question.id + + flash[:notice] = failed_create_error(@question, _('question')) + if @phase.template.customization_of.present? + @original_org = Template.where(dmptemplate_id: @phase.template.customization_of).first.org + else + @original_org = @phase.template.org + end + render template: 'phases/admin_show' + end + rescue ActionController::ParameterMissing => e + flash[:notice] = e.message + end + end + + #update a question of a template + def admin_update + @question = Question.find(params[:id]) + authorize @question + guidance = @question.get_guidance_annotation(current_user.org_id) + if params["question-guidance-#{params[:id]}"].present? + if guidance.blank? + guidance = @question.annotations.build + guidance.type = :guidance + guidance.org_id = current_user.org_id + end + guidance.text = params["question-guidance-#{params[:id]}"] + guidance.save + end + example_answer = @question.get_example_answer(current_user.org_id) + if params["question"]["annotations_attributes"].present? && params["question"]["annotations_attributes"]["0"]["id"].present? + if example_answer.blank? + example_answer = @question.annotations.build + example_answer.type = :example_answer + example_answer.org_id = current_user.org_id + end + example_answer.text = params["question"]["annotations_attributes"]["0"]["text"] + example_answer.save + end + if @question.question_format.textfield? + @question.default_value = params["question-default-value-textfield"] + elsif @question.question_format.textarea? + @question.default_value = params["question-default-value-textarea"] + end + @section = @question.section + @phase = @section.phase + template = @phase.template + if @question.update_attributes(params[:question]) + @phase.template.dirty = true + @phase.template.save! + + redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id, question_id: @question.id, edit: 'true'), notice: _('Information was successfully updated.') + else + @edit = (@phase.template.org == current_user.org) + @open = true + @sections = @phase.sections + @section_id = @section.id + @question_id = @question.id + + flash[:notice] = failed_update_error(@question, _('question')) + if @phase.template.customization_of.present? + @original_org = Template.where(dmptemplate_id: @phase.template.customization_of).first.org + else + @original_org = @phase.template.org + end + render template: 'phases/admin_show' + end + end + + #delete question + def admin_destroy + @question = Question.find(params[:question_id]) + authorize @question + @section = @question.section + @phase = @section.phase + if @question.destroy + @phase.template.dirty = true + @phase.template.save! + + redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id, edit: 'true'), notice: _('Information was successfully deleted.') + else + redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id, edit: 'true'), notice: failed_destroy_error(@question, 'question') + end + end + + private + # Filters the valid attributes for a question according to each type. + # Note, that params[:question] and params[:question][:question_format_id] are required and their absence raises ActionController::ParameterMissing + def question_params + permitted = params.require(:question).except(:created_at, :updated_at).tap do |question_params| + question_params.require(:question_format_id) + q_format = QuestionFormat.find(question_params[:question_format_id]) + if !q_format.option_based? + question_params.delete(':question_options_attributes') + end + end + end +end \ No newline at end of file diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index a82b679..a628929 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -6,6 +6,7 @@ @orgs = Org.where(parent_id: nil).order("name") @other_organisations = Org.where(parent_id: nil, is_other: true).pluck(:id) @identifier_schemes = IdentifierScheme.where(active: true).order(:name) + @default_org = current_user.org end # GET /resource @@ -34,48 +35,48 @@ # POST /resource def create - logger.debug "#{sign_up_params}" - if sign_up_params[:accept_terms] != "1" then - redirect_to after_sign_up_error_path_for(resource), alert: I18n.t('helpers.you_must_accept') - else - existing_user = User.find_by_email(sign_up_params[:email]) - if !existing_user.nil? then - if (existing_user.password == "" || existing_user.password.nil?) && existing_user.confirmed_at.nil? then - @user = existing_user - do_update(false, true) - else - redirect_to after_sign_up_error_path_for(resource), alert: I18n.t('helpers.email_already_registered') - end - else + #logger.debug "#{sign_up_params}" + if sign_up_params[:accept_terms] != "1" then + redirect_to after_sign_up_error_path_for(resource), alert: _('You must accept the terms and conditions to register.') + else + existing_user = User.find_by_email(sign_up_params[:email]) + if !existing_user.nil? # If email exists + if (existing_user.password == "" || existing_user.password.nil?) && existing_user.confirmed_at.nil? # If user has not accepted invitation yet + existing_user.destroy # Only solution for now + super + else + redirect_to after_sign_up_error_path_for(resource), alert: _('That email address is already registered.') + end + else build_resource(sign_up_params) - if resource.save - if resource.active_for_authentication? - set_flash_message :notice, :signed_up if is_navigational_format? - sign_up(resource_name, resource) - respond_with resource, location: after_sign_up_path_for(resource) - else - set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format? - #expire_session_data_after_sign_in! <-- DEPRECATED BY DEVISE - respond_with resource, location: after_inactive_sign_up_path_for(resource) - end - else - clean_up_passwords resource - redirect_to after_sign_up_error_path_for(resource), alert: I18n.t('helpers.error_registration_check') - end - end + if resource.save + if resource.active_for_authentication? + set_flash_message :notice, :signed_up if is_navigational_format? + sign_up(resource_name, resource) + UserMailer.welcome_notification(current_user).deliver + respond_with resource, location: after_sign_up_path_for(resource) + else + set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format? + #expire_session_data_after_sign_in! <-- DEPRECATED BY DEVISE + respond_with resource, location: after_inactive_sign_up_path_for(resource) + end + else + clean_up_passwords resource + redirect_to after_sign_up_error_path_for(resource), alert: _('Error processing registration. Please check that you have entered a valid email address and that your chosen password is at least 8 characters long.') + end + end end end def update if user_signed_in? then - @user = User.find(current_user.id) @orgs = Org.where(parent_id: nil).order("name") + @default_org = current_user.org @other_organisations = Org.where(parent_id: nil, is_other: true).pluck(:id) - @languages = Language.order("name") @identifier_schemes = IdentifierScheme.where(active: true).order(:name) - - do_update + @languages = Language.sorted_by_abbreviation + do_update(require_password=needs_password?(current_user, params)) else render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) end @@ -91,53 +92,93 @@ end def do_update(require_password = true, confirm = false) - if require_password then - successfully_updated = if needs_password?(@user, params) - @user.update_with_password(params[:user]) - else - # remove the virtual current_password attribute update_without_password - # doesn't know how to ignore it - params[:user].delete(:current_password) - @user.update_without_password(params[:user]) + mandatory_params = true + message = _('Save Unsuccessful.') + ' ' # added to by below, overwritten otherwise + # ensure that the required fields are present + if params[:user][:email].blank? + message +=_('Please enter an email address.') + ' ' + mandatory_params &&= false + end + if params[:user][:firstname].blank? + message +=_('Please enter a First name.') + ' ' + mandatory_params &&= false + end + if params[:user][:surname].blank? + message +=_('Please enter a Last name.') + ' ' + mandatory_params &&= false + end + if params[:user][:org_id].blank? + message += _('Please select an organisation, or select Other.') + mandatory_params &&= false + end + if mandatory_params # has the user entered all the details + if require_password # user is changing email or password + if current_user.email != params[:user][:email] # if user is changing email + if params[:user][:current_password].blank? # password needs to be present + message = _('Please enter your password to change email address.') + successfully_updated = false + else + successfully_updated = current_user.update_with_password(password_update) + end + elsif params[:user][:password].present? # if user is changing password + successfully_updated = false # shared across first 3 conditions + if params[:user][:current_password].blank? + message = _('Please enter your current password') + elsif params[:user][:password_confirmation].blank? + message = _('Please enter a password confirmation') + elsif params[:user][:password] != params[:user][:password_confirmation] + message = _('Password and comfirmation must match') + else + successfully_updated = current_user.update_with_password(password_update) + end + else # potentially unreachable... but I dont like to leave off the else + successfully_updated = current_user.update_with_password(password_update) + end + else # password not required + successfully_updated = current_user.update_without_password(update_params) end else - @user.update_attributes(password: params[:user][:password], password_confirmation: params[:user][:password_confirmation]) - successfully_updated = @user.update_without_password(params[:user]) - end - - # If the user selected a new language setting, go ahead and reset the locale - if params[:user][:language_id] - if @user.language_id != params[:user][:language_id] - params[:locale] = Language.find(params[:user][:language_id]).abbreviation - set_locale - end + successfully_updated = false end #unlink shibboleth from user's details if params[:unlink_flag] == 'true' then - @user.update_attributes(shibboleth_id: "") + current_user.update_attributes(shibboleth_id: "") end + #render the correct page if successfully_updated - if confirm then - @user.skip_confirmation! - @user.save! - end - set_flash_message :notice, :updated - # Sign in the user bypassing validation in case his password changed + if confirm + current_user.skip_confirmation! # will error out if confirmable is turned off in user model + current_user.save! + end + session[:locale] = current_user.get_locale unless current_user.get_locale.nil? + set_gettext_locale #Method defined at controllers/application_controller.rb + set_flash_message :notice, _('Details successfully updated.') + sign_in current_user, bypass: true # Sign in the user bypassing validation in case his password changed + redirect_to edit_user_registration_path, notice: _('Details successfully updated.') - sign_in @user, bypass_sign_in: true - - redirect_to({:controller => "registrations", :action => "edit"}, {:notice => I18n.t('helpers.project.details_update_success')}) - else + flash[:notice] = message.blank? ? failed_update_error(current_user, _('profile')) : message render "edit" end end def sign_up_params - params.require(:user).permit(:email, :password, :password_confirmation, :accept_terms, - :organisation_id, :other_organisation) + params.require(:user).permit(:email, :password, :password_confirmation, :firstname, :surname, + :accept_terms, :org_id, :other_organisation) + end + + def update_params + params.require(:user).permit(:firstname, :org_id, :other_organisation, + :language_id, :surname) + end + + def password_update + params.require(:user).permit(:email, :firstname, :current_password, + :org_id, :language_id, :password, + :password_confirmation, :surname, + :other_organisation) end end diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb index d4e4072..3a50d54 100644 --- a/app/controllers/roles_controller.rb +++ b/app/controllers/roles_controller.rb @@ -2,60 +2,91 @@ respond_to :html after_action :verify_authorized - def create - @role = Role.new(params[:role]) + def create + registered = true + @role = Role.new(role_params) authorize @role - @role.access_level = params[:role][:access_level].to_i - if params[:role][:email].present? - message = I18n.t('helpers.project.user_added') - if @role.save - if @role.user.nil? then - if User.find_by_email(params[:role][:email]).nil? then - User.invite!(email: params[:role][:email]) - message = I18n.t('helpers.project.invitation_success') - @role.user = User.find_by_email(params[:role][:email]) - @role.save - else - @role.user = User.find_by_email(params[:role][:email]) - @role.save - UserMailer.sharing_notification(@role).deliver - end - else - UserMailer.sharing_notification(@role).deliver - end - flash[:notice] = message - redirect_to controller: 'plans', action: 'share', id: @role.plan.slug - else - render action: "new" - end - else - flash[:notice] = I18n.t('helpers.project.enter_email') - redirect_to controller: 'plans', action: 'share', id: @role.plan.slug - end - end + access_level = params[:role][:access_level].to_i + set_access_level(access_level) + if params[:user].present? + if @role.plan.owner.present? && @role.plan.owner.email == params[:user] + flash[:notice] = _('Cannot share plan with %{email} since that email matches with the owner of the plan.') % {email: params[:user]} + else + if Role.find_by(plan: @role.plan, user: User.find_by(email: params[:user])) # role already exists + flash[:notice] = _('Plan is already shared with %{email}.') % {email: params[:user]} + else + message = _('Plan shared with %{email}.') % {email: params[:user]} + user = User.find_by(email: params[:user]) + if user.nil? + registered = false + User.invite!(email: params[:user]) + message = _('Invitation to %{email} issued successfully.') % {email: params[:user]} + user = User.find_by(email: params[:user]) + end + @role.user = user + if @role.save + if registered then UserMailer.sharing_notification(@role, current_user).deliver_now end + flash[:notice] = message + else + flash[:notice] = failed_create_error(@role, _('role')) + end + end + end + else + flash[:notice] = _('Please enter an email address') + end + redirect_to controller: 'plans', action: 'share', id: @role.plan.id + end - def update - @role = Role.find(params[:id]) + + def update + @role = Role.find(params[:id]) authorize @role - @role.access_level = params[:role][:access_level].to_i - if @role.update_attributes(params[:role]) - flash[:notice] = I18n.t('helpers.project.sharing_updated') - UserMailer.permissions_change_notification(@role).deliver - redirect_to controller: 'plans', action: 'share', id: @role.plan.slug - else - render action: "edit" - end - end + access_level = params[:role][:access_level].to_i + set_access_level(access_level) + if @role.update_attributes(role_params) + flash[:notice] = _('Sharing details successfully updated.') + UserMailer.permissions_change_notification(@role, current_user).deliver_now + redirect_to controller: 'plans', action: 'share', id: @role.plan.id + else + flash[:notice] = failed_create_error(@role, _('role')) + render action: "edit" + end + end - def destroy - @role = Role.find(params[:id]) + def destroy + @role = Role.find(params[:id]) authorize @role - user = @role.user - plan = @role.plan - @role.destroy + user = @role.user + plan = @role.plan + @role.destroy + flash[:notice] = _('Access removed') + UserMailer.project_access_removed_notification(user, plan, current_user).deliver_now + redirect_to controller: 'plans', action: 'share', id: @role.plan.id + end - flash[:notice] = I18n.t('helpers.project.access_removed') - UserMailer.project_access_removed_notification(user, plan).deliver - redirect_to controller: 'plans', action: 'share', id: @role.plan.slug - end -end \ No newline at end of file + private + + def role_params + params.require(:role).permit(:plan_id) + end + + def set_access_level(access_level) + if access_level >= 1 + @role.commenter = true + else + @role.commenter = false + end + if access_level >= 2 + @role.editor = true + else + @role.editor = false + end + if access_level >= 3 + @role.administrator = true + else + @role.administrator = false + end + end + +end diff --git a/app/controllers/sections_controller.rb b/app/controllers/sections_controller.rb new file mode 100644 index 0000000..b6ef3d1 --- /dev/null +++ b/app/controllers/sections_controller.rb @@ -0,0 +1,91 @@ +class SectionsController < ApplicationController + respond_to :html + after_action :verify_authorized + + #create a section + def admin_create + @section = Section.new(params[:section]) + authorize @section + @section.description = params["section-desc"] + @section.modifiable = true + @phase = @section.phase + if @section.save + @section.phase.template.dirty = true + @section.phase.template.save! + + redirect_to admin_show_phase_path(id: @section.phase_id, + :section_id => @section.id, edit: 'true'), notice: _('Information was successfully created.') + else + @edit = (@phase.template.org == current_user.org) + @open = true + @sections = @phase.sections + @section_id = @section.id + @question_id = nil + flash[:notice] = failed_create_error(@section, _('section')) + if @phase.template.customization_of.present? + @original_org = Template.where(dmptemplate_id: @phase.template.customization_of).first.org + else + @original_org = @phase.template.org + end + render template: 'phases/admin_show' + end + end + + + #update a section of a template + def admin_update + @section = Section.includes(phase: :template).find(params[:id]) + authorize @section + @section.description = params["section-desc-#{params[:id]}"] + @phase = @section.phase + if @section.update_attributes(params[:section]) + @section.phase.template.dirty = true + @section.phase.template.save! + + redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id , edit: 'true'), notice: _('Information was successfully updated.') + else + @edit = (@phase.template.org == current_user.org) + @open = true + @sections = @phase.sections + @section_id = @section.id + @question_id = nil + flash[:notice] = failed_update_error(@section, _('section')) + if @phase.template.customization_of.present? + @original_org = Template.where(dmptemplate_id: @phase.template.customization_of).first.org + else + @original_org = @phase.template.org + end + render template: 'phases/admin_show' + end + end + + + #delete a section and questions + def admin_destroy + @section = Section.includes(phase: :template).find(params[:section_id]) + authorize @section + @phase = @section.phase + + if @section.destroy + @phase.template.dirty = true + @phase.template.save! + + redirect_to admin_show_phase_path(id: @phase.id, edit: 'true' ), notice: _('Information was successfully deleted.') + else + @edit = (@phase.template.org == current_user.org) + @open = true + @sections = @phase.sections + @section_id = @section.id + @question_id = nil + + flash[:notice] = failed_destroy_error(@section, _('section')) + if @phase.template.customization_of.present? + @original_org = Template.where(dmptemplate_id: @phase.template.customization_of).first.org + else + @original_org = @phase.template.org + end + render template: 'phases/admin_show' + end + end + +end \ No newline at end of file diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 89a5f44..a4154d9 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -16,13 +16,23 @@ # --------------------------------------------------------------------- def create existing_user = User.find_by(email: params[:user][:email]) - - if !existing_user.nil? && !params[:shibboleth_data].nil? then - #after authentication verify if session[:shibboleth] exists - existing_user.update_attributes(shibboleth_id: session[:shibboleth_data][:uid]) + if !existing_user.nil? + +# TODO: Not sure why we check for shib data in params and then use session value below. We should move this to the +# new user_identifiers table + if !params[:shibboleth_data].nil? + #after authentication verify if session[:shibboleth] exists + existing_user.update_attributes(shibboleth_id: session[:shibboleth_data][:uid]) + end + session[:locale] = existing_user.get_locale unless existing_user.get_locale.nil? + set_gettext_locale #Method defined at controllers/application_controller.rb end - super end + def destroy + super + session[:locale] = nil + set_gettext_locale #Method defined at controllers/application_controller.rb + end end \ No newline at end of file diff --git a/app/controllers/settings/plans_controller.rb b/app/controllers/settings/plans_controller.rb index 9708521..c406401 100644 --- a/app/controllers/settings/plans_controller.rb +++ b/app/controllers/settings/plans_controller.rb @@ -1,7 +1,6 @@ module Settings class PlansController < SettingsController - before_filter :get_plan_list_columns before_filter :get_settings after_action :verify_authorized @@ -23,6 +22,7 @@ if params[:commit] == 'Reset' s.formatting = nil s.fields = nil + s.title = nil else s.formatting = export_params[:formatting] s.fields = export_params[:fields] @@ -31,13 +31,13 @@ end if settings.save - respond_to do |format| - format.html { redirect_to(export_project_path(@plan.project)) } - end + flash[:notice] = _('Export settings updated successfully.') else - settings.formatting = nil - @export_settings = settings - render(action: :show) + flash[:alert] = _('An error has occurred while saving/resetting your export settings.') + end + respond_to do |format| + format.html { redirect_to(show_export_plan_path(@plan.id)) } + # format.json { render json: settings_json } end end diff --git a/app/controllers/settings/projects_controller.rb b/app/controllers/settings/projects_controller.rb deleted file mode 100644 index 8b0f800..0000000 --- a/app/controllers/settings/projects_controller.rb +++ /dev/null @@ -1,46 +0,0 @@ -module Settings - class ProjectsController < SettingsController - - before_filter :get_plan_list_columns - before_filter :get_settings - - after_action :verify_authorized - - def show - authorize [:settings, Project] - respond_to do |format| - format.html - - format.json{ render json: settings_json } - end - end - - def update - authorize [:settings, Project] - columns = (params[:columns] || {}) - - if @settings.update_attributes(columns: columns) - respond_to do |format| - format.html { redirect_to(projects_path) } - - format.json{ render json: settings_json } - end - else - render(action: :show) # Expect #show to display errors etc - end - end - - private - - def get_settings - @settings = current_user.settings(:plan_list) - # :name column should always be present (displayed as a disabled checkbox) - # so it's not necessary to include it in the list here - @all_columns -= ['name'] - end - - def settings_json - @settings_json ||= { selected_columns: @settings.columns, all_columns: @all_columns }.to_json - end - end -end diff --git a/app/controllers/static_pages_controller.rb b/app/controllers/static_pages_controller.rb index cded887..6f38009 100644 --- a/app/controllers/static_pages_controller.rb +++ b/app/controllers/static_pages_controller.rb @@ -13,61 +13,61 @@ end def roadmap + end - # GET /plans/publicly_available - # ----------------------------------------------------------- def public_plans - @plans = Plan.where(visibility: :publicly_visible).order(title: :asc) + @plans = Plan.publicly_visible end # GET /plans/[:plan_slug]/public_export # ------------------------------------------------------------- def public_export - @plan = Plan.find(params[:id]) + redirect_to public_plans_path, notice: _('Exporting public plan is under development. Apologies for any inconvience.') + #@plan = Plan.find(params[:id]) # Force PDF response - request.format = :pdf + #request.format = :pdf # if the project is designated as public - if @plan.visibility == :publicly_visible - if !@plan.nil? - @exported_plan = ExportedPlan.new.tap do |ep| - ep.plan = @plan - ep.user = current_user ||= nil - #ep.format = request.format.try(:symbol) - ep.format = request.format.to_sym - plan_settings = @plan.settings(:export) + #if @plan.visibility == :publicly_visible + # if !@plan.nil? + # @exported_plan = ExportedPlan.new.tap do |ep| + # ep.plan = @plan + # ep.user = current_user ||= nil + # #ep.format = request.format.try(:symbol) + # ep.format = request.format.to_sym + # plan_settings = @plan.settings(:export) - Settings::Dmptemplate::DEFAULT_SETTINGS.each do |key, value| - ep.settings(:export).send("#{key}=", plan_settings.send(key)) - end - end + # Settings::Dmptemplate::DEFAULT_SETTINGS.each do |key, value| + # ep.settings(:export).send("#{key}=", plan_settings.send(key)) + # end + # end - @exported_plan.save! # FIXME: handle invalid request types without erroring? - file_name = @exported_plan.project_name + # @exported_plan.save! # FIXME: handle invalid request types without erroring? + # file_name = @exported_plan.project_name - respond_to do |format| - format.pdf do - @formatting = @plan.settings(:export).formatting - render pdf: file_name, - margin: @formatting[:margin], - footer: { - center: t('helpers.plan.export.pdf.generated_by'), - font_size: 8, - spacing: (@formatting[:margin][:bottom] / 2) - 4, - right: '[page] of [topage]' - } - end - end + # respond_to do |format| + # format.pdf do + # @formatting = @plan.settings(:export).formatting + # render pdf: file_name, + # margin: @formatting[:margin], + # footer: { + # center: t('helpers.plan.export.pdf.generated_by'), + # font_size: 8, + # spacing: (@formatting[:margin][:bottom] / 2) - 4, + # right: '[page] of [topage]' + # } + # end + # end - else + # else # the project has no plans for some reason - redirect_to public_plans_path, notice: I18n.t('helpers.settings.projects.errors.no_plan') - end - else + # redirect_to public_plans_path, notice: _('The plan is incomplete.') + # end + #else # Otherwise redirect to the home page with an unauthorized message - redirect_to public_plans_path, notice: I18n.t('helpers.settings.plans.errors.no_access_account') - end + # redirect_to public_plans_path, notice: _('This account does not have access to that plan.') + #end end end \ No newline at end of file diff --git a/app/controllers/templates_controller.rb b/app/controllers/templates_controller.rb index 50f3c60..42eb4ee 100644 --- a/app/controllers/templates_controller.rb +++ b/app/controllers/templates_controller.rb @@ -6,416 +6,321 @@ respond_to :html after_action :verify_authorized - # GET /dmptemplates + # GET /org/admin/templates/:id/admin_index + # ----------------------------------------------------- def admin_index authorize Template - # institutional templates - all_versions_own_templates = Template.where(org_id: current_user.org_id, customization_of: nil).order(version: :desc) - current_templates = {} - # take most recent version of each template - all_versions_own_templates.each do |temp| - if current_templates[temp.dmptemplate_id].nil? - current_templates[temp.dmptemplate_id] = temp - end + + funder_templates, org_templates = [], [] + + # Get all of the unique template family ids (dmptemplate_id) for each funder and the current org + funder_ids = Org.funders.includes(:templates).collect{|f| f.templates.where(published: true).valid.collect{|ft| ft.dmptemplate_id } }.flatten.uniq + org_ids = current_user.org.templates.where(customization_of: nil).valid.collect{|t| t.dmptemplate_id }.flatten.uniq + + org_ids.each do |id| + current = Template.current(id) + live = Template.live(id) + org_templates << {current: current, live: live} end - @templates_own = current_templates.values - @other_published_version = {} - current_templates.keys.each do |dmptemplate_id| - @other_published_version[dmptemplate_id] = Template.where(org_id: current_user.org_id, dmptemplate_id: dmptemplate_id, published: true).present? + funder_ids.each do |id| + funder_live = Template.live(id) + current = Template.org_customizations(id, current_user.org_id) + # if we have a current template, check to see if there is a live version + live = current.nil? ? nil : Template.live(current.dmptemplate_id) + # need a current version, default to funder live if no custs exist + current = funder_live unless current.present? + + funder_templates << {current: current, live: live, funder_live: funder_live, stale: funder_live.updated_at > current.created_at} end - # funders templates - funders_templates = {} - Org.includes(:templates).funder.each do |org| - org.templates.where(customization_of: nil, published: true).order(version: :desc).each do |temp| - if funders_templates[temp.dmptemplate_id].nil? - funders_templates[temp.dmptemplate_id] = temp - end - end - end - - @templates_funders = funders_templates.values - # are any funder templates customized - @templates_customizations = {} - Template.where(org_id: current_user.org_id, customization_of: funders_templates.keys).order(version: :desc).each do |temp| - if @templates_customizations[temp.customization_of].nil? - @templates_customizations[temp.customization_of] = {} - @templates_customizations[temp.customization_of][:temp] = temp - @templates_customizations[temp.customization_of][:published] = temp.published - else - @templates_customizations[temp.customization_of][:published] = @templates_customizations[temp.customization_of][:published] || temp.published - end - end + @funder_templates = funder_templates.sort{|x,y| + x[:current].title <=> y[:current].title + } + @org_templates = org_templates.sort{|x,y| + x[:current].title <=> y[:current].title + } end - - # GET /dmptemplates/1 - def admin_template + # GET /org/admin/templates/:id/admin_customize + # ----------------------------------------------------- + def admin_customize @template = Template.find(params[:id]) - # check to see if this is a funder template needing customized - if @template.org_id != current_user.org_id - # definitely need to deep_copy the given template - new_customization = Template.deep_copy(@template) - new_customization.org_id = current_user.org_id - new_customization.published = false - new_customization.customization_of = @template.dmptemplate_id - # need to mark all Phases, questions, sections as not-modifiable - new_customization.phases.includes(sections: :questions).each do |phase| - phase.modifiable = false - phase.save! - phase.sections.each do |section| - section.modifiable = false - section.save! - section.questions.each do |question| - question.modifiable = false - question.save! - end + authorize @template + + customisation = Template.deep_copy(@template) + customisation.org = current_user.org + customisation.version = 0 + customisation.customization_of = @template.dmptemplate_id + customisation.dmptemplate_id = loop do + random = rand 2147483647 + break random unless Template.exists?(dmptemplate_id: random) + end + customisation.save + + customisation.phases.includes(:sections, :questions).each do |phase| + phase.modifiable = false + phase.save! + phase.sections.each do |section| + section.modifiable = false + section.save! + section.questions.each do |question| + question.modifiable = false + question.save! end end - customizations = Template.includes(phases: [sections: [questions: :suggested_answers ]]).where(org_id: current_user.org_id, customization_of: @template.dmptemplate_id).order(version: :desc) - if customizations.present? - # existing customization to port over - max_version = customizations.first - new_customization.dmptemplate_id = max_version.dmptemplate_id - new_customization.version = max_version.version + 1 - # here we rip the customizations out of the old template - # First, we find any customized phases or sections - max_version.phases.each do |phase| - # check if the phase was added as a customization - if phase.modifiable - # deep copy the phase and add it to the template - phase_copy = Phase.deep_copy(phase) - phase_copy.number = new_customization.phases.length + 1 - phase_copy.template_id = new_customization.id - phase_copy.save! + end + + redirect_to admin_template_template_path(customisation) + end + + # GET /org/admin/templates/:id/admin_transfer_customization + # the funder template's id is passed through here + # ----------------------------------------------------- + def admin_transfer_customization + @template = Template.includes(:org).find(params[:id]) + authorize @template + new_customization = Template.deep_copy(@template) + new_customization.org_id = current_user.org_id + new_customization.published = false + new_customization.customization_of = @template.dmptemplate_id + new_customization.dirty = true + new_customization.phases.includes(sections: :questions).each do |phase| + phase.modifiable = false + phase.save + phase.sections.each do |section| + section.modifiable = false + section.save + section.questions.each do |question| + question.modifiable = false + question.save + end + end + end + customizations = Template.includes(:org, phases:[sections: [questions: :annotations]]).where(org_id: current_user.org_id, customization_of: @template.dmptemplate_id).order(version: :desc) + # existing version to port over + max_version = customizations.first + new_customization.dmptemplate_id = max_version.dmptemplate_id + new_customization.version = max_version.version + 1 + # here we rip the customizations out of the old template + # First, we find any customzed phases or sections + max_version.phases.each do |phase| + # check if the phase was added as a customization + if phase.modifiable + # deep copy the phase and add it to the template + phase_copy = Phase.deep_copy(phase) + phase_copy.number = new_customization.phases.length + 1 + phase_copy.template_id = new_customization.id + phase_copy.save! + else + # iterate over the sections to see if any of them are customizations + phase.sections.each do |section| + if section.modifiable + # this is a custom section + section_copy = Section.deep_copy(section) + customization_phase = new_customization.phases.includes(:sections).where(number: phase.number).first + section_copy.phase_id = customization_phase.id + # custom sections get added to the end + section_copy.number = customization_phase.sections.length + 1 + # section from phase with corresponding number in the main_template + section_copy.save! else - # iterate over the sections to see if any of them are customizations - phase.sections.each do |section| - if section.modifiable - # this is a custom section - section_copy = Section.deep_copy(section) - customization_phase = new_customization.phases.includes(:sections).where(number: phase.number).first - section_copy.phase_id = customization_phase.id - # custom sections get added to the end - section_copy.number = customization_phase.sections.length + 1 - # section from phase with corresponding number in the main_template - section_copy.save! - else - # not a customized section, iterate over questions - customization_phase = new_customization.phases.includes(sections: [questions: :suggested_answers]).where(number: phase.number).first - customization_section = customization_phase.sections.where(number: section.number).first - section.questions.each do |question| - # find corresponding question in new template - customization_question = customization_section.questions.where(number: question.number).first - # apply suggested_answers - question.suggested_answers.each do |suggested_answer| - suggested_answer_copy = SuggestedAnswer.deep_copy(suggested_answer) - suggested_answer_copy.org_id = current_user.org_id - suggested_answer_copy.question_id = customization_question.id - suggested_answer_copy.save! - end - # guidance attached to a question is also a form of customization - # It will soon become an annotation of the question, and be combined with - # suggested answers - customization_question.guidance = customization_question.guidance + question.guidance - customization_question.save! - end + # not a customized section, iterate over questions + customization_phase = new_customization.phases.includes(sections: [questions: :annotations]).where(number: phase.number).first + customization_section = customization_phase.sections.where(number: section.number).first + section.questions.each do |question| + # find corresponding question in new template + customization_question = customization_section.questions.where(number: question.number).first + # apply annotations + question.annotations.where(org_id: current_user.org_id).each do |annotation| + annotation_copy = Annotation.deep_copy(annotation) + annotation_copy.question_id = customization_question.id + annotation_copy.save! end end end end - else - # first time customization - new_customization.version = 0 - new_customization.dmptemplate_id = loop do - random = rand 2147483647 # max int field in psql - break random unless Template.exists?(dmptemplate_id: random) - end end - new_customization.save! - @template = new_customization end - # needed for some post-migration edge cases - # some customized templates which were edited - if @template.published + new_customization.save + redirect_to admin_template_template_path(new_customization) + end + + # PUT /org/admin/templates/:id/admin_publish + # ----------------------------------------------------- + def admin_publish + @template = Template.find(params[:id]) + authorize @template + + current = Template.current(@template.dmptemplate_id) + + # Only allow the current version to be updated + if current != @template + redirect_to admin_template_template_path(@template), notice: _('You can not publish a historical version of this template.') + + else + # Unpublish the older published version if there is one + live = Template.live(@template.dmptemplate_id) + if !live.nil? and self != live + live.published = false + live.save! + end + # Set the dirty flag to false + @template.dirty = false + @template.published = true + @template.save + + flash[:notice] = _('Your template has been published and is now available to users.') + + redirect_to admin_index_template_path(current_user.org) + end + end + + # PUT /org/admin/templates/:id/admin_unpublish + # ----------------------------------------------------- + def admin_unpublish + template = Template.find(params[:id]) + authorize template + + # Unpublish the live version + @template = Template.live(template.dmptemplate_id) + + if @template.nil? + flash[:notice] = _('That template is not currently published.') + else + @template.published = false + @template.save + flash[:notice] = _('Your template is no longer published. Users will not be able to create new DMPs for this template until you re-publish it') + end + + redirect_to admin_index_template_path(current_user.org) + end + + # GET /org/admin/templates/:id/admin_template + # ----------------------------------------------------- + def admin_template + @template = Template.includes(:org, phases: [sections: [questions: [:question_options, :question_format, :annotations]]]).find(params[:id]) + authorize @template + + @current = Template.current(@template.dmptemplate_id) + + if @template == @current + # If the template is published + if @template.published? + # We need to create a new, editable version + new_version = Template.deep_copy(@template) + new_version.version = (@template.version + 1) + new_version.published = false + new_version.save + @template = new_version +# @current = Template.current(@template.dmptemplate_id) + end + else + flash[:notice] = _('You are viewing a historical version of this template. You will not be able to make changes.') + end + + # If the template is published + if @template.published? + # We need to create a new, editable version new_version = Template.deep_copy(@template) - new_version.version = @template.version + 1 + new_version.version = (@template.version + 1) new_version.published = false - new_version.save! + new_version.save @template = new_version end - authorize @template + + # once the correct template has been generated, we convert it to hash + @hash = @template.to_hash end - # PUT /dmptemplates/1 + # PUT /org/admin/templates/:id/admin_update + # ----------------------------------------------------- def admin_update @template = Template.find(params[:id]) authorize @template - if @template.published? - # published templates cannot be edited - redirect_to admin_template_template_path(@template), notice: I18n.t('org_admin.templates.read_only') and return - end - @template.description = params["template-desc"] - if @template.update_attributes(params[:template]) - if @template.published - # create a new template version if this template became published - new_version = Template.deep_copy(@template) - new_version.version = @template.version + 1 - new_version.published = false - new_version.save! - end - redirect_to admin_index_template_path(), notice: I18n.t('org_admin.templates.updated_message') + + current = Template.current(@template.dmptemplate_id) + + # Only allow the current version to be updated + if current != @template + redirect_to admin_template_template_path(@template), notice: _('You can not edit a historical version of this template.') + else - render action: "edit" + if @template.description != params["template-desc"] || + @template.title != params[:template][:title] + @template.dirty = true + end + + @template.description = params["template-desc"] + if @template.update_attributes(params[:template]) + flash[:notice] = _('Information was successfully updated.') + + else + flash[:notice] = failed_update_error(@template, _('template')) + end + + @hash = @template.to_hash + render 'admin_template' end end - # GET /dmptemplates/new + # GET /org/admin/templates/:id/admin_new + # ----------------------------------------------------- def admin_new authorize Template end - # POST /dmptemplates - # creates a new template with version 0 and new dmptemplate_id + # POST /org/admin/templates/:id/admin_create + # ----------------------------------------------------- def admin_create + # creates a new template with version 0 and new dmptemplate_id @template = Template.new(params[:template]) - @template.org_id = current_user.org_id - @template.description = params['template-desc'] - @template.published = false - @template.version = 0 - # Generate a unique identifier for the dmptemplate_id - @template.dmptemplate_id = loop do - random = rand 2147483647 - break random unless Template.exists?(dmptemplate_id: random) - end authorize @template + @template.org_id = current_user.org.id + @template.description = params['template-desc'] + if @template.save - redirect_to admin_template_template_path(@template), notice: I18n.t('org_admin.templates.created_message') + redirect_to admin_template_template_path(@template), notice: _('Information was successfully created.') else + @hash = @template.to_hash + flash[:notice] = failed_create_error(@template, _('template')) render action: "admin_new" end end - # DELETE /dmptemplates/1 + # DELETE /org/admin/templates/:id/admin_destroy + # ----------------------------------------------------- def admin_destroy @template = Template.find(params[:id]) authorize @template - @template.destroy - redirect_to admin_index_template_path + + current = Template.current(@template.dmptemplate_id) + + # Only allow the current version to be destroyed + if current == @template + if @template.destroy + redirect_to admin_index_template_path + else + @hash = @template.to_hash + flash[:notice] = failed_destroy_error(@template, _('template')) + render admin_template_template_path(@template) + end + else + flash[:notice] = _('You cannot delete historical versions of this template.') + redirect_to admin_index_template_path + end end - # GET /templates/1 + # GET /org/admin/templates/:id/admin_template_history + # ----------------------------------------------------- def admin_template_history @template = Template.find(params[:id]) authorize @template @templates = Template.where(dmptemplate_id: @template.dmptemplate_id).order(:version) + @current = Template.current(@template.dmptemplate_id) end - - - # PHASES - - #show and edit a phase of the template - def admin_phase - @phase = Phase.find(params[:id]) - authorize @phase.template - @edit = params[:edit] == "true" ? true : false - #verify if there are any sections if not create one - @sections = @phase.sections - if !@sections.any?() || @sections.count == 0 - @section = @phase.sections.build - @section.phase = @phase - @section.title = '' - @section.number = 1 - @section.published = true - @section.modifiable = true - @section.save - @new_sec = true - end - #verify if section_id has been passed, if so then open that section - if params.has_key?(:section_id) - @open = true - @section_id = params[:section_id].to_i - end - if params.has_key?(:question_id) - @question_id = params[:question_id].to_i - end - end - - - #preview a phase - def admin_previewphase - @phase = Phase.find(params[:id]) - authorize @phase.template - @template = @phase.template - end - - - #add a new phase to a template - def admin_addphase - @template = Template.find(params[:id]) - @phase = Phase.new - authorize @template - @phase.number = @template.phases.count + 1 - end - - - #create a phase - def admin_createphase - @phase = Phase.new(params[:phase]) - authorize @phase.template - @phase.description = params["phase-desc"] - @phase.modifiable = true - if @phase.save - redirect_to admin_phase_template_path(id: @phase.id, edit: 'true'), notice: I18n.t('org_admin.templates.created_message') - else - render action: "admin_phase" - end - end - - - #update a phase of a template - def admin_updatephase - @phase = Phase.find(params[:id]) - authorize @phase.template - @phase.description = params["phase-desc"] - if @phase.update_attributes(params[:phase]) - redirect_to admin_phase_template_path(@phase), notice: I18n.t('org_admin.templates.updated_message') - else - render action: "admin_phase" - end - end - - #delete a phase - def admin_destroyphase - @phase = Phase.find(params[:phase_id]) - authorize @phase.template - @template = @phase.template - @phase.destroy - redirect_to admin_template_template_path(@template), notice: I18n.t('org_admin.templates.destroyed_message') - end - -# SECTIONS - #create a section - def admin_createsection - @section = Section.new(params[:section]) - authorize @section.phase.template - @section.description = params["section-desc"] - @section.modifiable = true - if @section.save - redirect_to admin_phase_template_path(id: @section.phase_id, - :section_id => @section.id, edit: 'true'), notice: I18n.t('org_admin.templates.created_message') - else - render action: "admin_phase" - end - end - - - #update a section of a template - def admin_updatesection - @section = Section.find(params[:id]) - authorize @section.phase.template - @section.description = params["section-desc-#{params[:id]}"] - @phase = @section.phase - if @section.update_attributes(params[:section]) - redirect_to admin_phase_template_path(id: @phase.id, section_id: @section.id , edit: 'true'), notice: I18n.t('org_admin.templates.updated_message') - else - render action: "admin_phase" - end - end - - - #delete a section and questions - def admin_destroysection - @section = Section.find(params[:section_id]) - authorize @section.phase.template - @phase = @section.phase - @section.destroy - redirect_to admin_phase_template_path(id: @phase.id, edit: 'true' ), notice: I18n.t('org_admin.templates.destroyed_message') - end - - -# QUESTIONS - - #create a question - def admin_createquestion - @question = Question.new(params[:question]) - authorize @question.section.phase.template - @question.guidance = params["new-question-guidance"] - @question.default_value = params["new-question-default-value"] - if @question.save! - redirect_to admin_phase_template_path(id: @question.section.phase_id, section_id: @question.section_id, question_id: @question.id, edit: 'true'), notice: I18n.t('org_admin.templates.created_message') - else - render action: "admin_phase" - end - end - - #update a question of a template - def admin_updatequestion - @question = Question.find(params[:id]) - authorize @question.section.phase.template - @question.guidance = params["question-guidance-#{params[:id]}"] - @question.default_value = params["question-default-value-#{params[:id]}"] - @section = @question.section - @phase = @section.phase - if @question.update_attributes(params[:question]) - redirect_to admin_phase_template_path(id: @phase.id, section_id: @section.id, question_id: @question.id, edit: 'true'), notice: I18n.t('org_admin.templates.updated_message') - else - render action: "admin_phase" - end - end - - #delete question - def admin_destroyquestion - @question = Question.find(params[:question_id]) - authorize @question.section.phase.template - @section = @question.section - @phase = @section.phase - @question.destroy - redirect_to admin_phase_template_path(id: @phase.id, section_id: @section.id, edit: 'true'), notice: I18n.t('org_admin.templates.destroyed_message') - end - - - #SUGGESTED ANSWERS - #create suggested answers - def admin_createsuggestedanswer - @suggested_answer = SuggestedAnswer.new(params[:suggested_answer]) - authorize @suggested_answer.question.section.phase.template - if @suggested_answer.save - redirect_to admin_phase_template_path(id: @suggested_answer.question.section.phase_id, section_id: @suggested_answer.question.section_id, question_id: @suggested_answer.question.id, edit: 'true'), notice: I18n.t('org_admin.templates.created_message') - else - render action: "admin_phase" - end - end - - - #update a suggested answer of a template - def admin_updatesuggestedanswer - @suggested_answer = SuggestedAnswer.find(params[:id]) - authorize @suggested_answer.question.section.phase.template - @question = @suggested_answer.question - @section = @question.section - @phase = @section.phase - if @suggested_answer.update_attributes(params[:suggested_answer]) - redirect_to admin_phase_template_path(id: @phase.id, section_id: @section.id, question_id: @question.id, edit: 'true'), notice: I18n.t('org_admin.templates.updated_message') - else - render action: "admin_phase" - end - end - - #delete a suggested answer - def admin_destroysuggestedanswer - @suggested_answer = SuggestedAnswer.find(params[:suggested_answer]) - authorize @suggested_answer.question.section.phase.template - @question = @suggested_answer.question - @section = @question.section - @phase = @section.phase - @suggested_answer.destroy - redirect_to admin_phase_template_path(id: @phase.id, section_id: @section.id, edit: 'true'), notice: I18n.t('org_admin.templates.destroyed_message') - end - -end \ No newline at end of file +end diff --git a/app/controllers/user_identifiers_controller.rb b/app/controllers/user_identifiers_controller.rb index 040a50b..6b78c8e 100644 --- a/app/controllers/user_identifiers_controller.rb +++ b/app/controllers/user_identifiers_controller.rb @@ -1,25 +1,23 @@ class UserIdentifiersController < ApplicationController + respond_to :html + after_action :verify_authorized # DELETE /users/identifiers # --------------------------------------------------------------------- def destroy - if user_signed_in? then - user = User.find(current_user.id) - identifier = UserIdentifier.find(params[:id]) - - # If the requested identifier belongs to the current user remove it - if user.user_identifiers.include?(identifier) - identifier.destroy! - flash[:notice] = t('identifier_schemes.disconnect_success', - scheme: identifier.identifier_scheme.name) - - else - flash[:notice] = t('identifier_schemes.disconnect_failure', - scheme: identifier.identifier_scheme.name) - end - - redirect_to edit_user_registration_path + authorize UserIdentifier + user = User.find(current_user.id) + identifier = UserIdentifier.find(params[:id]) + + # If the requested identifier belongs to the current user remove it + if user.user_identifiers.include?(identifier) + identifier.destroy! + flash[:notice] = _('Successfully unlinked your account from %{is}.') % {is: identifier.identifier_scheme.description} + else + flash[:notice] = _('Unable to unlink your account from %{is}.') % {is: identifier.identifier_scheme.description} end + + redirect_to edit_user_registration_path end -end \ No newline at end of file +end diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index 593e146..d50e397 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -31,8 +31,14 @@ # Otherwise sign them in else - sign_in_and_redirect user, event: :authentication - set_flash_message(:notice, :success, kind: scheme.name) if is_navigational_format? + # Until ORCID becomes supported as a login method + if scheme.name == 'shibboleth' + set_flash_message(:notice, :success, kind: scheme.description) if is_navigational_format? + sign_in_and_redirect user, event: :authentication + else + flash[:notice] = t('identifier_schemes.new_login_success') + redirect_to new_user_registration_url + end end # The user is already logged in and just registering the uid with us @@ -43,9 +49,9 @@ identifier: request.env["omniauth.auth"].uid, user: current_user) - flash[:notice] = t('identifier_schemes.connect_success', scheme: scheme.name) + flash[:notice] = _('Your account has been successfully linked to %{scheme}.') % { scheme: scheme.description } else - flash[:notice] = t('identifier_schemes.connect_failure', scheme: scheme.name) + flash[:notice] = _('Unable to link your account to %{scheme}.') % { scheme: scheme.description } end end @@ -53,63 +59,9 @@ redirect_to edit_user_registration_path end end - - - # TODO: We should consider rolling the below function up into the - # generic handler above # ------------------------------------------------------------- - def shibboleth - if user_signed_in? && current_user.shibboleth_id.present? && current_user.shibboleth_id.length > 0 then - flash[:warning] = I18n.t('devise.failure.already_authenticated') - redirect_to root_path - else - auth = request.env['omniauth.auth'] || {} - eppn = auth['extra']['raw_info']['eppn'] - uid = nil - if !eppn.blank? then - uid = eppn - elsif !auth['uid'].blank? then - uid = auth['uid'] - elsif !auth['extra']['raw_info']['targeted-id'].blank? then - uid = auth['extra']['raw_info']['targeted-id'] - end - if !uid.nil? && !uid.blank? then - s_user = User.where(shibboleth_id: uid).first - # Take out previous record if was not confirmed. - if !s_user.nil? && s_user.confirmed_at.nil? then - sign_out s_user - User.delete(s_user.id) - s_user = nil - end - # Stops Shibboleth ID being blocked if email incorrectly entered. - if !s_user.nil? && s_user.try(:persisted?) then - flash[:notice] = I18n.t('devise.omniauth_callbacks.success', :kind => 'Shibboleth') - sign_in s_user - redirect_to root_path - else - if user_signed_in? then - current_user.update_attribute('shibboleth_id', uid) - user_id = current_user.id - sign_out current_user - session.delete(:shibboleth_data) - s_user = User.find(user_id) - sign_in s_user - redirect_to edit_user_registration_path - else - session[:shibboleth_data] = request.env['omniauth.auth'] - session[:shibboleth_data][:uid] = uid - redirect_to new_user_registration_url(:nosplash => 'true') - end - end - else - redirect_to root_path - end - end - end - - # ------------------------------------------------------------- def failure redirect_to root_path end diff --git a/app/controllers/users/omniauth_shibboleth_request_controller.rb b/app/controllers/users/omniauth_shibboleth_request_controller.rb deleted file mode 100644 index 3190c2f..0000000 --- a/app/controllers/users/omniauth_shibboleth_request_controller.rb +++ /dev/null @@ -1,22 +0,0 @@ -class Users::OmniauthShibbolethRequestController < ApplicationController - before_filter :authenticate_user!, only: :associate - - def redirect - if !current_user.nil? && !current_user.org.nil? - idp = params[:idp] || current_user.org.wayfless_entity - else - idp = params[:idp] - end - query_params = {target: user_omniauth_callback_path(:shibboleth)} - unless idp.blank? - query_params[:entityID] = idp - end - redirect_to "#{Rails.application.config.shibboleth_login}?#{query_params.to_query}", status: 302 - end - - def associate - # This action is protected - can only be reached if user is already logged in. - # See before_filter - redirect_to user_omniauth_callback_path(:shibboleth) - end -end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 6ca0cd7..b26a62e 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -18,12 +18,13 @@ @user = User.includes(:perms).find(params[:id]) authorize @user user_perms = current_user.perms - @perms = user_perms & Perm.where(name: [constant("user_role_types.change_org_details"),constant("user_role_types.use_api"), constant("user_role_types.modify_guidance"), constant("user_role_types.modify_templates"), constant("user_role_types.grant_permissions")]) + @perms = user_perms & [Perm.grant_permissions, Perm.modify_templates, Perm.modify_guidance, Perm.use_api, Perm.change_org_details] end ## # POST - updates the permissions for a user # redirects to the admin_index action + # should add validation that the perms given are current perms of the current_user def admin_update_permissions @user = User.includes(:perms).find(params[:id]) authorize @user @@ -33,21 +34,25 @@ if @user.perms.include? perm if ! perms.include? perm @user.perms.delete(perm) - if perm.name == constant("user_role_types.use_api") + if perm.id == Perm.use_api.id @user.remove_token! end end else if perms.include? perm @user.perms << perm - if perm.name == constant("user_role_types.use_api") + if perm.id == Perm.use_api.id @user.keep_or_generate_token! end end end end - @user.save! - redirect_to({controller: 'users', action: 'admin_index'}, {notice: I18n.t('helpers.success')}) + + if @user.save! + redirect_to({controller: 'users', action: 'admin_index'}, {notice: _('Information was successfully updated.')}) # helpers.success key does not exist, replaced with a generic string + else + flash[:notice] = failed_update_error(@user, _('user')) + end end end diff --git a/app/dashboards/annotation_dashboard.rb b/app/dashboards/annotation_dashboard.rb new file mode 100644 index 0000000..e26b609 --- /dev/null +++ b/app/dashboards/annotation_dashboard.rb @@ -0,0 +1,60 @@ +require "administrate/base_dashboard" + +class AnnotationDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + org: Field::BelongsTo, + question: Field::BelongsTo, + id: Field::Number, + text: Field::Text, + type: Field::String.with_options(searchable: false), + created_at: Field::DateTime, + updated_at: Field::DateTime, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :org, + :question, + :id, + :text, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :org, + :question, + :id, + :text, + :type, + :created_at, + :updated_at, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :org, + :question, + :text, + :type, + ].freeze + + # Overwrite this method to customize how annotations are displayed + # across all pages of the admin dashboard. + # + # def display_resource(annotation) + # "Annotation ##{annotation.id}" + # end +end diff --git a/app/dashboards/answer_dashboard.rb b/app/dashboards/answer_dashboard.rb new file mode 100644 index 0000000..ad7df7f --- /dev/null +++ b/app/dashboards/answer_dashboard.rb @@ -0,0 +1,69 @@ +require "administrate/base_dashboard" + +class AnswerDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + question: Field::BelongsTo, + user: Field::BelongsTo, + plan: Field::BelongsTo, + notes: Field::HasMany, + question_options: Field::HasMany, + id: Field::Number, + text: Field::Text, + created_at: Field::DateTime, + updated_at: Field::DateTime, + lock_version: Field::Number, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :question, + :user, + :plan, + :notes, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :question, + :user, + :plan, + :notes, + :question_options, + :id, + :text, + :created_at, + :updated_at, + :lock_version, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :question, + :user, + :plan, + :notes, + :question_options, + :text, + :lock_version, + ].freeze + + # Overwrite this method to customize how answers are displayed + # across all pages of the admin dashboard. + # + # def display_resource(answer) + # "Answer ##{answer.id}" + # end +end diff --git a/app/dashboards/exported_plan_dashboard.rb b/app/dashboards/exported_plan_dashboard.rb new file mode 100644 index 0000000..ec618cf --- /dev/null +++ b/app/dashboards/exported_plan_dashboard.rb @@ -0,0 +1,63 @@ +require "administrate/base_dashboard" + +class ExportedPlanDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + plan: Field::BelongsTo, + user: Field::BelongsTo, + setting_objects: Field::HasMany.with_options(class_name: "Settings::Template"), + id: Field::Number, + format: Field::String, + created_at: Field::DateTime, + updated_at: Field::DateTime, + phase_id: Field::Number, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :plan, + :user, + :setting_objects, + :id, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :plan, + :user, + :setting_objects, + :id, + :format, + :created_at, + :updated_at, + :phase_id, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :plan, + :user, + :setting_objects, + :format, + :phase_id, + ].freeze + + # Overwrite this method to customize how exported plans are displayed + # across all pages of the admin dashboard. + # + # def display_resource(exported_plan) + # "ExportedPlan ##{exported_plan.id}" + # end +end diff --git a/app/dashboards/guidance_dashboard.rb b/app/dashboards/guidance_dashboard.rb new file mode 100644 index 0000000..c76c41b --- /dev/null +++ b/app/dashboards/guidance_dashboard.rb @@ -0,0 +1,63 @@ +require "administrate/base_dashboard" + +class GuidanceDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + guidance_group: Field::BelongsTo, + themes: Field::HasMany, + id: Field::Number, + text: Field::Text, + created_at: Field::DateTime, + updated_at: Field::DateTime, + question_id: Field::Number, + published: Field::Boolean, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :guidance_group, + :themes, + :id, + :text, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :guidance_group, + :themes, + :id, + :text, + :created_at, + :updated_at, + :question_id, + :published, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :guidance_group, + :themes, + :text, + :question_id, + :published, + ].freeze + + # Overwrite this method to customize how guidances are displayed + # across all pages of the admin dashboard. + # + # def display_resource(guidance) + # "Guidance ##{guidance.id}" + # end +end diff --git a/app/dashboards/guidance_group_dashboard.rb b/app/dashboards/guidance_group_dashboard.rb new file mode 100644 index 0000000..76e2f09 --- /dev/null +++ b/app/dashboards/guidance_group_dashboard.rb @@ -0,0 +1,70 @@ +require "administrate/base_dashboard" + +class GuidanceGroupDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + org: Field::BelongsTo, + guidances: Field::HasMany, + plans: Field::HasMany, + id: Field::Number, + name: Field::String, + created_at: Field::DateTime, + updated_at: Field::DateTime, + optional_subset: Field::Boolean, + published: Field::Boolean, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :name, + :org, + :guidances, +# :plans, + :id, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :org, + :guidances, +# :plans, + :id, + :name, + :created_at, + :updated_at, + :optional_subset, + :published, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :org, + :guidances, +# :plans, + :name, + :optional_subset, + :published, + ].freeze + + # Overwrite this method to customize how guidance groups are displayed + # across all pages of the admin dashboard. + # + # def display_resource(guidance_group) + # "GuidanceGroup ##{guidance_group.id}" + # end + def display_resource(guidance_group) + guidance_group.name + end +end diff --git a/app/dashboards/identifier_scheme_dashboard.rb b/app/dashboards/identifier_scheme_dashboard.rb new file mode 100644 index 0000000..7dc1dca --- /dev/null +++ b/app/dashboards/identifier_scheme_dashboard.rb @@ -0,0 +1,68 @@ +require "administrate/base_dashboard" + +class IdentifierSchemeDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + user_identifiers: Field::HasMany, + users: Field::HasMany, + id: Field::Number, + name: Field::String, + description: Field::String, + active: Field::Boolean, + created_at: Field::DateTime, + updated_at: Field::DateTime, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :name, + :description, + :user_identifiers, + :users, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :user_identifiers, + :users, + :id, + :name, + :description, + :active, + :created_at, + :updated_at, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :user_identifiers, + :users, + :name, + :description, + :active, + ].freeze + + # Overwrite this method to customize how identifier schemes are displayed + # across all pages of the admin dashboard. + # + # def display_resource(identifier_scheme) + # "IdentifierScheme ##{identifier_scheme.id}" + # end + + def display_resource(identifier_scheme) + identifier_scheme.description + end + +end diff --git a/app/dashboards/language_dashboard.rb b/app/dashboards/language_dashboard.rb new file mode 100644 index 0000000..c888a7d --- /dev/null +++ b/app/dashboards/language_dashboard.rb @@ -0,0 +1,68 @@ +require "administrate/base_dashboard" + +class LanguageDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + users: Field::HasMany, + orgs: Field::HasMany, + id: Field::Number, + abbreviation: Field::String, + description: Field::String, + name: Field::String, + default_language: Field::Boolean, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :abbreviation, + :name, + :users, + :orgs, + :default_language, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :users, + :orgs, + :id, + :abbreviation, + :description, + :name, + :default_language, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + # :users, + # :orgs, + :abbreviation, + :description, + :name, + :default_language, + ].freeze + + # Overwrite this method to customize how languages are displayed + # across all pages of the admin dashboard. + # + # def display_resource(language) + # "Language ##{language.id}" + # end + + def display_resource(language) + language.abbreviation + end + +end diff --git a/app/dashboards/note_dashboard.rb b/app/dashboards/note_dashboard.rb new file mode 100644 index 0000000..5912418 --- /dev/null +++ b/app/dashboards/note_dashboard.rb @@ -0,0 +1,63 @@ +require "administrate/base_dashboard" + +class NoteDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + answer: Field::BelongsTo, + user: Field::BelongsTo, + id: Field::Number, + text: Field::Text, + archived: Field::Boolean, + archived_by: Field::Number, + created_at: Field::DateTime, + updated_at: Field::DateTime, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :answer, + :user, + :id, + :text, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :answer, + :user, + :id, + :text, + :archived, + :archived_by, + :created_at, + :updated_at, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :answer, + :user, + :text, + :archived, + :archived_by, + ].freeze + + # Overwrite this method to customize how notes are displayed + # across all pages of the admin dashboard. + # + # def display_resource(note) + # "Note ##{note.id}" + # end +end diff --git a/app/dashboards/org_dashboard.rb b/app/dashboards/org_dashboard.rb new file mode 100644 index 0000000..72f8962 --- /dev/null +++ b/app/dashboards/org_dashboard.rb @@ -0,0 +1,115 @@ +require "administrate/base_dashboard" + +class OrgDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + language: Field::BelongsTo, + guidance_groups: Field::HasMany, + templates: Field::HasMany, + users: Field::HasMany, + annotations: Field::HasMany, + token_permission_types: Field::HasMany, + id: Field::Number, + name: Field::String, + abbreviation: Field::String, + target_url: Field::String, + wayfless_entity: Field::String, + created_at: Field::DateTime, + updated_at: Field::DateTime, + parent_id: Field::Number, + is_other: Field::Boolean, + sort_name: Field::String, + banner_text: Field::Text, + logo_file_name: Field::String, + region_id: Field::Number, + logo_uid: Field::String, + logo_name: Field::String, + contact_email: Field::String, + org_type: Field::Number, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :name, + :abbreviation, + :language, + :guidance_groups, +# :templates, + :contact_email, + :org_type, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :name, + :abbreviation, + :language, + :guidance_groups, +# :templates, + :contact_email, + :org_type, + :users, + :annotations, + :token_permission_types, + :id, + :target_url, + :wayfless_entity, + :created_at, + :updated_at, + :parent_id, + :is_other, + :sort_name, + :banner_text, + :logo_file_name, + :region_id, + :logo_uid, + :logo_name, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :language, + :guidance_groups, +# :templates, +# :users, +# :annotations, + :token_permission_types, + :name, + :abbreviation, + :target_url, + :wayfless_entity, + :parent_id, + :is_other, + :sort_name, + :banner_text, + :logo_file_name, + :region_id, + :logo_uid, + :logo_name, + :contact_email, + :org_type, + ].freeze + + # Overwrite this method to customize how orgs are displayed + # across all pages of the admin dashboard. + # + # def display_resource(org) + # "Org ##{org.id}" + # end + + def display_resource(org) + org.name + end +end diff --git a/app/dashboards/perm_dashboard.rb b/app/dashboards/perm_dashboard.rb new file mode 100644 index 0000000..dc9e20b --- /dev/null +++ b/app/dashboards/perm_dashboard.rb @@ -0,0 +1,59 @@ +require "administrate/base_dashboard" + +class PermDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + users: Field::HasMany, + id: Field::Number, + name: Field::String, + created_at: Field::DateTime, + updated_at: Field::DateTime, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :id, + :name, + :users, + :created_at, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :id, + :name, + :users, + :created_at, + :updated_at, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ +# :users, + :name, + ].freeze + + # Overwrite this method to customize how perms are displayed + # across all pages of the admin dashboard. + # + # def display_resource(perm) + # "Perm ##{perm.id}" + # end + + def display_resource(perm) + perm.name + end + +end diff --git a/app/dashboards/phase_dashboard.rb b/app/dashboards/phase_dashboard.rb new file mode 100644 index 0000000..966961b --- /dev/null +++ b/app/dashboards/phase_dashboard.rb @@ -0,0 +1,72 @@ +require "administrate/base_dashboard" + +class PhaseDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + template: Field::BelongsTo, + sections: Field::HasMany, + questions: Field::HasMany, + id: Field::Number, + title: Field::String, + description: Field::Text, + number: Field::Number, + created_at: Field::DateTime, + updated_at: Field::DateTime, + slug: Field::String, + modifiable: Field::Boolean, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :template, + :sections, + :questions, + :id, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :template, + :sections, + :questions, + :id, + :title, + :description, + :number, + :created_at, + :updated_at, + :slug, + :modifiable, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :template, + :sections, + :questions, + :title, + :description, + :number, + :slug, + :modifiable, + ].freeze + + # Overwrite this method to customize how phases are displayed + # across all pages of the admin dashboard. + # + # def display_resource(phase) + # "Phase ##{phase.id}" + # end +end diff --git a/app/dashboards/plan_dashboard.rb b/app/dashboards/plan_dashboard.rb new file mode 100644 index 0000000..e22c30f --- /dev/null +++ b/app/dashboards/plan_dashboard.rb @@ -0,0 +1,114 @@ +require "administrate/base_dashboard" + +class PlanDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + template: Field::BelongsTo, + phases: Field::HasMany, + sections: Field::HasMany, + questions: Field::HasMany, + themes: Field::HasMany, + answers: Field::HasMany, + notes: Field::HasMany, + roles: Field::HasMany, + users: Field::HasMany, + guidance_groups: Field::HasMany, + exported_plans: Field::HasMany, + setting_objects: Field::HasMany.with_options(class_name: "Settings::Template"), + id: Field::Number, + title: Field::String, + created_at: Field::DateTime, + updated_at: Field::DateTime, + slug: Field::String, + grant_number: Field::String, + identifier: Field::String, + description: Field::Text, + principal_investigator: Field::String, + principal_investigator_identifier: Field::String, + data_contact: Field::String, + funder_name: Field::String, + visibility: Field::String.with_options(searchable: false), + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :template, + :phases, + :sections, + :questions, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :template, + :phases, + :sections, + :questions, + :themes, + :answers, + :notes, + :roles, + :users, + :guidance_groups, + :exported_plans, + :setting_objects, + :id, + :title, + :created_at, + :updated_at, + :slug, + :grant_number, + :identifier, + :description, + :principal_investigator, + :principal_investigator_identifier, + :data_contact, + :funder_name, + :visibility, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :template, + :phases, + :sections, + :questions, + :themes, + :answers, + :notes, + :roles, + :users, + :guidance_groups, + :exported_plans, + :setting_objects, + :title, + :slug, + :grant_number, + :identifier, + :description, + :principal_investigator, + :principal_investigator_identifier, + :data_contact, + :funder_name, + :visibility, + ].freeze + + # Overwrite this method to customize how plans are displayed + # across all pages of the admin dashboard. + # + # def display_resource(plan) + # "Plan ##{plan.id}" + # end +end diff --git a/app/dashboards/plan_guidance_group_dashboard.rb b/app/dashboards/plan_guidance_group_dashboard.rb new file mode 100644 index 0000000..5e659c0 --- /dev/null +++ b/app/dashboards/plan_guidance_group_dashboard.rb @@ -0,0 +1,57 @@ +require "administrate/base_dashboard" + +class PlanGuidanceGroupDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + plan: Field::BelongsTo, + guidance_group: Field::BelongsTo, + id: Field::Number, + created_at: Field::DateTime, + updated_at: Field::DateTime, + selected: Field::Boolean, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :plan, + :guidance_group, + :id, + :created_at, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :plan, + :guidance_group, + :id, + :created_at, + :updated_at, + :selected, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :plan, + :guidance_group, + :selected, + ].freeze + + # Overwrite this method to customize how plan guidance groups are displayed + # across all pages of the admin dashboard. + # + # def display_resource(plans_guidance_group) + # "PlanGuidanceGroup ##{plans_guidance_group.id}" + # end +end diff --git a/app/dashboards/question_dashboard.rb b/app/dashboards/question_dashboard.rb new file mode 100644 index 0000000..cda2c4c --- /dev/null +++ b/app/dashboards/question_dashboard.rb @@ -0,0 +1,81 @@ +require "administrate/base_dashboard" + +class QuestionDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + answers: Field::HasMany, + question_options: Field::HasMany, + annotations: Field::HasMany, + themes: Field::HasMany, + section: Field::BelongsTo, + question_format: Field::BelongsTo, + id: Field::Number, + text: Field::Text, + default_value: Field::Text, + number: Field::Number, + created_at: Field::DateTime, + updated_at: Field::DateTime, + option_comment_display: Field::Boolean, + modifiable: Field::Boolean, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :answers, + :question_options, + :annotations, + :themes, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :answers, + :question_options, + :annotations, + :themes, + :section, + :question_format, + :id, + :text, + :default_value, + :number, + :created_at, + :updated_at, + :option_comment_display, + :modifiable, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :answers, + :question_options, + :annotations, + :themes, + :section, + :question_format, + :text, + :default_value, + :number, + :option_comment_display, + :modifiable, + ].freeze + + # Overwrite this method to customize how questions are displayed + # across all pages of the admin dashboard. + # + # def display_resource(question) + # "Question ##{question.id}" + # end +end diff --git a/app/dashboards/question_format_dashboard.rb b/app/dashboards/question_format_dashboard.rb new file mode 100644 index 0000000..76bbff3 --- /dev/null +++ b/app/dashboards/question_format_dashboard.rb @@ -0,0 +1,63 @@ +require "administrate/base_dashboard" + +class QuestionFormatDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + questions: Field::HasMany, + id: Field::Number, + title: Field::String, + description: Field::Text, + created_at: Field::DateTime, + updated_at: Field::DateTime, + option_based: Field::Boolean, + formattype: Field::String.with_options(searchable: false), + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :questions, + :id, + :title, + :description, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :questions, + :id, + :title, + :description, + :created_at, + :updated_at, + :option_based, + :formattype, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :questions, + :title, + :description, + :option_based, + :formattype, + ].freeze + + # Overwrite this method to customize how question formats are displayed + # across all pages of the admin dashboard. + # + # def display_resource(question_format) + # "QuestionFormat ##{question_format.id}" + # end +end diff --git a/app/dashboards/question_option_dashboard.rb b/app/dashboards/question_option_dashboard.rb new file mode 100644 index 0000000..967a91d --- /dev/null +++ b/app/dashboards/question_option_dashboard.rb @@ -0,0 +1,63 @@ +require "administrate/base_dashboard" + +class QuestionOptionDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + question: Field::BelongsTo, + answers: Field::HasMany, + id: Field::Number, + text: Field::String, + number: Field::Number, + is_default: Field::Boolean, + created_at: Field::DateTime, + updated_at: Field::DateTime, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :question, + :answers, + :id, + :text, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :question, + :answers, + :id, + :text, + :number, + :is_default, + :created_at, + :updated_at, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :question, + :answers, + :text, + :number, + :is_default, + ].freeze + + # Overwrite this method to customize how question options are displayed + # across all pages of the admin dashboard. + # + # def display_resource(question_option) + # "QuestionOption ##{question_option.id}" + # end +end diff --git a/app/dashboards/region_dashboard.rb b/app/dashboards/region_dashboard.rb new file mode 100644 index 0000000..851ad0e --- /dev/null +++ b/app/dashboards/region_dashboard.rb @@ -0,0 +1,62 @@ +require "administrate/base_dashboard" + +class RegionDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + sub_regions: Field::HasMany.with_options(class_name: "Region"), + super_region: Field::BelongsTo.with_options(class_name: "Region"), + id: Field::Number, + abbreviation: Field::String, + description: Field::String, + name: Field::String, + super_region_id: Field::Number, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :sub_regions, + :super_region, + :id, + :abbreviation, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :sub_regions, + :super_region, + :id, + :abbreviation, + :description, + :name, + :super_region_id, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :sub_regions, + :super_region, + :abbreviation, + :description, + :name, + :super_region_id, + ].freeze + + # Overwrite this method to customize how regions are displayed + # across all pages of the admin dashboard. + # + # def display_resource(region) + # "Region ##{region.id}" + # end +end diff --git a/app/dashboards/role_dashboard.rb b/app/dashboards/role_dashboard.rb new file mode 100644 index 0000000..0d8b9ea --- /dev/null +++ b/app/dashboards/role_dashboard.rb @@ -0,0 +1,57 @@ +require "administrate/base_dashboard" + +class RoleDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + user: Field::BelongsTo, + plan: Field::BelongsTo, + id: Field::Number, + created_at: Field::DateTime, + updated_at: Field::DateTime, + access: Field::Number, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :user, + :plan, + :id, + :created_at, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :user, + :plan, + :id, + :created_at, + :updated_at, + :access, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :user, + :plan, + :access, + ].freeze + + # Overwrite this method to customize how roles are displayed + # across all pages of the admin dashboard. + # + # def display_resource(role) + # "Role ##{role.id}" + # end +end diff --git a/app/dashboards/section_dashboard.rb b/app/dashboards/section_dashboard.rb new file mode 100644 index 0000000..2dfb78b --- /dev/null +++ b/app/dashboards/section_dashboard.rb @@ -0,0 +1,72 @@ +require "administrate/base_dashboard" + +class SectionDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + phase: Field::BelongsTo, + organisation: Field::BelongsTo, + questions: Field::HasMany, + id: Field::Number, + title: Field::String, + description: Field::Text, + number: Field::Number, + created_at: Field::DateTime, + updated_at: Field::DateTime, + published: Field::Boolean, + modifiable: Field::Boolean, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :phase, + :organisation, + :questions, + :id, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :phase, + :organisation, + :questions, + :id, + :title, + :description, + :number, + :created_at, + :updated_at, + :published, + :modifiable, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :phase, + :organisation, + :questions, + :title, + :description, + :number, + :published, + :modifiable, + ].freeze + + # Overwrite this method to customize how sections are displayed + # across all pages of the admin dashboard. + # + # def display_resource(section) + # "Section ##{section.id}" + # end +end diff --git a/app/dashboards/splash_log_dashboard.rb b/app/dashboards/splash_log_dashboard.rb new file mode 100644 index 0000000..ed549aa --- /dev/null +++ b/app/dashboards/splash_log_dashboard.rb @@ -0,0 +1,51 @@ +require "administrate/base_dashboard" + +class SplashLogDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + id: Field::Number, + destination: Field::String, + created_at: Field::DateTime, + updated_at: Field::DateTime, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :id, + :destination, + :created_at, + :updated_at, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :id, + :destination, + :created_at, + :updated_at, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :destination, + ].freeze + + # Overwrite this method to customize how splash logs are displayed + # across all pages of the admin dashboard. + # + # def display_resource(splash_log) + # "SplashLog ##{splash_log.id}" + # end +end diff --git a/app/dashboards/template_dashboard.rb b/app/dashboards/template_dashboard.rb new file mode 100644 index 0000000..7a5a313 --- /dev/null +++ b/app/dashboards/template_dashboard.rb @@ -0,0 +1,107 @@ +require "administrate/base_dashboard" + +class TemplateDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + org: Field::BelongsTo, + plans: Field::HasMany, + phases: Field::HasMany, + sections: Field::HasMany, + questions: Field::HasMany, + customizations: Field::HasMany.with_options(class_name: "Template"), + dmptemplate: Field::BelongsTo.with_options(class_name: "Template"), + setting_objects: Field::HasMany.with_options(class_name: "Settings::Template"), + id: Field::Number, + title: Field::String, + description: Field::Text, + published: Field::Boolean, + locale: Field::String, + is_default: Field::Boolean, + created_at: Field::DateTime, + updated_at: Field::DateTime, + version: Field::Number, + visibility: Field::Number, + customization_of: Field::Number, + dmptemplate_id: Field::Number, + migrated: Field::Boolean, + dirty: Field::Boolean, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :title, + :description, + :org, + :plans, + :phases, + :sections, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :org, + :plans, + :phases, + :sections, + :questions, + :customizations, + :dmptemplate, + :setting_objects, + :id, + :title, + :description, + :published, + :locale, + :is_default, + :created_at, + :updated_at, + :version, + :visibility, + :customization_of, + :dmptemplate_id, + :migrated, + :dirty, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :org, + :plans, + :phases, + :sections, + :questions, + :customizations, + :dmptemplate, + :setting_objects, + :title, + :description, + :published, + :locale, + :is_default, + :version, + :visibility, + :customization_of, + :dmptemplate_id, + :migrated, + :dirty, + ].freeze + + # Overwrite this method to customize how templates are displayed + # across all pages of the admin dashboard. + # + # def display_resource(template) + # "Template ##{template.id}" + # end +end diff --git a/app/dashboards/theme_dashboard.rb b/app/dashboards/theme_dashboard.rb new file mode 100644 index 0000000..2be7c8d --- /dev/null +++ b/app/dashboards/theme_dashboard.rb @@ -0,0 +1,66 @@ +require "administrate/base_dashboard" + +class ThemeDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + questions: Field::HasMany, + guidances: Field::HasMany, + id: Field::Number, + title: Field::String, + description: Field::Text, + created_at: Field::DateTime, + updated_at: Field::DateTime, + locale: Field::String, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :questions, + :guidances, + :id, + :title, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :questions, + :guidances, + :id, + :title, + :description, + :created_at, + :updated_at, + :locale, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :questions, + :guidances, + :title, + :description, + :locale, + ].freeze + + # Overwrite this method to customize how themes are displayed + # across all pages of the admin dashboard. + # + # def display_resource(theme) + # "Theme ##{theme.id}" + # end + def display_resource(theme) + "Theme: #{theme.title} (##{theme.id})" + end +end diff --git a/app/dashboards/token_permission_type_dashboard.rb b/app/dashboards/token_permission_type_dashboard.rb new file mode 100644 index 0000000..93deb0f --- /dev/null +++ b/app/dashboards/token_permission_type_dashboard.rb @@ -0,0 +1,61 @@ +require "administrate/base_dashboard" + +class TokenPermissionTypeDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + orgs: Field::HasMany, + id: Field::Number, + token_type: Field::String, + text_description: Field::Text, + created_at: Field::DateTime, + updated_at: Field::DateTime, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :orgs, + :id, + :token_type, + :text_description, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :orgs, + :id, + :token_type, + :text_description, + :created_at, + :updated_at, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :orgs, + :token_type, + :text_description, + ].freeze + + # Overwrite this method to customize how token permission types are displayed + # across all pages of the admin dashboard. + # + # def display_resource(token_permission_type) + # "TokenPermissionType ##{token_permission_type.id}" + # end + def display_resource(token_permission_type) + "#{token_permission_type.token_type}: #{token_permission_type.text_description}" + end + +end diff --git a/app/dashboards/user_dashboard.rb b/app/dashboards/user_dashboard.rb new file mode 100644 index 0000000..4ba23ad --- /dev/null +++ b/app/dashboards/user_dashboard.rb @@ -0,0 +1,160 @@ +require "administrate/base_dashboard" + +class UserDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + invited_by: Field::Polymorphic, + perms: Field::HasMany, + language: Field::BelongsTo, + org: Field::BelongsTo, + answers: Field::HasMany, + notes: Field::HasMany, + exported_plans: Field::HasMany, + roles: Field::HasMany, + plans: Field::HasMany, + user_identifiers: Field::HasMany, + identifier_schemes: Field::HasMany, + setting_objects: Field::HasMany.with_options(class_name: "Settings::PlanList"), + id: Field::Number, + firstname: Field::String, + surname: Field::String, + email: Field::String, + orcid_id: Field::String, + shibboleth_id: Field::String, + created_at: Field::DateTime, + updated_at: Field::DateTime, + encrypted_password: Field::String, + reset_password_token: Field::String, + reset_password_sent_at: Field::DateTime, + remember_created_at: Field::DateTime, + sign_in_count: Field::Number, + current_sign_in_at: Field::DateTime, + last_sign_in_at: Field::DateTime, + current_sign_in_ip: Field::String, + last_sign_in_ip: Field::String, + confirmation_token: Field::String, + confirmed_at: Field::DateTime, + confirmation_sent_at: Field::DateTime, + invitation_token: Field::String, + invitation_created_at: Field::DateTime, + invitation_sent_at: Field::DateTime, + invitation_accepted_at: Field::DateTime, + other_organisation: Field::String, + accept_terms: Field::Boolean, + api_token: Field::String, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :firstname, + :surname, + :email, + :org, + :perms, + :confirmed_at, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :firstname, + :surname, + :email, + :org, + :perms, + :confirmed_at, + :id, + :invited_by, + :language, + :answers, + :notes, + :exported_plans, + :roles, + :plans, + :user_identifiers, + :identifier_schemes, + :orcid_id, + :shibboleth_id, + :created_at, + :updated_at, + :encrypted_password, + :reset_password_token, + :reset_password_sent_at, + :remember_created_at, + :sign_in_count, + :current_sign_in_at, + :last_sign_in_at, + :current_sign_in_ip, + :last_sign_in_ip, + :confirmation_token, + :confirmation_sent_at, + :invitation_token, + :invitation_created_at, + :invitation_sent_at, + :invitation_accepted_at, + :other_organisation, + :accept_terms, + :api_token, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ +# :invited_by, + :perms, + :language, + :org, +# :answers, +# :notes, +# :exported_plans, +# :roles, +# :plans, + :user_identifiers, + :identifier_schemes, + :firstname, + :surname, + :email, + :orcid_id, + :shibboleth_id, +# :encrypted_password, +# :reset_password_token, +# :reset_password_sent_at, +# :remember_created_at, +# :sign_in_count, +# :current_sign_in_at, +# :last_sign_in_at, +# :current_sign_in_ip, +# :last_sign_in_ip, +# :confirmation_token, +# :confirmed_at, +# :confirmation_sent_at, +# :invitation_token, +# :invitation_created_at, +# :invitation_sent_at, +# :invitation_accepted_at, +# :other_organisation, + :accept_terms, +# :api_token, + ].freeze + + # Overwrite this method to customize how users are displayed + # across all pages of the admin dashboard. + # + # def display_resource(user) + # "User ##{user.id}" + # end + + def display_resource(user) + "#{user.firstname} #{user.surname} (##{user.id})" + end +end diff --git a/app/dashboards/user_identifier_dashboard.rb b/app/dashboards/user_identifier_dashboard.rb new file mode 100644 index 0000000..fc6d73e --- /dev/null +++ b/app/dashboards/user_identifier_dashboard.rb @@ -0,0 +1,62 @@ +require "administrate/base_dashboard" + +class UserIdentifierDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + user: Field::BelongsTo, + identifier_scheme: Field::BelongsTo, + id: Field::Number, + identifier: Field::String, + created_at: Field::DateTime, + updated_at: Field::DateTime, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = [ + :user, + :identifier_scheme, + :id, + :identifier, + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = [ + :user, + :identifier_scheme, + :id, + :identifier, + :created_at, + :updated_at, + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = [ + :user, + :identifier_scheme, + :identifier, + ].freeze + + # Overwrite this method to customize how user identifiers are displayed + # across all pages of the admin dashboard. + # + # def display_resource(user_identifier) + # "UserIdentifier ##{user_identifier.id}" + # end + + def display_resource(user_identifier) + user_identifier.identifier + end + +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 0d8de1a..8c37586 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -29,4 +29,5 @@ def isActivePage(path) return request.fullpath() == path end + end diff --git a/app/helpers/plans_helper.rb b/app/helpers/plans_helper.rb index 8cdd5d9..cf5a0c6 100644 --- a/app/helpers/plans_helper.rb +++ b/app/helpers/plans_helper.rb @@ -4,18 +4,18 @@ # -------------------------------------------------------- def plan_list_column_heading(column) if column.kind_of?(Array) - heading = (column.first.kind_of?(String) ? column.first : t("helpers.project.columns.unknown")) + heading = (column.first.kind_of?(String) ? column.first : _(' - ')) elsif column.kind_of?(String) heading = column else - heading = t("helpers.project.columns.unknown") + heading = _(' - ') end klass = (['name', 'description'].include?(heading) ? :dmp_th_big : :dmp_th_small) - content_tag(:th, t("helpers.project.columns.#{heading}"), class: klass) + content_tag(:th, t("helpers.project.columns.#{heading}"), class: klass) # parametrised YAML keys are no longer possible with gettext, TODO end # Populate a variable column for the project list @@ -26,15 +26,13 @@ klass, content = case col when 'name' - [ "dmp_td_big", link_to(plan.title, plan_path(I18n.locale, plan), class: "dmp_table_link") ] - + [ "dmp_td_big", link_to(plan.title, plan_path(plan), class: "dmp_table_link") ] when 'owner' user = plan.owner - text = if user.nil? - t("helpers.project.columns.unknown") + _(' - ') elsif user == current_user - t("helpers.me") + _('Me') else user.name end @@ -42,24 +40,32 @@ [ "tmp_td_small", text ] when 'shared' shared_num = plan.users.count - 1 - text = shared_num > 0 ? (t("helpers.yes_label") + " (with #{shared_num} people) ") : t("helpers.no_label") + text = shared_num > 0 ? (_('Yes') + " (with #{shared_num} people) ") : _('No') # Hardcoded strings are not internationalised [ "dmp_td_small", text ] when 'visibility' - ["dmp_td_small", (plan.visibility.nil? ? I18n.t("helpers.project.visibilities.labels.organisationally_visible") : I18n.t("helpers.project.visibilities.labels.#{plan.visibility}"))] + text = if plan.visibility == 'organisationally_visible' + _('Organisational') + elsif plan.visibility == 'publicly_visible' + _('Public') + elsif plan.visibility == 'is_test' + _('Test/Practice') + elsif plan.visibility == 'privately_visible' + _('Private') + end + ["dmp_td_small", text ] when 'last_edited' [ "dmp_td_small", l(plan.latest_update.to_date, formats: :short) ] when 'description' - [ "dmp_td_medium", (plan.try(col) || t("helpers.settings.unknown")) ] + [ "dmp_td_medium", (plan.try(col) || _(' - ')) ] when 'non_link_name' [ "dmp_td_big", plan.title ] when 'template' ["dmp_td_big", plan.template.title] when 'organisation' - ["dmp_td_medium", (plan.owner.org.nil? ? t("helpers.settings.unknown") : plan.owner.org.name) ] + ["dmp_td_medium", plan.template.org.name] # This will trigger 2 queries for each function call, i.e. one for templates and another for orgs tables else - [ "dmp_td_small", (plan.try(col) || t("helpers.settings.unknown")) ] + [ "dmp_td_small", (plan.try(col) || _(' - ')) ] end - content_tag(:td, content, class: klass) end diff --git a/app/helpers/settings_template_helper.rb b/app/helpers/settings_template_helper.rb new file mode 100644 index 0000000..255c95e --- /dev/null +++ b/app/helpers/settings_template_helper.rb @@ -0,0 +1,27 @@ +module SettingsTemplateHelper + # Retrieves an msgstr for a given admin_field + def admin_field_t(admin_field) + if Settings::Template::VALID_ADMIN_FIELDS.include?(admin_field) + if admin_field == 'project_name' + return _('Plan Name') + elsif admin_field == 'project_identifier' + return _('Plan ID') + elsif admin_field == 'grant_title' + return _('Grant number') + elsif admin_field == 'principal_investigator' + return _('Principal Investigator / Researcher') + elsif admin_field == 'project_data_contact' + return _('Plan Data Contact') + elsif admin_field == 'project_description' + return _('Plan Description') + elsif admin_field == 'funder' + return _('Funder') + elsif admin_field == 'institution' + return _('Institution') + elsif admin_field == 'orcid' + return _('Your ORCID') + end + end + return _('Unknown column name.') + end +end \ No newline at end of file diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index e11166a..f679ba2 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -1,24 +1,47 @@ class UserMailer < ActionMailer::Base - default from: I18n.t('helpers.main_email.from') + default from: Rails.configuration.branding[:organisation][:email] - def sharing_notification(project_group) - @project_group = project_group - mail(to: @project_group.user.email, subject: I18n.t('helpers.main_email.access_given')) + def welcome_notification(user) + @user = user + FastGettext.with_locale FastGettext.default_locale do + mail(to: @user.email, + subject: "#{_('Welcome to')} #{Rails.configuration.branding[:application][:name]}") + end + end + + def sharing_notification(role, user) + @role = role + @user = user + FastGettext.with_locale FastGettext.default_locale do + mail(to: @role.user.email, + subject: "#{_('A Data Management Plan in ')} #{Rails.configuration.branding[:application][:name]} #{_(' has been shared with you')}") + end end - def permissions_change_notification(project_group) - @project_group = project_group - mail(to: @project_group.user.email, subject: I18n.t('helpers.main_email.permission_changed')) + def permissions_change_notification(role, current_user) + @role = role + @current_user = current_user + FastGettext.with_locale FastGettext.default_locale do + mail(to: @role.user.email, + subject: "#{_('Changed permissions on a DMP in')} #{Rails.configuration.branding[:application][:name]}") + end end - def project_access_removed_notification(user, project) + def project_access_removed_notification(user, plan, current_user) @user = user - @project = project - mail(to: @user.email, subject: I18n.t('helpers.main_email.access_removed')) + @plan = plan + @current_user = current_user + FastGettext.with_locale FastGettext.default_locale do + mail(to: @user.email, + subject: "#{_('Permissions removed on a DMP in')} #{Rails.configuration.branding[:application][:name]}") + end end def api_token_granted_notification(user) @user = user - mail(to: @user.email, subject: I18n.t('helper.api_mail_subject')) + FastGettext.with_locale FastGettext.default_locale do + mail(to: @user.email, + subject: "#{_('API rights in')} #{Rails.configuration.branding[:application][:name]}") + end end -end \ No newline at end of file +end diff --git a/app/models/annotation.rb b/app/models/annotation.rb new file mode 100644 index 0000000..8ea44dd --- /dev/null +++ b/app/models/annotation.rb @@ -0,0 +1,40 @@ +class Annotation < ActiveRecord::Base + enum type: [ :example_answer, :guidance] + ## + # Associations + belongs_to :org + belongs_to :question + + ## + # I liked type as the name for the enum so overriding inheritance column + self.inheritance_column = nil + + ## + # Possibly needed for active_admin + # -relies on protected_attributes gem as syntax depricated in rails 4.2 + attr_accessible :org_id, :question_id, :text, :type, + :org, :question, :as => [:default, :admin] + + + validates :question, :org, presence: {message: _("can't be blank")} + + ## + # returns the text from the annotation + # + # @return [String] the text from the annotation + def to_s + "#{text}" + end + + + ## + # deep copy the given annotation and all it's associations + # + # @params [Annotation] annotation to be deep copied + # @return [Annotation] the saved, copied annotation + def self.deep_copy(annotation) + annotation_copy = annotation.dup + annotation_copy.save! + return annotation_copy + end +end \ No newline at end of file diff --git a/app/models/answer.rb b/app/models/answer.rb index 35e0c2d..d46ad59 100644 --- a/app/models/answer.rb +++ b/app/models/answer.rb @@ -13,8 +13,8 @@ ## # Possibly needed for active_admin # -relies on protected_attributes gem as syntax depricated in rails 4.2 - attr_accessible :text, :plan_id, :question_id, :user_id, :question_option_ids, - :question, :user, :plan, :question_options, :notes, :note_ids, + attr_accessible :text, :plan_id, :lock_version, :question_id, :user_id, :question_option_ids, + :question, :user, :plan, :question_options, :notes, :note_ids, :id, :as => [:default, :admin] ## @@ -36,4 +36,24 @@ # # # Make sure the plan and question are associated with the same template! # validates :plan, :question, answer_for_correct_template: true + + # This method helps to decide if an answer option (:radiobuttons, :checkbox, etc ) in form views should be checked or not + # Returns true if the given option_id is present in question_options, otherwise returns false + def has_question_option(option_id) + self.question_option_ids.include?(option_id) + end + + # Returns true if the answer is valid and false otherwise. If the answer's question is option_based, it is checked if exist + # any question_option selected. For non option_based (e.g. textarea or textfield), it is checked the presence of text + def is_valid? + if self.question.present? + if self.question.question_format.option_based? + return !self.question_options.empty? + else # (e.g. textarea or textfield question formats) + return self.text.present? + end + else + return false + end + end end diff --git a/app/models/exported_plan.rb b/app/models/exported_plan.rb index 4045298..0bd9ef1 100644 --- a/app/models/exported_plan.rb +++ b/app/models/exported_plan.rb @@ -1,5 +1,6 @@ class ExportedPlan < ActiveRecord::Base include GlobalHelpers + include SettingsTemplateHelper # TODO: REMOVE AND HANDLE ATTRIBUTE SECURITY IN THE CONTROLLER! attr_accessible :plan_id, :user_id, :format, :user, :plan, :as => [:default, :admin] @@ -8,10 +9,15 @@ belongs_to :plan belongs_to :user - VALID_FORMATS = ['csv', 'html', 'json', 'pdf', 'text', 'xml', 'docx'] + VALID_FORMATS = ['csv', 'html', 'pdf', 'text', 'docx'] - validates :format, inclusion: { in: VALID_FORMATS, message: I18n.t('helpers.plan.export.not_valid_format') } - validates :plan, :format, presence: true + validates :format, inclusion: { + in: VALID_FORMATS, + message: -> (object, data) do + _('%{value} is not a valid format') % { :value => data[:value] } + end + } + validates :plan, :format, presence: {message: _("can't be blank")} # Store settings with the exported plan so it can be recreated later # if necessary (otherwise the settings associated with the plan at a @@ -50,6 +56,10 @@ self.plan.description end + def owner + self.plan.roles.to_a.select{ |role| role.creator? }.first.user + end + def funder org = self.plan.template.try(:org) org.name if org.present? && org.funder? @@ -69,91 +79,109 @@ end end -# TODO: This looks like it will always return an empty array as questions is undefined - # sections taken from fields settings def sections - # TODO: How do we know which phase to use here!? - sections = self.template.phases.first.sections - - return [] if questions.empty? - - section_ids = questions.pluck(:section_id).uniq - sections = sections.select {|section| section_ids.member?(section.id) } - - sections.sort_by(&:number) + self.phase_id ||= self.plan.template.phases.first.id + Section.where({phase_id: phase_id}).order(:number) end def questions_for_section(section_id) - questions.where(section_id: section_id) + Question.where(id: questions).where(section_id: section_id).order(:number) end def admin_details @admin_details ||= self.settings(:export).fields[:admin] end + # Retrieves the title field + def title + self.settings(:export).title + end + # Export formats def as_csv CSV.generate do |csv| - csv << ["Section","Question","Answer","Selected option(s)","Answered by","Answered at"] + csv << [_('Section'),_('Question'),_('Answer'),_('Selected option(s)'),_('Answered by'),_('Answered at')] self.sections.each do |section| - self.questions_for_section(section).each do |question| - answer = self.plan.answer(question.id) - options_string = answer.options.collect {|o| o.text}.join('; ') - - csv << [section.title, sanitize_text(question.text), sanitize_text(answer.text), options_string, answer.try(:user).try(:name), answer.created_at] + questions = self.questions_for_section(section) + if questions.present? + questions.each do |question| + answer = self.plan.answer(question.id) + q_format = question.question_format + if q_format.option_based? + options_string = answer.question_options.collect {|o| o.text}.join('; ') + else + options_string = '' + end + csv << [ + section.title, + sanitize_text(question.text), + question.option_comment_display ? sanitize_text(answer.text) : '', + options_string, + user.name, + answer.updated_at + ] + end end end end end def as_txt - output = "#{self.plan.project.title}\n\n#{self.plan.version.phase.title}\n" - output += "\nDetails:\n\n" - attrs = self.plan.settings(:export)[:value]['fields'][:admin].collect{|f| f.to_s} - attrs.each do |attr| - output += attr + ": " + self.send(attr) + "\n" + output = "#{self.plan.title}\n\n#{self.plan.template.title}\n" + output += "\n"+_('Details')+"\n\n" + + self.admin_details.each do |at| + value = self.send(at) + if value.present? + output += admin_field_t(at.to_s) + ": " + value + "\n" + else + output += admin_field_t(at.to_s) + ": " + _('-') + "\n" + end end self.sections.each do |section| - output += "\n#{section.title}\n" + questions = self.questions_for_section(section) + if questions.present? + output += "\n#{section.title}\n" + questions.each do |question| + qtext = sanitize_text( question.text.gsub(/
  • /, ' * ') ) + output += "\n* #{qtext}" + answer = self.plan.answer(question.id, false) - self.questions_for_section(section).each do |question| - qtext = sanitize_text( question.text.gsub(/
  • /, ' * ') ) - output += "\n* #{qtext}" - answer = self.plan.answer(question.id, false) - - if answer.nil? || answer.text.nil? then - output += I18n.t('helpers.plan.export.pdf.question_not_answered')+ "\n" - else - output += answer.options.collect {|o| o.text}.join("\n") - if question.option_comment_display == true then - output += "\n#{sanitize_text(answer.text)}\n" + if answer.nil? + output += _('Question not answered.')+ "\n" else - output += "\n" + q_format = question.question_format + if q_format.option_based? + output += answer.question_options.collect {|o| o.text}.join("\n") + if question.option_comment_display + output += "\n#{sanitize_text(answer.text)}\n" + end + else + output += "\n#{sanitize_text(answer.text)}\n" + end end end end end - output end private - + # Returns an Array of question_ids for the exported settings stored for a plan def questions - @questions ||= begin - question_settings = self.settings(:export).fields[:questions] - - return [] if question_settings.is_a?(Array) && question_settings.empty? - - questions = if question_settings.present? && question_settings != :all - Question.where(id: question_settings) + question_settings = self.settings(:export).fields[:questions] + @questions ||= if question_settings.present? + if question_settings == :all + Question.where(section_id: self.plan.sections.collect { |s| s.id }).pluck(:id) + elsif question_settings.is_a?(Array) + question_settings else - Question.where(section_id: self.plan.sections.collect {|s| s.id }) + [] end - - questions.order(:number) + else + [] end end diff --git a/app/models/guidance.rb b/app/models/guidance.rb index 3b15e2a..8ba321b 100644 --- a/app/models/guidance.rb +++ b/app/models/guidance.rb @@ -3,7 +3,7 @@ # This class keeps the information organisations enter to support users when answering questions. # It always belongs to a guidance group class and it can be linked directly to a question or through one or more themes # [+Created:+] 07/07/2014 -# [+Copyright:+] Digital Curation Centre and University of California Curation Center +# [+Copyright:+] Digital Curation Centre and California Digital Library @@ -13,12 +13,9 @@ ## # Associations belongs_to :guidance_group -# belongs_to :question has_and_belongs_to_many :themes, join_table: "themes_in_guidance" # depricated, but required for migration "single_group_for_guidance" - has_and_belongs_to_many :guidance_groups, join_table: "guidance_in_group" - - + #has_and_belongs_to_many :guidance_groups, join_table: "guidance_in_group" # EVALUATE CLASS AND INSTANCE METHODS BELOW @@ -28,7 +25,7 @@ - validates :text, presence: true + validates :text, presence: {message: _("can't be blank")} ## @@ -91,7 +88,7 @@ unless guidance.nil? unless guidance.guidance_group.nil? - # guidances are viewable if they are owned by any of the user's organisations + # guidances are viewable if they are owned by the user's org if guidance.guidance_group.org == user.org viewable = true end @@ -99,14 +96,14 @@ if Org.managing_orgs.include?(guidance.guidance_group.org) viewable = true end - + # guidance groups are viewable if they are owned by a funder if Org.funders.include?(guidance.guidance_group.org) viewable = true end end end - + return viewable end @@ -120,24 +117,17 @@ # @param user [User] a user object # @return [Array] a list of all "viewable" guidances to a user def self.all_viewable(user) - managing_groups = Org.managing_orgs.collect{|o| o.guidance_groups} + managing_groups = Org.includes(guidance_groups: :guidances).managing_orgs.collect{|o| o.guidance_groups} # find all groups owned by a Funder organisation - funder_groups = [] - funders = Org.funders - funders.each do |funder| - funder_groups += funder.guidance_groups - end + funder_groups = Org.includes(guidance_groups: :guidances).funders.collect{|org| org.guidance_groups} # find all groups owned by any of the user's organisations organisation_groups = user.org.guidance_groups - + # find all guidances belonging to any of the viewable groups - all_viewable_guidances = [] - all_viewable_groups = managing_groups + funder_groups + organisation_groups - all_viewable_groups.flatten.each do |group| - all_viewable_guidances += group.guidances - end + all_viewable_groups = (managing_groups + funder_groups + organisation_groups).flatten + all_viewable_guidances = all_viewable_groups.collect{|group| group.guidances} # pass the list of viewable guidances to the view - return all_viewable_guidances + return all_viewable_guidances.flatten end end diff --git a/app/models/guidance_group.rb b/app/models/guidance_group.rb index 71535c3..ee3e685 100644 --- a/app/models/guidance_group.rb +++ b/app/models/guidance_group.rb @@ -3,9 +3,11 @@ ## # Associations belongs_to :org - has_many :guidances + has_many :guidances, dependent: :destroy + has_and_belongs_to_many :plans, join_table: :plans_guidance_groups # depricated but needed for migration "single_group_for_guidance" # has_and_belongs_to_many :guidances, join_table: "guidance_in_group" + ## # Possibly needed for active_admin @@ -13,7 +15,7 @@ attr_accessible :org_id, :name, :optional_subset, :published, :org, :guidances, :as => [:default, :admin] - validates :name, :org, presence: true + validates :name, :org, presence: {message: _("can't be blank")} # EVALUATE CLASS AND INSTANCE METHODS BELOW @@ -70,22 +72,20 @@ # @param id [Integer] the integer id for a guidance group # @param user [User] a user object # @return [Boolean] true if the specified user can view the specified guidance group, false otherwise - def self.can_view?(user, id) - guidance_group = GuidanceGroup.find_by(id: id) + def self.can_view?(user, guidance_group) viewable = false - # groups are viewable if they are owned by any of the user's organisations if guidance_group.org == user.org viewable = true end # groups are viewable if they are owned by the managing curation center - Org.where( name: GlobalHelpers.constant("organisation_types.managing_organisation")).find_each do |managing_group| + Org.managing_orgs.each do |managing_group| if guidance_group.org.id == managing_group.id viewable = true end end # groups are viewable if they are owned by a funder - if guidance_group.org.org_type == 2 + if guidance_group.org.funder? viewable = true end @@ -103,22 +103,16 @@ # @return [Array] a list of all "viewable" guidance groups to a user def self.all_viewable(user) # first find all groups owned by the Managing Curation Center - managing_org_groups = [] - Org.where(name: GlobalHelpers.constant("organisation_types.managing_organisation")).find_each do |managing_org| - managing_org_groups = managing_org_groups + managing_org.guidance_groups - end + managing_org_groups = Org.includes(guidance_groups: [guidances: :themes]).managing_orgs.collect{|org| org.guidance_groups} # find all groups owned by a Funder organisation - funder_groups = [] - funders = Org.where(org_type: 2) - funders.each do |funder| - funder_groups = funder_groups + funder.guidance_groups - end + funder_groups = Org.includes(:guidance_groups).funders.collect{|org| org.guidance_groups} + organisation_groups = [user.org.guidance_groups] # pass this organisation guidance groups to the view with respond_with @all_viewable_groups all_viewable_groups = managing_org_groups + funder_groups + organisation_groups - all_viewable_groups = all_viewable_groups.flatten.uniq{|x| x.id} + all_viewable_groups = all_viewable_groups.flatten.uniq return all_viewable_groups end end diff --git a/app/models/identifier_scheme.rb b/app/models/identifier_scheme.rb index 45b8922..d07aafc 100644 --- a/app/models/identifier_scheme.rb +++ b/app/models/identifier_scheme.rb @@ -2,5 +2,5 @@ has_many :user_identifiers has_many :users, through: :user_identifiers - validates :name, uniqueness: true, presence: true + validates :name, uniqueness: {message: _("must be unique")}, presence: {message: _("can't be blank")} end \ No newline at end of file diff --git a/app/models/language.rb b/app/models/language.rb index 0bb5a35..2d02783 100644 --- a/app/models/language.rb +++ b/app/models/language.rb @@ -6,5 +6,9 @@ ## # Validations - validates :abbreviation, presence: true, uniqueness: true + # Cannot do FastGettext translations here because we constantize LANGUAGES in initializers/constants.rb + validates :abbreviation, presence: {message: "can't be blank"}, uniqueness: {message: "must be unique"} + + scope :sorted_by_abbreviation, -> { all.order(:abbreviation) } + scope :default, -> { where(default_language: true).first } end \ No newline at end of file diff --git a/app/models/note.rb b/app/models/note.rb index 74b3078..4341c2a 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -10,5 +10,5 @@ attr_accessible :text, :user_id, :answer_id, :archived, :archived_by, :answer, :user, :as => [:default, :admin] - validates :text, :answer, :user, presence: true + validates :text, :answer, :user, presence: {message: _("can't be blank")} end diff --git a/app/models/org.rb b/app/models/org.rb index 15dcd92..9abbe2e 100644 --- a/app/models/org.rb +++ b/app/models/org.rb @@ -4,13 +4,18 @@ extend Dragonfly::Model::Validations ## + # Sort order: Name ASC + default_scope { order(name: :asc) } + + + ## # Associations - belongs_to :organisation_type # depricated, but cannot be removed until migration run +# belongs_to :organisation_type # depricated, but cannot be removed until migration run belongs_to :language has_many :guidance_groups has_many :templates has_many :users - has_many :suggested_answers + has_many :annotations has_and_belongs_to_many :token_permission_types, join_table: "org_token_permissions", unique: true @@ -21,19 +26,20 @@ :logo_file_name, :name, :target_url, :organisation_type_id, :wayfless_entity, :parent_id, :sort_name, :token_permission_type_ids, :language_id, :contact_email, - :language, :org_type, :region, :token_permission_types + :language, :org_type, :region, :token_permission_types, + :guidance_group_ids, :is_other, :region_id, :logo_uid, :logo_name ## # Validators validates :contact_email, email: true, allow_nil: true - validates :name, presence: true, uniqueness: true + validates :name, presence: {message: _("can't be blank")}, uniqueness: {message: _("must be unique")} # allow validations for logo upload dragonfly_accessor :logo do after_assign :resize_image end - validates_property :height, of: :logo, in: (0..100) - validates_property :format, of: :logo, in: ['jpeg', 'png', 'gif','jpg','bmp'] - validates_size_of :logo, maximum: 500.kilobytes + validates_property :height, of: :logo, in: (0..100), message: _("height must be less than 100px") + validates_property :format, of: :logo, in: ['jpeg', 'png', 'gif','jpg','bmp'], message: _("must be one of the following formats: jpeg, jpg, png, gif, bmp") + validates_size_of :logo, maximum: 500.kilobytes, message: _("can't be larger than 500KB") ## # Define Bit Field values @@ -47,15 +53,24 @@ column: 'org_type' # Predefined queries for retrieving the managain organisation and funders - scope :managing_orgs, -> { where(name: GlobalHelpers.constant("organisation_types.managing_organisation")) } + scope :managing_orgs, -> { where(abbreviation: Rails.configuration.branding[:organisation][:abbreviation]) } scope :funders, -> { where(org_type: 2) } - scope :institutions, -> { where(org_type: 3) } + scope :institutions, -> { where(org_type: 1) } # EVALUATE CLASS AND INSTANCE METHODS BELOW # # What do they do? do they do it efficiently, and do we need them? + # Determines the locale set for the organisation + # @return String or nil + def get_locale + if !self.language.nil? + return self.language.abbreviation + else + return nil + end + end # TODO: Should these be hardcoded? Also, an Org can currently be multiple org_types at one time. # For example you can do: funder = true; project = true; school = true diff --git a/app/models/perm.rb b/app/models/perm.rb index 114c0f0..58aad3e 100644 --- a/app/models/perm.rb +++ b/app/models/perm.rb @@ -6,7 +6,27 @@ ## # Possibly needed for active_admin # -relies on protected_attributes gem as syntax depricated in rails 4.2 - attr_accessible :name, :as => [:default, :admin] + #attr_accessible :name, :as => [:default, :admin] + + validates :name, presence: {message: _("can't be blank")}, uniqueness: {message: _("must be unique")} + + ## + # Constant perms + #ADD_ORGS = Perm.where(name: 'add_organisations').first.freeze + #CHANGE_AFFILIATION = Perm.where(name: 'change_org_affiliation').first.freeze + #GRANT_PERMISSIONS = Perm.where(name: 'grant_permissions').first.freeze + #MODIFY_TEMPLATES = Perm.where(name: 'modify_templates').first.freeze + #MODIFY_GUIDANCE = Perm.where(name: 'modify_guidance').first.freeze + #USE_API = Perm.where(name: 'use_api').first.freeze + #CHANGE_ORG_DETAILS = Perm.where(name: 'change_org_details').first.freeze + #GRANT_API = Perm.where(name: 'grant_api_to_orgs').first.freeze - validates :name, presence: true, uniqueness: true + scope :add_orgs, -> {Perm.find_by(name: 'add_organisations')} + scope :change_affiliation, -> {Perm.find_by(name: 'change_org_affiliation')} + scope :grant_permissions, -> {Perm.find_by(name: 'grant_permissions')} + scope :modify_templates, -> {Perm.find_by(name: 'modify_templates')} + scope :modify_guidance, -> {Perm.find_by(name: 'modify_guidance')} + scope :use_api, -> {Perm.find_by(name: 'use_api')} + scope :change_org_details, -> {Perm.find_by(name: 'change_org_details')} + scope :grant_api, -> {Perm.find_by(name: 'grant_api_to_orgs')} end diff --git a/app/models/phase.rb b/app/models/phase.rb index 88429fd..5c2323f 100644 --- a/app/models/phase.rb +++ b/app/models/phase.rb @@ -4,12 +4,17 @@ # [+Created:+] 03/09/2014 # [+Copyright:+] Digital Curation Centre and University of California Curation Center class Phase < ActiveRecord::Base -# extend FriendlyId + ## + # Sort order: Number ASC + default_scope { order(number: :asc) } + + +# extend FriendlyId ## # Associations belongs_to :template - has_many :sections, dependent: :destroy + has_many :sections, -> { order(:number => :asc) }, dependent: :destroy has_many :questions, :through => :sections, dependent: :destroy ## @@ -23,13 +28,9 @@ #friendly_id :title, use: [:slugged, :history, :finders] - validates :title, :number, :template, presence: true + validates :title, :number, :template, presence: {message: _("can't be blank")} - - - - - + # EVALUATE CLASS AND INSTANCE METHODS BELOW # # What do they do? do they do it efficiently, and do we need them? @@ -104,4 +105,5 @@ end return phase_copy end + end diff --git a/app/models/plan.rb b/app/models/plan.rb index a32b171..8688f34 100644 --- a/app/models/plan.rb +++ b/app/models/plan.rb @@ -1,4 +1,7 @@ class Plan < ActiveRecord::Base + + before_validation :set_creation_defaults + ## # Associations belongs_to :template @@ -10,13 +13,14 @@ has_many :notes, through: :answers has_many :roles, dependent: :destroy has_many :users, through: :roles - has_many :plan_guidance_groups, dependent: :destroy - has_many :guidance_groups, through: :plan_guidance_groups + has_and_belongs_to_many :guidance_groups, join_table: :plans_guidance_groups accepts_nested_attributes_for :template has_many :exported_plans has_many :roles + + # COMMENTED OUT THE DIRECT CONNECTION HERE TO Users to prevent assignment of users without an access_level specified (currently defaults to creator) # has_many :users, through: :roles @@ -46,6 +50,10 @@ FONT_HEIGHT_CONVERSION_FACTOR = 0.35278 #convert font point size to mm FONT_WIDTH_HEIGHT_RATIO = 0.4 #Assume glyph width averages 2/5 the height + # Scope queries + # Note that in ActiveRecord::Enum the mappings are exposed through a class method with the pluralized attribute name (e.g visibilities rather than visibility) + scope :publicly_visible, -> { where(:visibility => visibilities[:publicly_visible]).order(:title => :asc) } + ## # Settings for the template has_settings :export, class_name: 'Settings::Template' do |s| @@ -79,6 +87,17 @@ + def base_template + base = nil + t = self.template + if t.customization_of.present? + base = Template.where("dmptemplate_id = ? and created_at < ?", t.customization_of, self.created_at).order(version: :desc).first + end + return base + end + + + ## # returns the most recent answer to the given question id # optionally can create an answer if none exists @@ -120,7 +139,8 @@ section.questions.each do |question| question.themes.each do |theme| theme.guidances.each do |guidance| - ggroups << guidance.guidance_group + ggroups << guidance.guidance_group if guidance.guidance_group.published + # only show published guidance groups end end end @@ -130,10 +150,34 @@ self.guidance_groups = ggroups.uniq end - - - ## + # returns all of the possible guidance groups for the plan (all options to + # be selected by the user to display) + # + # @return Array + def get_guidance_group_options + # find all the themes in this plan + # and get the guidance groups they belong to + ggroups = [] + Template.includes(phases: [sections: [questions: [themes: [guidances: [guidance_group: :org]]]]]).find(self.template_id).phases.each do |phase| + phase.sections.each do |section| + section.questions.each do |question| + question.themes.each do |theme| + theme.guidances.each do |guidance| + ggroups << guidance.guidance_group if guidance.guidance_group.published + # only show published guidance groups + end + end + end + end + end + return ggroups.uniq + end + + + + + ## # returns the guidances associated with the project's organisation, for a specified question # # @param question [Question] the question to find guidance for @@ -168,8 +212,7 @@ end # Get guidance by theme from any guidance groups currently selected - self.plan_guidance_groups.where(selected: true).each do |pgg| - group = pgg.guidance_group + self.guidance_groups.each do |group| group.guidances.each do |guidance| common_themes = guidance.themes.all & question.themes.all if common_themes.length > 0 @@ -181,6 +224,9 @@ return guidances end + + + ## # adds the given guidance to a hash indexed by a passed guidance group and theme # @@ -217,6 +263,7 @@ # @param user_id [Integer] the id for a user # @return [Boolean] true if user can edit the plan def editable_by?(user_id) + user_id = user_id.id if user_id.is_a?(User) role = roles.where(user_id: user_id).first return role.present? && role.editor? end @@ -229,6 +276,7 @@ # @param user_id [Integer] the id for a user # @return [Boolean] true if the user can read the plan def readable_by?(user_id) + user_id = user_id.id if user_id.is_a?(User) role = roles.where(user_id: user_id).first return role.present? end @@ -239,6 +287,7 @@ # @param user_id [Integer] the id for the user # @return [Boolean] true if the user can administer the plan def administerable_by?(user_id) + user_id = user_id.id if user_id.is_a?(User) role = roles.where(user_id: user_id).first return role.present? && role.administrator? end @@ -247,65 +296,140 @@ ## # defines and returns the status of the plan # status consists of a hash of the num_questions, num_answers, sections, questions, and spaced used. - # For each section, it contains theid's of each of the questions + # For each section, it contains the id's of each of the questions # for each question, it contains the answer_id, answer_created_by, answer_text, answer_options_id, aand answered_by # # @return [Status] - def status - status = { - "num_questions" => 0, - "num_answers" => 0, - "sections" => {}, - "questions" => {}, - "space_used" => 0 # percentage of available space in pdf used - } - space_used = height_of_text(self.title, 2, 2) + def status + status = { + "num_questions" => 0, + "num_answers" => 0, + "sections" => {}, + "questions" => {}, + "space_used" => 0 # percentage of available space in pdf used + } - sections.each do |s| - space_used += height_of_text(s.title, 1, 1) - section_questions = 0 - section_answers = 0 - status["sections"][s.id] = {} - status["sections"][s.id]["questions"] = Array.new - s.questions.each do |q| - status["num_questions"] += 1 - section_questions += 1 - status["sections"][s.id]["questions"] << q.id - status["questions"][q.id] = {} - answer = answer(q.id, false) + space_used = height_of_text(self.title, 2, 2) - space_used += height_of_text(q.text) unless q.text == s.title - space_used += height_of_text(answer.try(:text) || I18n.t('helpers.plan.export.pdf.question_not_answered')) + section_ids = sections.map {|s| s.id} - if ! answer.nil? then - status["questions"][q.id] = { - "answer_id" => answer.id, - "answer_created_at" => answer.created_at.to_i, - "answer_text" => answer.text, - "answer_option_ids" => answer.question_options.pluck(:id), - "answered_by" => answer.user.name - } - q_format = q.question_format - status["num_answers"] += 1 if (q_format.title == I18n.t("helpers.checkbox") || q_format.title == I18n.t("helpers.multi_select_box") || - q_format.title == I18n.t("helpers.radio_buttons") || q_format.title == I18n.t("helpers.dropdown")) || answer.text.present? - section_answers += 1 - #TODO: include selected options in space estimate - else - status["questions"][q.id] = { - "answer_id" => nil, - "answer_created_at" => nil, - "answer_text" => nil, - "answer_option_ids" => nil, - "answered_by" => nil - } - end - status["sections"][s.id]["num_questions"] = section_questions - status["sections"][s.id]["num_answers"] = section_answers + # we retrieve this is 2 joins: + # 1. sections and questions + # 2. questions and answers + # why? because Rails 4 doesn't have any sensible left outer join. + # when we change to RAILS 5 it is meant to have so this can be fixed then + + records = Section.joins(questions: :question_format) + .select('sections.id as sectionid, + sections.title as stitle, + questions.id as questionid, + questions.text as questiontext, + question_formats.title as qformat') + .where("sections.id in (?) ", section_ids) + .to_a + + # extract question ids to get answers + question_ids = records.map {|r| r.questionid}.uniq + status["num_questions"] = question_ids.count + + arecords = Question.joins(answers: :user) + .select('questions.id as questionid, + answers.id as answerid, + answers.plan_id as plan_id, + answers.text as answertext, + answers.updated_at as updated, + users.email as username') + .where("questions.id in (?) and answers.plan_id = ?",question_ids, self.id) + .to_a + + # we want answerids to extract options later + answer_ids = arecords.map {|r| r.answerid}.uniq + status["num_answers"] = answer_ids.count + + # create map from questionid to answer structure + qa_map = {} + arecords.each do |rec| + qa_map[rec.questionid] = { + plan: rec.plan_id, + id: rec.answerid, + text: rec.answertext, + updated: rec.updated, + user: rec.username + } + end + + + # build main status structure + records.each do |rec| + sid = rec.sectionid + stitle = rec.stitle + qid = rec.questionid + qtext = rec.questiontext + format = rec.qformat + + answer = nil + if qa_map.has_key?(qid) + answer = qa_map[qid] end + + aid = answer.nil? ? nil : answer[:id] + atext = answer.nil? ? nil : answer[:text] + updated = answer.nil? ? nil : answer[:updated] + uname = answer.nil? ? nil : answer[:user] + + space_used += height_of_text(stitle, 1, 1) + + shash = status["sections"] + if !shash.has_key?(sid) + shash[sid] = {} + shash[sid]["num_questions"] = 0 + shash[sid]["num_answers"] = 0 + shash[sid]["questions"] = Array.new + end + + shash[sid]["questions"] << qid + shash[sid]["num_questions"] += 1 + + space_used += height_of_text(qtext) unless qtext == stitle + if atext.present? + space_used += height_of_text(atext) + else + space_used += height_of_text(_('Question not answered.')) + end + + if answer.present? then + shash[sid]["num_answers"] += 1 + end + + status["questions"][qid] = { + "format" => format, + "answer_id" => aid, + "answer_updated_at" => updated.to_i, + "answer_text" => atext, + "answered_by" => uname + } + + end + + records = Answer.joins(:question_options).select('answers.id as answerid, question_options.id as optid').where(id: answer_ids).to_a + opt_hash = {} + records.each do |rec| + aid = rec.answerid + optid = rec.optid + if !opt_hash.has_key?(aid) + opt_hash[aid] = Array.new + end + opt_hash[aid] << optid + end + + status["questions"].each_key do |questionid| + answerid = status["questions"][questionid]["answer_id"] + status["questions"][questionid]["answer_option_ids"] = opt_hash[answerid] end status['space_used'] = estimate_space_used(space_used) + return status end @@ -509,6 +633,7 @@ # # @param user_id [Integer] the user to be given priveleges' id def assign_creator(user_id) + user_id = user_id.id if user_id.is_a?(User) add_user(user_id, true, true, true) end @@ -587,6 +712,7 @@ end end end +=end ## # returns the funder id for the plan @@ -598,7 +724,6 @@ end return self.template.org end -=end ## # returns the funder organisation for the project or nil if none is specified @@ -826,171 +951,61 @@ end =end + # Returns the number of answered questions from the entire plan + def num_answered_questions + n = 0 + self.sections.each do |s| + n+= s.num_answered_questions(self.id) + end + return n + end + # Returns a section given its id or nil if does not exist for the current plan + def get_section(section_id) + self.sections.find { |s| s.id == section_id } + end - ## + # Returns the number of questions for a plan. Note, this method becomes useful + # for when sections and their questions are eager loaded so that avoids SQL queries. + def num_questions + n = 0 + self.sections.each do |s| + n+= s.questions.size() + end + return n + end + # the following two methods are for eager loading. One gets used for the plan/show + # page and the oter for the plan/edit. The difference is just that one pulls in more than + # the other. + # TODO: revisit this and work out for sure that maintaining the difference is worthwhile. + # it may not be. Also make sure nether is doing more thanit needs to. # - # The following method is to help optimise data access. - # Even using includes or joins the data access gets performed lazily - # and the caching appears to be forgotten at times over view/partial boundaries - # To get round it we can pull everything out into a hash and use that - # which guarantees no further DB accesses. - # - # The serializable_hash method only pulls in one level but this includes - # attributes which are "through" other attributes. So we do a basic - # conversion to hash and then a "fixup" which knits the pieces together into - # the structure which we really want. - # - def to_hash - plan_data = self.serializable_hash( - include: [ :template, :phases, :sections, - :answers, :notes, :roles, :users, :questions, - :plan_guidance_groups, :guidance_groups] - ) + def self.eager_load(id) + Plan.includes( + [{template: [ + {phases: {sections: {questions: :answers}}}, + {customizations: :org} + ]}, + {plans_guidance_groups: {guidance_group: :guidances}} + ]).find(id) + end - question_hash = {} - - plan_data["questions"].each do |q| - question_hash[q["id"]] = q - end - - question_ids = question_hash.keys - - suggested_answers = SuggestedAnswer.where(question_id: question_ids).where.not(text: '') - suggested_answers.each do |sa| - question_hash[sa.question_id]["suggested_answer"] = sa.serializable_hash - end - - qf_hash = {} - QuestionFormat.all.each do |qf| - qf_hash[qf.id] = qf.serializable_hash - end - question_hash.values.each do |q| - q["question_format"] = qf_hash[q["question_format_id"]] - end - - gg_ids = plan_data["plan_guidance_groups"].select{|pgg| pgg["selected"]}.map{|pgg| pgg["guidance_group_id"]} - gg_hash = {} - - theme_guidance = {} - - ggs = GuidanceGroup.find(gg_ids).each do |gg| - gg_hash[gg.id] = gg.serializable_hash - end - - guidances = Guidance.joins(:themes).select('guidances.guidance_group_id, guidances.text, themes.title').where(guidance_group: gg_ids).to_a - guidances.each do |g| - title = g.title - if !theme_guidance.has_key?(title) - theme_guidance[title] = Array.new - end - theme_guidance[title] << { - "text" => g.text, - "org" => gg_hash[g.guidance_group_id]["name"] - } - end - - plan_data["questions"].each do |q| - qg = {} - if q.has_key?("themes") - q["themes"].each do |t| - title = t["title"] - qg[title] = theme_guidance[title] if theme_guidance.has_key?(title) - end - q["theme_guidance"] = qg - end - end - - fixup_hash(plan_data) - - return plan_data + def self.eager_load2(id) + Plan.includes( + [{template: [ + {phases: {sections: {questions: [{answers: :notes}, :annotations, :question_format, :themes]}}}, + {customizations: :org}, + :org + ]}, + {plans_guidance_groups: {guidance_group: {guidances: :themes}}}, + {questions: :themes} + ]).find(id) end private - # reconnect the various parts of the hash so that: - # plan = { - # template: - # phases: - # sections: - # questions: - # answers - # } - # - # becomes a nested structure like so - # - # plan = { template: { - # phases: [ { - # sections: [ { - # questions: [ { - # answers: [...] - # - def fixup_hash(plan) - # sort out guidance first so we can add it to the questions - # before rolling up - ghash = {} - plan["guidance_groups"].map{|g| ghash[g["id"]] = g} - plan["plan_guidance_groups"].each do |pgg| - pgg["guidance_group"] = ghash[ pgg["guidance_group_id"] ] - end - - rollup(plan, "notes", "answer_id", "answers") - rollup(plan, "answers", "question_id", "questions") - rollup(plan, "questions", "section_id", "sections", true) - rollup(plan, "sections", "phase_id", "phases", true) - - plan["template"]["phases"] = plan.delete("phases") - plan["template"]["phases"].sort! { |x,y| x["number"].to_i <=> y["number"].to_i } - - plan["template"]["org"] = Org.find(plan["template"]["org_id"]).serializable_hash() - - # when editing phases we want the number of questions answered - # so calculate that now - plan["template"]["phases"].each do |phase| - phase["sections"].each do |section| - nanswers = 0 - section["questions"].each do |question| - if question.has_key?("answers") && question["answers"].first["text"].present? - nanswers += 1 - end - end - section["nanswers"] = nanswers - end - end - - end - - - # find all object under src_plan_key - # merge them into the items under obj_plan_key using - # super_id = id - # so we have answers which each have a question_id - # rollup(plan, "answers", "quesiton_id", "questions") - # will put the answers into the right questions. - # sort determines whether the items being rolled up should be sorted by number field - def rollup(plan, src_plan_key, super_id, obj_plan_key, sort = false) - id_to_obj = Hash.new() - plan[src_plan_key].each do |o| - id = o[super_id] - if !id_to_obj.has_key?(id) - id_to_obj[id] = Array.new - end - id_to_obj[id] << o - end - - plan[obj_plan_key].each do |o| - id = o["id"] - if id_to_obj.has_key?(id) - if sort - id_to_obj[ id ].sort! { |x,y| x["number"].to_i <=> y["number"].to_i } - end - o[src_plan_key] = id_to_obj[ id ] - end - end - plan.delete(src_plan_key) - end ## # adds a user to the project @@ -1014,9 +1029,25 @@ role.user_id = user_id role.plan_id = id - role.creator= is_creator - role.editor= is_editor - role.administrator= is_administrator + # if you get assigned a role you can comment + role.commenter= true + + # the rest of the roles are inclusing so creator => administrator => editor + if is_creator + role.creator = true + role.administrator = true + role.editor = true + end + + if is_administrator + role.administrator = true + role.editor = true + end + + if is_editor + role.editor = true + end + role.save # This is necessary because we're creating the associated record but not assigning it @@ -1099,4 +1130,14 @@ (num_lines * font_height) + vertical_margin + leading end + # Initialize the title and dirty flags for new templates + # -------------------------------------------------------- + def set_creation_defaults + # Only run this before_validation because rails fires this before save/create + if self.id.nil? + self.title = "My plan (#{self.template.title})" if self.title.nil? && !self.template.nil? + self.visibility = 3 + end + end + end diff --git a/app/models/plan_guidance_group.rb b/app/models/plan_guidance_group.rb deleted file mode 100644 index 7b76499..0000000 --- a/app/models/plan_guidance_group.rb +++ /dev/null @@ -1,11 +0,0 @@ -# Used to link plans to guidance groups -# the links are created at plan creation stage -# and link to all possible GGs -# then the selected field keeps track of which ones the user has turned on /off -# -class PlanGuidanceGroup < ActiveRecord::Base - belongs_to :plan - belongs_to :guidance_group - - attr_accessible :selected -end diff --git a/app/models/question.rb b/app/models/question.rb index 61eddd1..0a3e947 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -1,10 +1,14 @@ class Question < ActiveRecord::Base ## + # Sort order: Number ASC + default_scope { order(number: :asc) } + + ## # Associations has_many :answers, :dependent => :destroy - has_many :question_options, :dependent => :destroy - has_many :suggested_answers, :dependent => :destroy + has_many :question_options, :dependent => :destroy, :inverse_of => :question # inverse_of needed for nester forms + has_many :annotations, :dependent => :destroy has_and_belongs_to_many :themes, join_table: "questions_themes" belongs_to :section belongs_to :question_format @@ -14,21 +18,20 @@ # TODO: evaluate if we need this accepts_nested_attributes_for :answers, :reject_if => lambda {|a| a[:text].blank? }, :allow_destroy => true accepts_nested_attributes_for :question_options, :reject_if => lambda {|a| a[:text].blank? }, :allow_destroy => true - accepts_nested_attributes_for :suggested_answers, :allow_destroy => true + accepts_nested_attributes_for :annotations, :allow_destroy => true accepts_nested_attributes_for :themes ## # Possibly needed for active_admin # -relies on protected_attributes gem as syntax depricated in rails 4.2 attr_accessible :default_value, :dependency_id, :dependency_text, :guidance,:number, - :suggested_answer, :text, :section_id, :question_format_id, - :question_options_attributes, :suggested_answers_attributes, + :annotation, :text, :section_id, :question_format_id, + :question_options_attributes, :annotations_attributes, :option_comment_display, :theme_ids, :section, :question_format, - :question_options, :suggested_answers, :answers, :themes, + :question_options, :annotations, :answers, :themes, :modifiable, :option_comment_display, :as => [:default, :admin] - validates :text, :section, :number, presence: true - + validates :text, :section, :number, presence: {message: _("can't be blank")} # EVALUATE CLASS AND INSTANCE METHODS BELOW # @@ -44,6 +47,16 @@ "#{text}" end + + def option_based? + format = self.question_format + return format.option_based + end + + def plan_answers(plan_id) + return self.answers.to_a.select{|ans| ans.plan_id == plan_id} + end + ## # deep copy the given question and all it's associations # @@ -57,10 +70,10 @@ question_option_copy.question_id = question_copy.id question_option_copy.save! end - question.suggested_answers.each do |suggested_answer| - suggested_answer_copy = SuggestedAnswer.deep_copy(suggested_answer) - suggested_answer_copy.question_id = question_copy.id - suggested_answer_copy.save! + question.annotations.each do |annotation| + annotation_copy = Annotation.deep_copy(annotation) + annotation_copy.question_id = question_copy.id + annotation_copy.save! end question.themes.each do |theme| question_copy.themes << theme @@ -82,7 +95,7 @@ group.guidances.each do |g| g.themes.each do |theme| if theme_ids.include? theme.id - guidances["#{group.name} " + I18n.t('admin.guidance_lowercase_on') + " #{theme.title}"] = g + guidances["#{group.name} " + _('guidance on') + " #{theme.title}"] = g end end end @@ -93,13 +106,24 @@ end ## - # get suggested answer belonging to the currents user for this question + # get example answer belonging to the currents user for this question # # @param org_id [Integer] the id for the organisation - # @return [String] the suggested_answer for this question for the specified organisation - def get_suggested_answer(org_id) - suggested_answer = suggested_answers.find_by(org_id: org_id) - return suggested_answer + # @return [String] the example answer for this question for the specified org + def get_example_answer(org_id) + example_answer = self.annotations.where(org_id: org_id).where(type: Annotation.types[:example_answer]).order(:created_at) + return example_answer.first end + ## + # get guidance belonging to the current user's org for this question(need org + # to distinguish customizations) + # + # @param org_id [Integer] the id for the organisation + # @return [String] the annotation guidance for this question for the specified org + def get_guidance_annotation(org_id) + guidance = self.annotations.where(org_id: org_id).where(type: Annotation.types[:guidance]) + return guidance.first + end + end diff --git a/app/models/question_format.rb b/app/models/question_format.rb index 7f1a900..b7d6afc 100644 --- a/app/models/question_format.rb +++ b/app/models/question_format.rb @@ -3,14 +3,23 @@ ## # Associations has_many :questions + + enum formattype: [ :textarea, :textfield, :radiobuttons, :checkbox, :dropdown, :multiselectbox, :date ] + attr_accessible :formattype - validates :title, presence: true, uniqueness: true + validates :title, presence: {message: _("can't be blank")}, uniqueness: {message: _("must be unique")} ## # Possibly needed for active_admin # -relies on protected_attributes gem as syntax depricated in rails 4.2 attr_accessible :title, :description, :option_based, :questions, :as => [:default, :admin] + # Retrieves the id for a given formattype passed + scope :id_for, -> (formattype) { where(formattype: formattype).pluck(:id).first } + + ## + # Define Bit Field Values so we can test a format without doing string comps + # Column type # EVALUATE CLASS AND INSTANCE METHODS BELOW # @@ -25,4 +34,4 @@ "#{title}" end -end \ No newline at end of file +end diff --git a/app/models/question_option.rb b/app/models/question_option.rb index 11552b0..b0fec82 100644 --- a/app/models/question_option.rb +++ b/app/models/question_option.rb @@ -10,8 +10,9 @@ attr_accessible :text, :question_id, :is_default, :number, :question, :as => [:default, :admin] - validates :text, :question, :number, presence: true + validates :text, :question, :number, presence: {message: _("can't be blank")} + scope :by_number, -> { order(:number) } ## # deep copy the given question_option and all it's associations # diff --git a/app/models/region.rb b/app/models/region.rb index 2c57e79..a7e366a 100644 --- a/app/models/region.rb +++ b/app/models/region.rb @@ -3,6 +3,6 @@ belongs_to :super_region, class_name: 'Region' - validates :name, presence: true, uniqueness: true - validates :abbreviation, uniqueness: true, allow_nil: true + validates :name, presence: {message: _("can't be blank")}, uniqueness: {message: _("must be unique")} + validates :abbreviation, uniqueness: {message: _("must be unique")}, allow_nil: true end \ No newline at end of file diff --git a/app/models/role.rb b/app/models/role.rb index cf49c87..a51177d 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -1,64 +1,59 @@ class Role < ActiveRecord::Base include FlagShihTzu - before_validation :check_access_level - ## - # Associations + # Associationsrequire "role" + belongs_to :user belongs_to :plan ## # Define Bit Field Values # Column access - has_flags 1 => :creator, - 2 => :administrator, - 3 => :editor, + has_flags 1 => :creator, # 1 + 2 => :administrator, # 2 + 3 => :editor, # 4 + 4 => :commenter, # 8 column: 'access' - validates :user, :plan, :access, presence: true - validates :access, numericality: {greater_than: 0} + validates :user, :plan, :access, presence: {message: _("can't be blank")} + validates :access, numericality: {greater_than: 0, message: _("can't be less than zero")} ## # return the access level for the current project group # 3 if the user is an administrator # 2 if the user is an editor # 1 if the user can only read + # used to facilliatte formtastic # # @return [Integer] def access_level - if self.administrator? then + if self.administrator? return 3 - elsif self.editor? then + elsif self.editor? return 2 - else + elsif self.commenter? return 1 end end - ## - # define a new access level for the current project group - # if >=3, the user is a project administrator - # if >=2, the user is an editor - # - # @param new_access_level [Integer] the access level to give the user - def access_level=(new_access_level) - new_access_level = new_access_level.to_i - if new_access_level >= 3 then - self.administrator = true - else - self.administrator = false - end - if new_access_level >= 2 then - self.editor = true - else - self.editor = false - end - self.creator = true unless self.administrator? || self.editor? - end - - # Ensures that the access attribute is set (will default to creator - see logic in access_level=) - def check_access_level - self.access_level = self.access_level - end end + +# ----------------------------------------------------- +# Bitwise key +# ----------------------------------------------------- +# 01 - creator +# 02 - administrator +# 03 - creator + administrator +# 04 - editor +# 05 - creator + editor +# 06 - administraor + editor +# 07 - creator + editor + administrator +# 08 - commenter +# 09 - creator + commenter +# 10 - administrator + commenter +# 11 - creator + administrator + commenter +# 12 - editor + commenter +# 13 - creator + editor + commenter +# 14 - administrator + editor + commenter +# 15 - creator + administrator + editor + commenter \ No newline at end of file diff --git a/app/models/section.rb b/app/models/section.rb index 87e98b6..4d4562b 100644 --- a/app/models/section.rb +++ b/app/models/section.rb @@ -1,5 +1,4 @@ class Section < ActiveRecord::Base - ## # Associations belongs_to :phase @@ -14,7 +13,7 @@ :questions_attributes, :organisation, :phase, :modifiable, :as => [:default, :admin] - validates :phase, :title, :number, presence: true + validates :phase, :title, :number, presence: {message: _("can't be blank")} ## # return the title of the section @@ -24,6 +23,15 @@ "#{title}" end + # Returns the number of answered questions for a given plan id + def num_answered_questions(plan_id) + n = 0 + self.questions.each do |question| + n += question.plan_answers(plan_id).select{|answer| answer.is_valid?}.count + end + return n + end + ## # deep copy of the given section and all it's associations # @@ -39,5 +47,4 @@ end return section_copy end - end diff --git a/app/models/settings/plan_list.rb b/app/models/settings/plan_list.rb deleted file mode 100644 index 26f6ed5..0000000 --- a/app/models/settings/plan_list.rb +++ /dev/null @@ -1,21 +0,0 @@ -module Settings - class PlanList < RailsSettings::SettingObject - - #attr_accessible :var, :target, :target_type, :target_id - - # TODO: can these be taken from somewhere else rather than hard-coded here? - DEFAULT_COLUMNS = ['name', 'owner', 'shared', 'last_edited'] - ALL_COLUMNS = DEFAULT_COLUMNS + ['template_owner', 'identifier', 'grant_number', 'visibility', - 'principal_investigator', 'data_contact', 'description'] - - validate do - cols = value["columns"] - - if cols.present? # columns can be empty, in which case they revert to defaults - errors.add(:columns, I18n.t("helpers.settings.projects.errors.no_name")) unless cols.member?("name") - errors.add(:columns, I18n.t("helpers.settings.projects.errors.duplicate")) unless cols.keys.uniq == cols.keys - errors.add(:columns, I18n.t("helpers.settings.projects.errors.unknown")) unless (cols.keys.uniq & ALL_COLUMNS) == cols.keys.uniq - end - end - end -end diff --git a/app/models/settings/template.rb b/app/models/settings/template.rb index 2956eac..59ac3de 100644 --- a/app/models/settings/template.rb +++ b/app/models/settings/template.rb @@ -59,13 +59,27 @@ end errs.map do |key| - errors.add(:formatting, I18n.t("helpers.settings.plans.errors.#{key}")) + if key == :missing_key + errors.add(:formatting, _('A required setting has not been provided')) + elsif key == :invalid_margin + errors.add(:formatting, _('Margin value is invalid')) + elsif key == :negative_margin + errors.add(:formatting, _('Margin cannot be negative')) + elsif key == :unknown_margin + errors.add(:formatting, _("Unknown margin. Can only be 'top', 'bottom', 'left' or 'right'")) + elsif key == :invalid_font_size + errors.add(:formatting, _('Invalid font size')) + elsif key == :invalid_font_face + errors.add(:formatting, _('Invalid font face')) + elsif key == :unknown_key + errors.add(:formatting, _('Unknown formatting setting')) + end end end if max_pages.present? && (!max_pages.is_a?(Integer) || max_pages <= 0) - errors.add(:max_pages, I18n.t('helpers.settings.plans.errors.invalid_max_pages')) + errors.add(:max_pages, _('Invalid maximum pages')) end end diff --git a/app/models/suggested_answer.rb b/app/models/suggested_answer.rb deleted file mode 100644 index 91ce3aa..0000000 --- a/app/models/suggested_answer.rb +++ /dev/null @@ -1,42 +0,0 @@ -class SuggestedAnswer < ActiveRecord::Base - - ## - # Associations - belongs_to :org - belongs_to :question - - ## - # Possibly needed for active_admin - # -relies on protected_attributes gem as syntax depricated in rails 4.2 - attr_accessible :org_id, :question_id, :text, :is_example, - :org, :question, :as => [:default, :admin] - - - validates :question, :org, presence: true - - # EVALUATE CLASS AND INSTANCE METHODS BELOW - # - # What do they do? do they do it efficiently, and do we need them? - - - - ## - # returns the text from the suggested_answer - # - # @return [String] the text from the suggested_answer - def to_s - "#{text}" - end - - - ## - # deep copy the given question_option and all it's associations - # - # @params [QuestionOption] question_option to be deep copied - # @return [QuestionOption] the saved, copied question_option - def self.deep_copy(suggested_answer) - suggested_answer_copy = suggested_answer.dup - suggested_answer_copy.save! - return suggested_answer_copy - end -end \ No newline at end of file diff --git a/app/models/template.rb b/app/models/template.rb index 9c59637..b72d216 100644 --- a/app/models/template.rb +++ b/app/models/template.rb @@ -1,6 +1,8 @@ class Template < ActiveRecord::Base include GlobalHelpers + before_validation :set_creation_defaults + scope :valid, -> {where(migrated: false)} ## # Associations belongs_to :org @@ -15,21 +17,43 @@ ## # Possibly needed for active_admin # -relies on protected_attributes gem as syntax depricated in rails 4.2 - attr_accessible :id, :org_id, :description, :published, :title, :locale, - :is_default, :guidance_group_ids, :org, :plans, :phases, - :version, :visibility, :published, :as => [:default, :admin] + attr_accessible :id, :org_id, :description, :published, :title, :locale, :customization_of, + :is_default, :guidance_group_ids, :org, :plans, :phases, :dmptemplate_id, + :migrated, :version, :visibility, :published, :as => [:default, :admin] # defines the export setting for a template object has_settings :export, class_name: 'Settings::Template' do |s| s.key :export, defaults: Settings::Template::DEFAULT_SETTINGS end - validates :org, :title, :version, presence: true + validates :org, :title, :version, presence: {message: _("can't be blank")} - # EVALUATE CLASS AND INSTANCE METHODS BELOW + # Retrieves the list of all dmptemplate_ids (template versioning families) for the specified Org + def self.dmptemplate_ids + Template.all.valid.distinct.pluck(:dmptemplate_id) + end + + # Retrieves the most recent version of the template for the specified Org and dmptemplate_id + def self.current(dmptemplate_id) + Template.where(dmptemplate_id: dmptemplate_id).order(version: :desc).valid.first + end + + # Retrieves the current published version of the template for the specified Org and dmptemplate_id + def self.live(dmptemplate_id) + Template.where(dmptemplate_id: dmptemplate_id, published: true).valid.first + end + + ## + # Retrieves the most current customization of the template for the + # specified org and dmptemplate_id + # returns nil if no customizations found # - # What do they do? do they do it efficiently, and do we need them? - + # @params [integer] dmptemplate_id of the original template + # @params [integer] org_id for the customizing organisation + # @return [nil, Template] the customized template or nil + def self.org_customizations(dmptemplate_id, org_id) + Template.where(customization_of: dmptemplate_id, org_id: org_id).order(version: :desc).valid.first + end ## # deep copy the given template and all of it's associations @@ -47,96 +71,54 @@ return template_copy end - ## - # takes a type or organisation and returns all published templates from - # organisations of that type - # - # @param ot [String] name of an organisation type e.g. founder - # @return [Array] list of published dmptemplates -=begin - def self.templates_org_type(ot) - # DISCUSS - This function other than the check for the template being published - # is a superclass for the below funders_templates - new_org_obejcts = OrganisationType.find_by( name: ot ).organisations - org_templates = Array.new - new_org_obejcts.each do |neworg| - org_templates += neworg.dmptemplates.where("published = ?", true) + # EVALUATE CLASS AND INSTANCE METHODS BELOW + # + # What do they do? do they do it efficiently, and do we need them? + + + ## + # convert the given template to a hash and return with all it's associations + # to use, please pre-fetch org, phases, section, questions, annotations, + # question_options, question_formats, + # TODO: Themes & guidance? + # + # @return [hash] hash of template, phases, sections, questions, question_options, annotations + def to_hash + hash = {} + hash[:template] = {} + hash[:template][:data] = self + hash[:template][:org] = self.org + phases = {} + hash[:template][:phases] = phases + self.phases.each do |phase| + phases[phase.number] = {} + phases[phase.number][:data] = phase + phases[phase.number][:sections] = {} + phase.sections.each do |section| + phases[phase.number][:sections][section.number] = {} + phases[phase.number][:sections][section.number][:data] = section + phases[phase.number][:sections][section.number][:questions] = {} + section.questions.each do |question| + phases[phase.number][:sections][section.number][:questions][question.number] = {} + phases[phase.number][:sections][section.number][:questions][question.number][:data] = question + phases[phase.number][:sections][section.number][:questions][question.number][:annotations] = {} + question.annotations.each do |annotation| + phases[phase.number][:sections][section.number][:questions][question.number][:annotations][annotation.id] = {} + phases[phase.number][:sections][section.number][:questions][question.number][:annotations][annotation.id][:data] = annotation + end + phases[phase.number][:sections][section.number][:questions][question.number][:question_options] = {} + question.question_options.each do |question_option| + phases[phase.number][:sections][section.number][:questions][question.number][:question_options][:data] = question_option + phases[phase.number][:sections][section.number][:questions][question.number][:question_format] = question.question_format + end + end + end end - - return org_templates + return hash end - ## - # returns all templates from all organisations of the Organisation_Type funder - # - # @return [Array] all templates from funder organisations - def self.funders_templates - funder_orgs = Org.includes(:templates).funder - org_templates = Array.new - - funder_orgs.each do |neworg| - org_templates += neworg.templates - end - - return org_templates - end - - ## - # returns all institutional templates bellowing to the given organisation - # - # @param org_id [integer] the integer id for an organisation - # @return [Array] all templates from a user's organisation - def self.own_institutional_templates(org_id) - # DISCUSS - Why is this done by scanning organisation_id's from the templates - # yet all other calls are done by finding an organisation, and using the - # has_many relationship to find the dmptemplates? - # - A possible answer is that there may be deleted organisations which we are - # serching for templates for. - # - A standardised behavior on querries, wether through active reccord or the - # where, should maybe be thought of/decided upon - new_templates = self.where("org_id = ?", org_id) - return new_templates - end - - ## - # returns an array with all funders and of the given organisations's - # institutional templates - # - # @param org_id [integer] the integer id for an organisation - # @return [Array] all templates from the template's organisation - # or from a funder organisation - def self.funders_and_own_templates(org_id) - funders_templates = self.funders_templates - - #verify if org type is not a funder - current_org = Org.find(org_id) - if !current_org.funder? then - own_institutional_templates = self.own_institutional_templates(org_id) - else - own_institutional_templates = [] - end - - templates_list = Array.new - templates_list += own_institutional_templates - templates_list += funders_templates - templates_list = templates_list.sort_by { |f| f['title'].downcase } - - return templates_list - end - - ## - # Returns the string name of the organisation type of the organisation who - # owns this dmptemplate - # - # @return [string] the string name of an organisation type - def org_type - org_type = org.organisation_type - return org_type - end -=end - -# TODO: Why are we passing in an org and template here? +# TODO: Why are we passing in an org and template here? ## # Verify if a template has customisation by given organisation # @@ -149,33 +131,29 @@ modifiable = modifiable && phase.modifiable end return !modifiable - # if temp.org_id != org_id then - # temp.phases.each do |phase| - # phase.versions.each do |version| - # version.sections.each do |section| - # return true if section.organisation_id == org_id - # end - # end - # return false - # end - # else - # return false - # end end -=begin - ## - # verify if there are any publish version for the template - # - # @return [Boolean] true if there is a published version for the template - def has_published_versions? - phases.each do |phase| - return true if !phase.latest_published_version.nil? + # -------------------------------------------------------- + private + # Initialize the published and dirty flags for new templates + def set_creation_defaults + # Only run this before_validation because rails fires this before save/create + if self.id.nil? + self.published = false + self.migrated = false + self.dirty = false + self.visibility = 1 + self.is_default = false + self.version = 0 if self.version.nil? + + # Generate a unique identifier for the dmptemplate_id if necessary + if self.dmptemplate_id.nil? + self.dmptemplate_id = loop do + random = rand 2147483647 + break random unless Template.exists?(dmptemplate_id: random) + end + end end - return false end -=end - - # OLD CODE STARTS HERE end diff --git a/app/models/theme.rb b/app/models/theme.rb index 315dfe8..bd787f6 100644 --- a/app/models/theme.rb +++ b/app/models/theme.rb @@ -13,7 +13,7 @@ attr_accessible :description, :title, :locale , :as => [:default, :admin] - validates :title, presence: true + validates :title, presence: {message: _("can't be blank")} # EVALUATE CLASS AND INSTANCE METHODS BELOW # diff --git a/app/models/token_permission_type.rb b/app/models/token_permission_type.rb index 71f8186..5770e6c 100644 --- a/app/models/token_permission_type.rb +++ b/app/models/token_permission_type.rb @@ -12,13 +12,14 @@ ## # Validators - validates :token_type, presence: true, uniqueness: true + validates :token_type, presence: {message: _("can't be blank")}, uniqueness: {message: _("must be unique")} - - # EVALUATE CLASS AND INSTANCE METHODS BELOW - # - # What do they do? do they do it efficiently, and do we need them? - + ## + # Constant Token Permission Types + GUIDANCES = TokenPermissionType.where(token_type: 'guidances').first.freeze + PLANS = TokenPermissionType.where(token_type: 'plans').first.freeze + TEMPLATES = TokenPermissionType.where(token_type: 'templates').first.freeze + STATISTICS = TokenPermissionType.where(token_type: 'statistics').first.freeze ## diff --git a/app/models/user.rb b/app/models/user.rb index 4cf42a2..f900030 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -7,7 +7,7 @@ # :token_authenticatable, :confirmable, # :lockable, :timeoutable and :omniauthable devise :invitable, :database_authenticatable, :registerable, :recoverable, - :rememberable, :trackable, :validatable, :confirmable, :omniauthable, + :rememberable, :trackable, :validatable, :omniauthable, :omniauth_providers => [:shibboleth, :orcid] ## @@ -40,25 +40,20 @@ ## # Possibly needed for active_admin # -relies on protected_attributes gem as syntax depricated in rails 4.2 - accepts_nested_attributes_for :roles - attr_accessible :password_confirmation, :encrypted_password, :remember_me, - :id, :email, :firstname, :last_login,:login_count, :orcid_id, - :password, :shibboleth_id, :user_status_id, :surname, - :user_type_id, :org_id, :skip_invitation, :other_organisation, - :accept_terms, :role_ids, :dmponline3, :api_token, - :organisation, :language, :language_id, :org, :perms, - :confirmed_at, :org_id + #accepts_nested_attributes_for :roles + #attr_accessible :password_confirmation, :encrypted_password, :remember_me, + # :id, :email, :firstname, :last_login,:login_count, :orcid_id, + # :password, :shibboleth_id, :user_status_id, :surname, + # :user_type_id, :org_id, :skip_invitation, :other_organisation, + # :accept_terms, :role_ids, :dmponline3, :api_token, + # :organisation, :language, :language_id, :org, :perms, + # :confirmed_at, :org_id - validates :email, email: true, allow_nil: true, uniqueness: true + validates :email, email: true, allow_nil: true, uniqueness: {message: _("must be unique")} ## - # Settings - # FIXME: The duplication in the block is to set defaults. It might be better if - # they could be set in Settings::PlanList itself, if possible. - has_settings :plan_list, class_name: 'Settings::PlanList' do |s| - s.key :plan_list, defaults: { columns: Settings::PlanList::DEFAULT_COLUMNS } - end - + # Scopes + default_scope { includes(:org, :perms) } @@ -66,8 +61,17 @@ # # What do they do? do they do it efficiently, and do we need them? - - + # Determines the locale set for the user or the organisation he/she belongs + # @return String or nil + def get_locale + if !self.language.nil? + return self.language.abbreviation + elsif !self.org.nil? + return self.org.get_locale + else + return nil + end + end ## @@ -103,14 +107,13 @@ # # @param new_organisation_id [Integer] the id for an organisation # @return [String] the empty string as a causality of setting api_token -=begin - def organisation_id=(new_organisation_id) - unless self.can_change_org? || new_organisation_id.nil? || self.organisation.nil? + def org_id=(new_org_id) + unless self.can_change_org? || new_org_id.nil? || self.org.nil? || (new_org_id.to_s == self.org.id.to_s) # rip all permissions from the user self.perms.delete_all end # set the user's new organisation - super(new_organisation_id) + super(new_org_id) self.save! # rip api permissions from the user self.remove_token! @@ -120,10 +123,9 @@ # sets a new organisation for the user # # @param new_organisation [Organisation] the new organisation for the user - def organisation=(new_organisation) - organisation_id = new_organisation.id unless new_organisation.nil? + def organisation=(new_org) + org_id = new_org.id unless new_org.nil? end -=end ## # checks if the user is a super admin @@ -151,7 +153,7 @@ # # @return [Boolean] true if the user can add new organisations def can_add_orgs? - perms.include? Perm.find_by(name: constant("roles.add_organisations")) + perms.include? Perm.add_orgs end ## @@ -159,7 +161,7 @@ # # @return [Boolean] true if the user can change their organisation affiliations def can_change_org? - perms.include? Perm.find_by(name: constant("roles.change_org_affiliation")) + perms.include? Perm.change_affiliation end ## @@ -167,7 +169,7 @@ # # @return [Boolean] true if the user can grant their permissions to others def can_grant_permissions? - perms.include? Perm.find_by(name: constant("roles.grant_permissions")) + perms.include? Perm.grant_permissions end ## @@ -175,7 +177,7 @@ # # @return [Boolean] true if the user can modify organisation templates def can_modify_templates? - perms.include? Perm.find_by(name: constant("roles.modify_templates")) + self.perms.include? Perm.modify_templates end ## @@ -183,7 +185,7 @@ # # @return [Boolean] true if the user can modify organistion guidance def can_modify_guidance? - perms.include? Perm.find_by(name: constant("roles.modify_guidance")) + perms.include? Perm.modify_guidance end ## @@ -191,7 +193,7 @@ # # @return [Boolean] true if the user can use the api def can_use_api? - perms.include? Perm.find_by(name: constant("roles.use_api")) + perms.include? Perm.use_api end ## @@ -199,7 +201,7 @@ # # @return [Boolean] true if the user can modify the org's details def can_modify_org_details? - perms.include? Perm.find_by(name: constant("roles.change_org_details")) + perms.include? Perm.change_org_details end @@ -208,7 +210,7 @@ # # @return [Boolean] true if the user can grant api permissions to organisations def can_grant_api_to_orgs? - perms.include? Perm.find_by(name: constant('roles.grant_api_to_orgs')) + perms.include? Perm.grant_api end ## @@ -261,6 +263,14 @@ end end + ## + # Override devise_invitable email title + # -------------------------------------------------------------- + def deliver_invitation(options = {}) + super(options.merge(subject: _('A Data Management Plan in %{application_name} has been shared with you') % {application_name: Rails.configuration.branding[:application][:name]})) + end + + # TODO: Remove this, its never called. # this generates a reset password link for a given user # which can then be sent to them with the appropriate host diff --git a/app/models/user_identifier.rb b/app/models/user_identifier.rb index 6623765..840e394 100644 --- a/app/models/user_identifier.rb +++ b/app/models/user_identifier.rb @@ -5,5 +5,5 @@ # Should only be able to have one identifier per scheme! validates_uniqueness_of :identifier_scheme, scope: :user - validates :identifier, :user, :identifier_scheme, presence: true + validates :identifier, :user, :identifier_scheme, presence: {message: _("can't be blank")} end \ No newline at end of file diff --git a/app/policies/annotation_policy.rb b/app/policies/annotation_policy.rb new file mode 100644 index 0000000..a426546 --- /dev/null +++ b/app/policies/annotation_policy.rb @@ -0,0 +1,29 @@ +class AnnotationPolicy < ApplicationPolicy + attr_reader :user, :annotation + + def initialize(user, annotation) + raise Pundit::NotAuthorizedError, "must be logged in" unless user + @user = user + @annotation = annotation + end + + ## + # Users can modify annotations if: + # - They can modify templates + # - The template which they are modifying belongs to their orggi + ## + + def admin_create? + # here we pass through a question instead of an annotation object + user.can_modify_templates? && (annotation.section.phase.template.org_id == user.org_id) + end + + def admin_update? + user.can_modify_templates? && (annotation.question.section.phase.template.org_id == user.org_id) && annotation.org_id == user.org_id + end + + def admin_destroy? + user.can_modify_templates? && (annotation.question.section.phase.template.org_id == user.org_id) + end + +end \ No newline at end of file diff --git a/app/policies/answer_policy.rb b/app/policies/answer_policy.rb index 805efac..1e9502c 100644 --- a/app/policies/answer_policy.rb +++ b/app/policies/answer_policy.rb @@ -8,9 +8,10 @@ @answer = answer end - def create? - # is the plan editable by the user, and is the user_id that of the user - @answer.plan.editable_by(@user.id) && (@answer.user_id == @user.id) + def update? + # TODO: Remove the owner check after the Roles have been updated + # is the plan editable by the user or the user is the owner of the plan + @answer.plan.editable_by?(@user.id) || @user == @answer.plan.owner end end \ No newline at end of file diff --git a/app/policies/api/v0/guidance_group_policy.rb b/app/policies/api/v0/guidance_group_policy.rb new file mode 100644 index 0000000..1ea52f4 --- /dev/null +++ b/app/policies/api/v0/guidance_group_policy.rb @@ -0,0 +1,29 @@ +module Api + module V0 + class GuidanceGroupPolicy < ApplicationPolicy + attr_reader :user, :guidance_group + + def initialize(user, guidance_group) + raise Pundit::NotAuthorizedError, _("must be logged in") unless user + unless user.org.token_permission_types.include? TokenPermissionType::GUIDANCES + raise Pundit::NotAuthorizedError, _("must have access to guidances api") + end + @user = user + @guidance_group = guidance_group + end + + ## + # is the plan editable by the user + def show? + GuidanceGroup.can_view?(@user, @guidance_group) + end + + ## + # always allowed as index chooses which guidances to display + def index? + true + end + + end + end +end \ No newline at end of file diff --git a/app/policies/api/v0/guidance_policy.rb b/app/policies/api/v0/guidance_policy.rb new file mode 100644 index 0000000..fd17c4e --- /dev/null +++ b/app/policies/api/v0/guidance_policy.rb @@ -0,0 +1,29 @@ +module Api + module V0 + class GuidancePolicy < ApplicationPolicy + attr_reader :user + attr_reader :guidance + + def initialize(user, guidance) + raise Pundit::NotAuthorizedError, _("must be logged in") unless user + unless user.org.token_permission_types.include? TokenPermissionType::GUIDANCES + raise Pundit::NotAuthorizedError, _("must have access to guidances api") + end + @user = user + @guidance = guidance + end + + ## + # is the plan editable by the user + def show? + Guidance.can_view(@user, @guidance.id) + end + + ## + # always allowed as index chooses which guidances to display + def index? + true + end + end + end +end \ No newline at end of file diff --git a/app/policies/api/v0/plans_policy.rb b/app/policies/api/v0/plans_policy.rb new file mode 100644 index 0000000..6d0ab77 --- /dev/null +++ b/app/policies/api/v0/plans_policy.rb @@ -0,0 +1,23 @@ +module Api + module V0 + class PlansPolicy < ApplicationPolicy + attr_reader :user + attr_reader :template + + def initialize(user, template) + raise Pundit::NotAuthorizedError, _("must be logged in") unless user + unless user.org.token_permission_types.include? TokenPermissionType::PLANS + raise Pundit::NotAuthorizedError, _("must have access to plans api") + end + @user = user + @template = template + end + + ## + # users can create a plan if their template exists + def create? + @template.present? + end + end + end +end \ No newline at end of file diff --git a/app/policies/api/v0/statistics_policy.rb b/app/policies/api/v0/statistics_policy.rb new file mode 100644 index 0000000..155a3da --- /dev/null +++ b/app/policies/api/v0/statistics_policy.rb @@ -0,0 +1,41 @@ +module Api + module V0 + class StatisticsPolicy < ApplicationPolicy + attr_reader :user + + def initialize(user, statistic) + raise Pundit::NotAuthorizedError, _("must be logged in") unless user + unless user.org.token_permission_types.include? TokenPermissionType::STATISTICS + raise Pundit::NotAuthorizedError, _("must have access to guidances api") + end + @user = user + @statistic = statistic + end + + ## + # always allowed to see how many users joined your org within a date range + def users_joined? + true + end + + ## + # need to check if your org owns this template + def using_template? + @statistic.org_id == @user.org_id + end + + ## + # always allowed to get plans by template + def plans_by_template? + true + end + + ## + # always allowed to get plans + def plans? + true + end + + end + end +end \ No newline at end of file diff --git a/app/policies/api/v0/template_policy.rb b/app/policies/api/v0/template_policy.rb new file mode 100644 index 0000000..7ec770b --- /dev/null +++ b/app/policies/api/v0/template_policy.rb @@ -0,0 +1,23 @@ +module Api + module V0 + class TemplatePolicy < ApplicationPolicy + attr_reader :user, :template + + def initialize(user, template) + raise Pundit::NotAuthorizedError, _("must be logged in") unless user + unless user.org.token_permission_types.include? TokenPermissionType::TEMPLATES + raise Pundit::NotAuthorizedError, _("must have access to guidances api") + end + @user = user + @template = template + end + + ## + # always allowed as index chooses which guidances to display + def index? + true + end + + end + end +end \ No newline at end of file diff --git a/app/policies/note_policy.rb b/app/policies/note_policy.rb index 8ffe95a..88a9e11 100644 --- a/app/policies/note_policy.rb +++ b/app/policies/note_policy.rb @@ -13,11 +13,11 @@ end def update? - Plan.find(@note.plan_id).readable_by?(@user.id) + Plan.find(@note.answer.plan_id).readable_by?(@user.id) end def archive? - Plan.find(@note.plan_id).readable_by?(@user.id) + Plan.find(@note.answer.plan_id).readable_by?(@user.id) end end diff --git a/app/policies/phase_policy.rb b/app/policies/phase_policy.rb new file mode 100644 index 0000000..caa0e3c --- /dev/null +++ b/app/policies/phase_policy.rb @@ -0,0 +1,40 @@ +class PhasePolicy < ApplicationPolicy + attr_reader :user, :phase + + def initialize(user, phase) + raise Pundit::NotAuthorizedError, "must be logged in" unless user + @user = user + @phase = phase + end + + ## + # Org-admin side + # Users can modify phases if: + # - They can modify templates + # - The template which they are modifying belongs to their org + + def admin_show? + user.can_modify_templates? && (phase.template.org_id == user.org_id) + end + + def admin_preview? + user.can_modify_templates? && (phase.template.org_id == user.org_id) + end + + def admin_update? + user.can_modify_templates? && (phase.template.org_id == user.org_id) + end + + def admin_add? + user.can_modify_templates? && (phase.template.org_id == user.org_id) + end + + def admin_create? + user.can_modify_templates? && (phase.template.org_id == user.org_id) + end + + def admin_destroy? + user.can_modify_templates? && (phase.template.org_id == user.org_id) + end + +end \ No newline at end of file diff --git a/app/policies/plan_policy.rb b/app/policies/plan_policy.rb index cb43258..aa99a2b 100644 --- a/app/policies/plan_policy.rb +++ b/app/policies/plan_policy.rb @@ -7,13 +7,13 @@ @user = user @plan = plan end - + def show? @plan.readable_by?(@user.id) end def edit? - @plan.editable_by?(@user.id) + @plan.readable_by?(@user.id) end def update_guidance_choices? @@ -28,14 +28,28 @@ @plan.readable_by?(@user.id) end + def show_export? + @plan.readable_by?(@user.id) + end + def update? @plan.editable_by?(@user.id) end + def destroy? + @plan.editable_by?(@user.id) + end + def status? @plan.readable_by?(@user.id) end + + def possible_templates? + @plan.id.nil? + end +# TODO: These routes are no lonmger used +=begin def section_answers? @plan.readable_by?(@user.id) end @@ -59,6 +73,7 @@ def unlock_section? @plan.editable_by?(@user.id) end +=end def answer? @plan.readable_by?(@user.id) diff --git a/app/policies/question_policy.rb b/app/policies/question_policy.rb new file mode 100644 index 0000000..5ea487c --- /dev/null +++ b/app/policies/question_policy.rb @@ -0,0 +1,28 @@ +class QuestionPolicy < ApplicationPolicy + attr_reader :user, :question + + def initialize(user, question) + raise Pundit::NotAuthorizedError, "must be logged in" unless user + @user = user + @question = question + end + + ## + # Users can modify questions if: + # - They can modify templates + # - The template which they are modifying belongs to their org + ## + + def admin_create? + user.can_modify_templates? && (question.section.phase.template.org_id == user.org_id) + end + + def admin_update? + user.can_modify_templates? && (question.section.phase.template.org_id == user.org_id) + end + + def admin_destroy? + user.can_modify_templates? && (question.section.phase.template.org_id == user.org_id) + end + +end \ No newline at end of file diff --git a/app/policies/role_policy.rb b/app/policies/role_policy.rb index 7aebf02..cf2b691 100644 --- a/app/policies/role_policy.rb +++ b/app/policies/role_policy.rb @@ -9,14 +9,14 @@ end def create? - @role.plan.administerable_by(@user.id) + @role.plan.administerable_by?(@user.id) end def update? - @role.plan.administerable_by(@user.id) + @role.plan.administerable_by?(@user.id) end def destroy? - @role.plan.administerable_by(@user.id) + @role.plan.administerable_by?(@user.id) end end \ No newline at end of file diff --git a/app/policies/section_policy.rb b/app/policies/section_policy.rb new file mode 100644 index 0000000..6effdbe --- /dev/null +++ b/app/policies/section_policy.rb @@ -0,0 +1,28 @@ +class SectionPolicy < ApplicationPolicy + attr_reader :user, :section + + def initialize(user, section) + raise Pundit::NotAuthorizedError, "must be logged in" unless user + @user = user + @section = section + end + + ## + # Users can modify sections if: + # - They can modify templates + # - The template which they are modifying belongs to their org + ## + + def admin_create? + user.can_modify_templates? && (section.phase.template.org_id == user.org_id) + end + + def admin_update? + user.can_modify_templates? && (section.phase.template.org_id == user.org_id) + end + + def admin_destroy? + user.can_modify_templates? && (section.phase.template.org_id == user.org_id) + end + +end \ No newline at end of file diff --git a/app/policies/template_policy.rb b/app/policies/template_policy.rb index 1fd64f5..754e622 100644 --- a/app/policies/template_policy.rb +++ b/app/policies/template_policy.rb @@ -7,6 +7,12 @@ @template = template end + ## + # Users can modify templates if: + # - They can modify templates + # - The template which they are modifying belongs to their org + ## + def admin_index? user.can_modify_templates? end @@ -14,6 +20,18 @@ def admin_template? user.can_modify_templates? && (template.org_id == user.org_id) end + + def admin_customize? + user.can_modify_templates? + end + + def admin_publish? + user.can_modify_templates? && (template.org_id == user.org_id) + end + + def admin_unpublish? + user.can_modify_templates? && (template.org_id == user.org_id) + end def admin_update? user.can_modify_templates? && (template.org_id == user.org_id) @@ -24,7 +42,7 @@ end def admin_create? - user.can_modify_templates? && (template.org_id == user.org_id) + user.can_modify_templates? && (template.org_id.nil? || (template.org_id == user.org_id)) end def admin_destroy? @@ -35,89 +53,10 @@ user.can_modify_templates? && (template.org_id == user.org_id) end - def admin_phase? - user.can_modify_templates? && (template.org_id == user.org_id) + def admin_transfer_customization? + user.can_modify_templates? end - def admin_previewphase? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_addphase? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_createphase? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_updatephase? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_destroyphase? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_updateversion? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_cloneversion? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_destroyversion? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_createsection? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_updatesection? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_destroysection? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_createquestion? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_updatequestion? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_destroyquestion? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_createsuggestedanswer? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_updatesuggestedanswer? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_destroysuggestedanswer? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_createguidance? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_updateguidance? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_destroyguidance? - user.can_modify_templates? && (template.org_id == user.org_id) - end class Scope < Scope def resolve diff --git a/app/policies/user_identifier_policy.rb b/app/policies/user_identifier_policy.rb new file mode 100644 index 0000000..e57f1c9 --- /dev/null +++ b/app/policies/user_identifier_policy.rb @@ -0,0 +1,20 @@ +class UserIdentifierPolicy < ApplicationPolicy + attr_reader :user_identifier + + def initialize(user, users) + raise Pundit::NotAuthorizedError, "must be logged in" unless user + @user = user + @users = users + end + + def destroy? + !user.nil? + end + + class Scope < Scope + def resolve + scope.where(user_id: user.id) + end + end + +end \ No newline at end of file diff --git a/app/views/admin/dmptemplates/settings.html.erb b/app/views/admin/dmptemplates/settings.html.erb deleted file mode 100644 index c955083..0000000 --- a/app/views/admin/dmptemplates/settings.html.erb +++ /dev/null @@ -1,38 +0,0 @@ -<% @settings.errors.full_messages.each do |error| %> -
    <%= error %>
    -<% end %> - -<%= form_for(@settings, url: update_settings_admin_dmptemplate_path(@template), method: :put, as: 'settings[export][formatting]', html: { class: 'formtastic' }) do |f| %> -
    - <%= _('Formatting') %> -
      -
    1. - <%= f.label(:font_face, _('Face')) %> - <%= f.select(:font_face, options_for_select(Settings::Dmptemplate::VALID_FONT_FACES, @settings.formatting[:font_face]), as: 'formatting[font_face]') %> - <%= f.select(:font_size, options_for_select((1..36).to_a, @settings.formatting[:font_size])) %>pt -
    2. -
    3. - <%= f.label(_('Margin')) %> - <% ["top", "bottom", "left", "right"].each do |pos| %> - <%= t("helpers.settings.plans.margins.#{pos}") -%> - <%= select_tag("settings[export][formatting][margin][#{pos}]", options_for_select((0..100).to_a, @settings.formatting[:margin][pos])) %> - <% end %> -
    4. -
    -
    - -
    - <%= _('Max Pages')%> -
      -
    1. - <%= label_tag('settings_export_max_pages', _('Maximum number of pages')) %> - <%= select_tag('settings[export][max_pages]', options_for_select((1..10).to_a, @settings.max_pages)) %> -
    2. -
    -
    - -
    - <%= submit_tag(_('Save'), class: 'btn btn-primary') %> - <%= submit_tag(_('Reset'), class: 'btn btn-primary') %> -
    -<% end %> diff --git a/app/views/administrate/application/_admin_header.html.erb b/app/views/administrate/application/_admin_header.html.erb new file mode 100644 index 0000000..115db95 --- /dev/null +++ b/app/views/administrate/application/_admin_header.html.erb @@ -0,0 +1,4 @@ +
    +

    Super Admin area

    + <%= link_to(image_tag("logo.jpg"), root_path)%> +
    diff --git a/app/views/administrate/application/_navigation.html.erb b/app/views/administrate/application/_navigation.html.erb new file mode 100644 index 0000000..a5cfa7a --- /dev/null +++ b/app/views/administrate/application/_navigation.html.erb @@ -0,0 +1,26 @@ +<%# Hack for customisation %> + +<%# +# Navigation + +This partial is used to display the navigation in Administrate. +By default, the navigation contains navigation links +for all resources in the admin dashboard, +as defined by the routes in the `admin/` namespace +%> + + diff --git a/app/views/administrate/application/_search.html.erb b/app/views/administrate/application/_search.html.erb new file mode 100644 index 0000000..7145011 --- /dev/null +++ b/app/views/administrate/application/_search.html.erb @@ -0,0 +1,21 @@ + diff --git a/app/views/annotations/_add_annotation.html.erb b/app/views/annotations/_add_annotation.html.erb new file mode 100644 index 0000000..8add942 --- /dev/null +++ b/app/views/annotations/_add_annotation.html.erb @@ -0,0 +1,32 @@ + +

    <%= _('Add Annotations') %>

    +<%= form_tag admin_create_annotation_path , class: 'add_annotation_form' do %> + + + + + + + + + +
    <%= _('Example Answer')%> +
      +
    • <%= text_area_tag :example_answer_text, nil, rows: 5 %> +
    • +
    +
    <%= _('Guidance')%> +
      +
    • <%= text_area_tag :guidance_text, nil, rows: 5 %> +
    • +
    +
    +
    + + +
    + <%= submit_tag _('Save'), class: "btn btn-primary" %> + <%= hidden_field_tag :question_id, question.id, class: "question_id" %> + <%= link_to _('Cancel'), "#", class: "btn cancel cancel_add_annotations" %> +
    +<%end%> diff --git a/app/views/annotations/_edit_annotation.html.erb b/app/views/annotations/_edit_annotation.html.erb new file mode 100644 index 0000000..3a59362 --- /dev/null +++ b/app/views/annotations/_edit_annotation.html.erb @@ -0,0 +1,43 @@ + +<%= form_tag admin_update_annotation_path, method: :put do %> + <% example_answer_text = example_answer.present? ? example_answer.text : '' %> + <% guidance_text = guidance.present? ? guidance.text : '' %> + <%= hidden_field_tag :example_answer_id, example_answer.present? ? example_answer.id : nil %> + <%= hidden_field_tag :guidance_id, guidance.present? ? guidance.id : nil %> + + + + + + + + + + +
    <%= _('Example Answer')%> +
      +
    • <%= text_area_tag :example_answer_text, example_answer_text, rows: 5 %>
    • +
    +
    <%= _('Guidance')%> +
      +
    • <%= text_area_tag :guidance_text, guidance_text, rows: 5 %>
    • +
    +
    +
    + + +
    + <%= submit_tag _('Save'), class: 'btn btn-primary' %> + <% if example_answer.present? %> + <%= link_to _('Delete Example Answer'), admin_destroy_annotation_path(id: example_answer.id), + confirm: _("You are about to delete an example answer for '%{question_text}'. Are you sure?") % { :question_text => question.text }, method: :delete, class: "btn btn-primary"%> + <% end %> + <% if guidance.present? %> + <%= link_to _('Delete Example Answer'), admin_destroy_annotation_path(id: guidance.id), + confirm: _("You are about to delete a guidance for '%{question_text}'. Are you sure?") % { :question_text => question.text }, method: :delete, class: "btn btn-primary"%> + <% end %> + + <%= hidden_field_tag :question_id, question.id, class: "question_id" %> + <%= link_to _('Cancel'), '#', class: 'btn cancel cancel_edit_annotations' %> +
    +<% end %> diff --git a/app/views/annotations/_show_annotation.html.erb b/app/views/annotations/_show_annotation.html.erb new file mode 100644 index 0000000..a790d70 --- /dev/null +++ b/app/views/annotations/_show_annotation.html.erb @@ -0,0 +1,26 @@ + +

    <%= _('Annotations') %>

    + + <% if example_answer.present? %> + + + + + <% end %> + <% if guidance.present? %> + + + + + <% end %> +
    + <%= _('Example Answer')%> + <%= raw example_answer.text %>
    + <%= _('Guidance')%> + <%= raw guidance.text %>
    +
    + +
    + <%= hidden_field_tag :question_id, question.id, class: "question_id" %> + <%= link_to _('Edit Annotations'), '# ', class: "btn btn-primary edit_form_for_annotations"%> +
    diff --git a/app/views/answers/_form_fields.html.erb b/app/views/answers/_form_fields.html.erb new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/views/answers/_form_fields.html.erb diff --git a/app/views/answers/_locking.html.erb b/app/views/answers/_locking.html.erb new file mode 100644 index 0000000..40a3d90 --- /dev/null +++ b/app/views/answers/_locking.html.erb @@ -0,0 +1,5 @@ +
    +

    <%= _('The following answer cannot be saved') %>

    + <%= render partial: '/answers/new_edit', locals: { question: question, answer: answer, readonly: true } %> +

    <%= _('since %{name} saved the answer below while you were editing. Please, combine your changes and then save the answer again.') % { name: user.name} %>

    +
    diff --git a/app/views/answers/_new_edit.html.erb b/app/views/answers/_new_edit.html.erb new file mode 100644 index 0000000..2434033 --- /dev/null +++ b/app/views/answers/_new_edit.html.erb @@ -0,0 +1,101 @@ + +<% q_format = question.question_format %> +<%= semantic_form_for answer, :url => {controller: :answers, action: :update }, html: {method: "put", class: "roadmap-form", 'data-autosave': question.id }, remote: true do |f| %> +
    + <% if !readonly %> + <%= f.input :id, as: :hidden, input_html: { value: answer.id } %> + <%= f.input :plan_id, as: :hidden, input_html: { value: answer.plan_id } %> + <%= f.input :user_id, as: :hidden, input_html: { value: answer.user_id } %> + <%= f.input :question_id, as: :hidden, input_html: { value: answer.question_id } %> + <%= f.input :lock_version, as: :hidden, input_html: { value: answer.lock_version } %> + <% end %> + + +

    + <%= raw question.text %> +

    + + + <% if !readonly && question.annotations.where(type: Annotation.types[:example_answer]).any? %> + <% annotation = question.annotations.where(type: Annotation.types[:example_answer]).order(:created_at).first %> + <% if annotation.text.present? %> +
    + + <%="#{annotation.org.abbreviation} "%> <%=_('Example of answer')%> + + +
    +

    + <%= raw annotation.text %> +

    +
    +
    + <% end %> + <% end %> + + <% if question.option_based? %> + <% options = question.question_options.by_number %> + <% if q_format.checkbox? %> +
      + <% options.each do |op| %> +
    1. + <%= f.check_box(:question_option_ids, { multiple: true, checked: answer.has_question_option(op.id), disabled: readonly }, op.id, nil) %> + <%= raw op.text %> +
    2. + <% end %> +
    + <% elsif q_format.radiobuttons? %> +
      + <% options.each do |op| %> +
    1. + <%= f.radio_button :question_option_ids, op.id, { checked: answer.has_question_option(op.id), id: "answer_option_ids_#{op.id}", disabled: readonly } %> + <%= raw op.text %> +
    2. + <% end %> +
    + <% elsif q_format.dropdown? || q_format.multiselectbox? %> + <% + options_html = "" + options.each do |op| + options_html += answer.has_question_option(op.id) ? + "" : + "" + end + %> + <%= select_tag('answer[question_option_ids]', raw(options_html), + {multiple: q_format.multiselectbox?, include_blank: q_format.dropdown?, disabled: readonly }) %> + <% end %> + + <% if question.option_comment_display == true %> + <%= label_tag('answer[text]', _('Comment')) %> + <% if readonly %> +

    <%= raw(answer.text) %>

    + <% else %> + <%= text_area_tag('answer[text]', answer.text, id: "answer-text-#{question.id}") %> + <%= tinymce(selector: "#answer-text-#{question.id}", setup: "$.fn.tinymce_answer_events", content_css: asset_path('application.css')) %> + <% end %> + <%end%> + <% end %> + + <% if q_format.textfield? %> + <% if readonly %> +

    <%= strip_tags(answer.text) %>

    + <% else %> + <%= text_field_tag('answer[text]', strip_tags(answer.text)) %> + <% end %> + <% elsif q_format.textarea? %> + <% if readonly %> +

    <%= raw(answer.text) %>

    + <% else %> + <%= text_area_tag('answer[text]', answer.text, id: "answer-text-#{question.id}") %> + <%= tinymce(selector: "#answer-text-#{question.id}", setup: "$.fn.tinymce_answer_events", content_css: asset_path('application.css')) %> + <% end %> + <% end %> + + <% if !readonly %> + + <% end %> +
    + <% end %> \ No newline at end of file diff --git a/app/views/answers/_status.html.erb b/app/views/answers/_status.html.erb new file mode 100644 index 0000000..ddf8dcf --- /dev/null +++ b/app/views/answers/_status.html.erb @@ -0,0 +1,9 @@ + + + +
    + <% if answer.updated_at.blank? %> + <%= _('Not answered yet') %> + <% else %> + <%= _('Answered')%> <%= answer.updated_at.iso8601 %><%= _(' by')%> <%= answer.user.name %> + <% end %> \ No newline at end of file diff --git a/app/views/answers/update.js.erb b/app/views/answers/update.js.erb new file mode 100644 index 0000000..2290a67 --- /dev/null +++ b/app/views/answers/update.js.erb @@ -0,0 +1,26 @@ +// partial /answers/locking +<% if @stale_answer %> + $("#answer-locking-<%= @question.id%>") + .html("<%= escape_javascript(render partial: '/answers/locking', locals: { question: @question, answer: @stale_answer, user: @answer.user }) %>"); +<% else %> + $("#answer-locking-<%= @question.id%>").html(""); +<% end %> + +// partial /answer/new_edit +if(tinymce) + tinymce.remove("#answer-text-<%= @question.id %>"); +$("#answer-form-<%= @question.id%>") + .html("<%= escape_javascript(render partial: '/answers/new_edit', locals: { question: @question, answer: @answer, readonly: false }) %>"); + +// partial /answer/status +$("#answer-status-<%= @question.id %>") + .html("<%= escape_javascript(render partial: '/answers/status', locals: { answer: @answer}) %>"); +if($.fn.init_answer_status) + $.fn.init_answer_status(); + +// partial /plans/progress +$(".progress").html("<%= escape_javascript(render :partial => '/plans/progress', locals: { plan: @plan }) %>"); + +// partial /sections/progress +$("#section-progress-<%= @section.id %>") + .html("<%= escape_javascript(render partial: '/sections/progress', locals: { section: @section, plan: @plan }) %>"); \ No newline at end of file diff --git a/app/views/api/v0/guidance_groups/index.json.jbuilder b/app/views/api/v0/guidance_groups/index.json.jbuilder index 908b19d..7a5fd3d 100644 --- a/app/views/api/v0/guidance_groups/index.json.jbuilder +++ b/app/views/api/v0/guidance_groups/index.json.jbuilder @@ -5,17 +5,13 @@ json.name guidance_group.name json.id guidance_group.id - # for each template associated with the guidance group, list the template name - @templates = guidance_group.dmptemplates - # if the template is empty, instead use all avalable templates - if @templates.empty? - @templates = Dmptemplate.all - end - json.templates @templates do |template| - json.title template.title - json.id template.id - end - json.optional guidance_group.optional_subset json.updated guidance_group.updated_at -end + json.guidances guidance_group.guidances.each do |guidance| + json.text guidance.text + json.updated guidance.updated_at + json.themes guidance.themes.each do |theme| + json.title theme.title + end + end +end \ No newline at end of file diff --git a/app/views/api/v0/guidance_groups/show.json.jbuilder b/app/views/api/v0/guidance_groups/show.json.jbuilder deleted file mode 100644 index 1a412db..0000000 --- a/app/views/api/v0/guidance_groups/show.json.jbuilder +++ /dev/null @@ -1,25 +0,0 @@ -# builds a json response to api query for a list of guidance groups -json.prettify! - -json.guidance_group do - json.name @guidance_group.name - json.id @guidance_group.id - - # for each template associated with the guidance group, list the template name - @templates = @guidance_group.dmptemplates - # if the template is empty, instead use all avalable templates - if @templates.empty? - @templates = Dmptemplate.all - end - json.templates @templates do |template| - json.title template.title - json.id template.id - end - - json.guidances @guidance_group.guidances do |guidance| - json.text guidance.text - json.id guidance.id - end - json.optional @guidance_group.optional_subset - json.updated @guidance_group.updated_at -end diff --git a/app/views/api/v0/guidances/index.json.jbuilder b/app/views/api/v0/guidances/index.json.jbuilder deleted file mode 100644 index 82edd20..0000000 --- a/app/views/api/v0/guidances/index.json.jbuilder +++ /dev/null @@ -1,29 +0,0 @@ -# builds a json response to api querry for all guidances - -json.prettify! - -json.guidance @all_viewable_guidances do |guidance| - json.id guidance.id - json.text guidance.text - json.updated_at guidance.updated_at - - # each guidance may be associated with many guidance groups - @guidance_groups = guidance.guidance_groups - json.guidance_groups @guidance_groups do |guidance_group| - json.name guidance_group.name - json.id guidance_group.id - - # for each template associated with the guidance group, list the template name - @templates = guidance_group.dmptemplates - # if the template is empty, instead use all avalable templates - if @templates.empty? - @templates = Dmptemplate.all - end - json.templates @templates do |template| - json.title template.title - end - json.optional guidance_group.optional_subset - json.updated guidance_group.updated_at - end - -end diff --git a/app/views/api/v0/guidances/show.json.jbuilder b/app/views/api/v0/guidances/show.json.jbuilder deleted file mode 100644 index be04df7..0000000 --- a/app/views/api/v0/guidances/show.json.jbuilder +++ /dev/null @@ -1,30 +0,0 @@ -# builds a json response to api querry for a specific guidance - -json.prettify! - -json.guidance do - json.id @guidance.id - json.text @guidance.text - json.updated_at @guidance.updated_at - - # each guidance may be associated with many guidance groups - @guidance_groups = @guidance.guidance_groups - unless @guidance_groups.empty? - json.guidance_groups @guidance_groups do |guidance_group| - json.name guidance_group.name - json.id guidance_group.id - - # for each template associated with the guidance group, list the template name - @templates = guidance_group.dmptemplates - # if the template is empty, instead use all avalable templates - if @templates.empty? - @templates = Dmptemplate.all - end - json.templates @templates do |template| - json.title template.title - end - json.optional guidance_group.optional_subset - json.updated guidance_group.updated_at - end - end -end \ No newline at end of file diff --git a/app/views/api/v0/plans/create.json.jbuilder b/app/views/api/v0/plans/create.json.jbuilder index ebb8c58..0c3b359 100644 --- a/app/views/api/v0/plans/create.json.jbuilder +++ b/app/views/api/v0/plans/create.json.jbuilder @@ -2,14 +2,11 @@ json.prettify! -json.project do - json.title @project.title +json.plan do + json.title @plan.title + json.template @plan.template.title # TODO add after decision on user creation/identification - #json.created_by @project.owner.email - json.id @project.id - json.created_at @project.created_at -end - -# json.location do -# json.link (url_for action: 'show', controller: 'project') -# end + json.created_by @plan.owner.email + json.id @plan.id + json.created_at @plan.created_at +end \ No newline at end of file diff --git a/app/views/api/v0/statistics/plans.json.jbuilder b/app/views/api/v0/statistics/plans.json.jbuilder index fe85ca8..fdefac1 100644 --- a/app/views/api/v0/statistics/plans.json.jbuilder +++ b/app/views/api/v0/statistics/plans.json.jbuilder @@ -1,18 +1,15 @@ json.prettify! -json.plans @org_projects.each do |plan| +json.plans @org_plans.each do |plan| json.id plan.id json.grant_number plan.grant_number - json.org_id plan.creator.org.id + json.title plan.title json.template do json.title plan.template.title - json.id plan.template.id - end - json.project do - json.title plan.title + json.id plan.template.dmptemplate_id end json.funder do - json.name (plan.template.org.funder? ? plan.org.name : '') + json.name (plan.template.org.funder? ? plan.template.org.name : '') end json.principal_investigator do json.name plan.principal_investigator diff --git a/app/views/api/v0/statistics/plans_by_template.json.jbuilder b/app/views/api/v0/statistics/plans_by_template.json.jbuilder index d8d5485..9a7efd8 100644 --- a/app/views/api/v0/statistics/plans_by_template.json.jbuilder +++ b/app/views/api/v0/statistics/plans_by_template.json.jbuilder @@ -1,20 +1,7 @@ json.prettify! -templates = {} -@org_projects.each do |plan| - # if hash exists - if templates[plan.template.title].blank? - templates[plan.template.title] = {} - templates[plan.template.title][:title] = plan.template.title - templates[plan.template.title][:id] = plan.template.id - templates[plan.template.title][:uses] = 1 - else - templates[plan.template.title][:uses] += 1 - end -end -json.templates templates.each do |template, info| +json.templates @templates.each do |template, info| json.template_name info[:title] json.template_id info[:id] json.template_uses info[:uses] -end - +end \ No newline at end of file diff --git a/app/views/api/v0/statistics/using_template.json.jbuilder b/app/views/api/v0/statistics/using_template.json.jbuilder index 04a77b6..9a7efd8 100644 --- a/app/views/api/v0/statistics/using_template.json.jbuilder +++ b/app/views/api/v0/statistics/using_template.json.jbuilder @@ -1,3 +1,7 @@ json.prettify! -json.plans_using_template @template_count \ No newline at end of file +json.templates @templates.each do |template, info| + json.template_name info[:title] + json.template_id info[:id] + json.template_uses info[:uses] +end \ No newline at end of file diff --git a/app/views/api/v0/templates/index.json.jbuilder b/app/views/api/v0/templates/index.json.jbuilder index 643d87d..5f9b5ff 100644 --- a/app/views/api/v0/templates/index.json.jbuilder +++ b/app/views/api/v0/templates/index.json.jbuilder @@ -2,11 +2,18 @@ json.prettify! json.templates @org_templates.each do |org, templates| - json.organisation_name org.name - json.organisation_id org.id - json.organisation_templates templates.each do |_, template| - json.title template.title - json.id template.id - json.description template.description - end + json.organisation_name org.name + json.organisation_id org.id + json.is_funder org.funder? + json.organisation_templates templates[:own].each do |_, template| + json.title template.title + json.id template.dmptemplate_id + json.description template.description + end + json.customized_templates templates[:cust].each do |_,template| + json.title template.title + json.id template.dmptemplate_id + json.customization_of template.customization_of + json.description template.description + end end \ No newline at end of file diff --git a/app/views/contact_us/contacts/new.html.erb b/app/views/contact_us/contacts/new.html.erb index 57596a5..c4d2f30 100644 --- a/app/views/contact_us/contacts/new.html.erb +++ b/app/views/contact_us/contacts/new.html.erb @@ -1,122 +1,111 @@ - +<% javascript "contacts/new_contact.js" %> +

    - <%= t("contact_page.title") %> + <%= _("Contact Us") %>

    - <%= raw t("contact_page.intro_text_html", - organisation_name: Rails.configuration.branding[:organisation][:name], - organisation_email: Rails.configuration.branding[:organisation][:email], - organisation_url: Rails.configuration.branding[:organisation][:url], - application_name: Rails.configuration.branding[:application][:name], - application_url: Rails.configuration.branding[:application][:url], - application_issue_list_url: Rails.configuration.branding[:application][:issue_list_url]) %> - <%= raw t("contact_page.github_text_html") %> + <%= raw _('%{application_name} is provided by the %{organisation_name}. You can find out more about us on our website. If you would like to contact us about %{application_name}, please fill out the form below.') % {organisation_name: Rails.configuration.branding[:organisation][:name], + organisation_url: Rails.configuration.branding[:organisation][:url], + application_name: Rails.configuration.branding[:application][:name]} %>

    - -
    -
    - <%= form_for @contact, :url => contacts_path do |f| %> -
    - - <% if ContactUs.require_name %> - - - - - <% end %> - - - - - <% if ContactUs.require_subject %> - - - - - <% end %> - - - - - <% if !user_signed_in? then %> - - - - - <% end %> -
    - <%= f.label :name, (t('.name') + content_tag(:abbr, "*", :class => "required")).html_safe %> - - <% if user_signed_in? then %> - <%= f.text_field :name, :value => current_user.name(false) %> - <% else %> - <%= f.text_field :name %> - <% end %> - <% if f.object.errors[:name].present? %> -

    <%= f.object.errors[:name].join(" and ") %>

    - <% end %> -
    - <%= f.label :email, (t('.email') + content_tag(:abbr, "*", :class => "required")).html_safe %> - - <% if user_signed_in? then %> - <%= f.email_field :email, :value => current_user.email %> - <% else %> - <%= f.email_field :email %> - <% end %> - <% if f.object.errors[:email].present? %> -

    <%= f.object.errors[:email].join(" and ") %>

    - <% end %> -
    - <%= f.label :subject, (t('.subject') + content_tag(:abbr, "*", :class => "required")).html_safe %> - - <%= f.text_field :subject %> - <% if f.object.errors[:subject].present? %> -

    <%= f.object.errors[:subject].join(" and ") %>

    - <% end %> -
    - <%= f.label :message, (t('.message') + content_tag(:abbr, "*", :class => "required")).html_safe %> - - <%= f.text_area :message, :rows => 10 %> - <% if f.object.errors[:message].present? %> -

    <%= f.object.errors[:message].join(" and ") %>

    - <% end %> -
    - <%= t('helpers.security_check') %> - - <%= recaptcha_tags %> -
    -
    -
    - <%= f.submit :submit, :class => "btn btn-primary", :label => t('.submit') %> -
    - <% end %> -
    -
    - - -
    -
    - <%= raw t("contact_page.address_text_html", - organisation_name: Rails.configuration.branding[:organisation][:name], - organisation_email: Rails.configuration.branding[:organisation][:email], - application_name: Rails.configuration.branding[:application][:name], - organisation_telephone: Rails.configuration.branding[:organisation][:telephone], - organisation_address_line1: Rails.configuration.branding[:organisation][:address_line1], - organisation_address_line2: Rails.configuration.branding[:organisation][:address_line2], - organisation_address_line3: Rails.configuration.branding[:organisation][:address_line3], - organisation_address_line4: Rails.configuration.branding[:organisation][:address_line4], - organisation_address_country: Rails.configuration.branding[:organisation][:address_country]) %> - -
    - + +
    +
    + <%= form_for @contact, url: contacts_path, html: {class: "roadmap-form"} do |f| %> +
    + <% if ContactUs.require_name %> +
    + <%= f.label :name, (_('Name') + content_tag(:abbr, "*", class: "required")).html_safe %> + <% if user_signed_in? then %> + <%= f.text_field :name, value: current_user.name(false) %> + <% else %> + <%= f.text_field :name %> + <% end %> + <% if f.object.errors[:name].present? %> +

    <%= f.object.errors[:name].join(_(" and ")) %>

    + <% end %> +
    + <% end %> + +
    + <%= f.label :email, (_('Email') + content_tag(:abbr, "*", class: "required")).html_safe %> + <% if user_signed_in? then %> + <%= f.email_field :email, value: current_user.email %> + <% else %> + <%= f.email_field :email %> + <% end %> + <% if f.object.errors[:email].present? %> +

    <%= f.object.errors[:email].join(_(" and ")) %>

    + <% end %> +
    + + <% if ContactUs.require_subject %> +
    + <%= f.label :subject, (_('Subject') + content_tag(:abbr, "*", class: "required")).html_safe %> + <%= f.text_field :subject %> + <% if f.object.errors[:subject].present? %> +

    <%= f.object.errors[:subject].join(_(" and ")) %>

    + <% end %> +
    + <% end %> + +
    + <%= f.label :message, (_('Message') + content_tag(:abbr, "*", class: "required")).html_safe %> + <%= f.text_area :message, rows: 10, class: "input-large" %> + <% if f.object.errors[:message].present? %> +

    <%= f.object.errors[:message].join(_(" and ")) %>

    + <% end %> +
    + + <% if !user_signed_in? then %> +
    + <%= t('helpers.security_check') %> + <%= recaptcha_tags %> +
    + <% end %> + +
    + + <%= render partial: 'shared/accessible_submit_button', + locals: {id: 'create_contact_submit', + val: 'Submit', + disabled_initially: true, + tooltip: _('Fill in the required fields')} %> +
    +
    -
    -
    -
    - + <% end %> +
    +
    + + +
    +
    + <%= raw _("
    • %{organisation_name}
    • +
    • %{organisation_address_line1}
    • +
    • %{organisation_address_line2}
    • +
    • %{organisation_address_line3}
    • +
    • %{organisation_address_line4}
    • +
    • %{organisation_address_country}
    • +
    +

    Helpline: %{organisation_telephone}

    +

    Email %{organisation_email}

    ") % + { organisation_name: Rails.configuration.branding[:organisation][:name], + organisation_address_line1: Rails.configuration.branding[:organisation][:address_line1], + organisation_address_line2: Rails.configuration.branding[:organisation][:address_line2], + organisation_address_line3: Rails.configuration.branding[:organisation][:address_line3], + organisation_address_line4: Rails.configuration.branding[:organisation][:address_line4], + organisation_address_country: Rails.configuration.branding[:organisation][:address_country], + organisation_telephone: Rails.configuration.branding[:organisation][:telephone], + organisation_email: Rails.configuration.branding[:organisation][:email], + application_name: Rails.configuration.branding[:application][:name]} %> + +
    + + +
    +
    +
    +
    diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb index c1faca5..0576cc7 100644 --- a/app/views/devise/mailer/confirmation_instructions.html.erb +++ b/app/views/devise/mailer/confirmation_instructions.html.erb @@ -1,5 +1,7 @@ -

    <%= t('custom_devise.welcome_to_DMP') %>, <%= @email %>!

    +<% FastGettext.with_locale FastGettext.default_locale do %> +

    <%= _("Welcome to %{application_name}") % {application_name: Rails.configuration.branding[:application][:name]} %>, <%= @email %>!

    -

    <%= t('custom_devise.thank_you_and_confirm') %>

    +

    <%= _("Thank you for registering. Please confirm your email address") %>:

    -

    <%= link_to t('custom_devise.click_to_confirm'), confirmation_url(@resource, :confirmation_token => @token) %> <%= t('custom_devise.1st_part_copy') %> <%= confirmation_url(@resource, :confirmation_token => @token) %> <%= t('custom_devise.2nd_part_copy') %>

    \ No newline at end of file +

    <%= link_to _("Click here to confirm your account"), confirmation_url(@resource, :confirmation_token => @token) %> (<%= _("or copy") %> <%= confirmation_url(@resource, :confirmation_token => @token) %> <%= _("into your browser") %>).

    +<% end %> \ No newline at end of file diff --git a/app/views/devise/mailer/invitation_instructions.html.erb b/app/views/devise/mailer/invitation_instructions.html.erb index 7beb75d..c7235c1 100644 --- a/app/views/devise/mailer/invitation_instructions.html.erb +++ b/app/views/devise/mailer/invitation_instructions.html.erb @@ -1,7 +1,8 @@ -

    <%= t('custom_devise.hello') %> <%= @resource.email %>!

    +<% FastGettext.with_locale FastGettext.default_locale do %> +

    <%= _("Hello") %> <%= @resource.email %>,

    +

    <%= _("A colleague has invited you to contribute to their Data Management Plan at ") %> <%= link_to Rails.configuration.branding[:application][:name], root_url %>.

    +

    <%= link_to _("Click here to accept the invitation"), accept_invitation_url(@resource, :invitation_token => @token) %> (<%= _("or copy") %> <%= accept_invitation_url(@resource, :invitation_token => @token) %> <%= _("into your browser") %>).

    +

    <%= _("If you don't want to accept the invitation, please ignore this email.") %>
    <%= _("Your account won't be created until you access the link above and set your password.") %>

    +

    <%=_('All the best,')%>
    <%= _('The ')%><%= Rails.configuration.branding[:application][:name] %><%=_(' team')%>.

    -

    <%= t('custom_devise.colleague_invited_you') %> <%= link_to t('tool_title'), root_url %>

    - -

    <%= link_to t('custom_devise.click_to_accept'), accept_invitation_url(@resource, :invitation_token => @token) %> <%= t('custom_devise.1st_part_copy') %> <%= accept_invitation_url(@resource, :invitation_token => @token) %> <%= t('custom_devise.2nd_part_copy') %>

    - -<%= t('custom_devise.ignore_wont_be_created') %> \ No newline at end of file +<% end %> diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb index b4c0ac6..55858c9 100644 --- a/app/views/devise/mailer/reset_password_instructions.html.erb +++ b/app/views/devise/mailer/reset_password_instructions.html.erb @@ -1,7 +1,13 @@ -

    <%= t('custom_devise.hello') %> <%= @resource.email %>!

    +<% FastGettext.with_locale FastGettext.default_locale do %> +

    <%= _("Hello ") %><%= @resource.email %>

    -

    <%= t('custom_devise.1st_part_change_password') %> <%= link_to t('tool_title'), root_url %> <%= t('custom_devise.2nd_part_change_password') %>

    +

    <%= _("Someone has requested a link to change your ") %><%= Rails.configuration.branding[:application][:name] %><%= _(" password. You can do this through the link below.") %>

    -

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

    +

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

    -<%= t('custom_devise.1st_part_change_password') %> +

    <%= _("If you didn't request this, please ignore this email.") %>

    + +

    + <%= _("Many thanks,") %>
    <%= _('The ') %><%= Rails.configuration.branding[:application][:name] %><%= _(' team') %> +

    +<% end %> \ No newline at end of file diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb index 0346189..3787b7a 100644 --- a/app/views/devise/mailer/unlock_instructions.html.erb +++ b/app/views/devise/mailer/unlock_instructions.html.erb @@ -1,7 +1,9 @@ -

    <%= t('custom_devise.hello') %> <%= @resource.email %>!

    +<% FastGettext.with_locale FastGettext.default_locale do %> +

    <%= _("Hello") %> <%= @resource.email %>!

    -

    <%= t('custom_devise.1st_part_locked') %><%= link_to t('tool_title'), root_url %><%= t('custom_devise.2nd_part_locked') %>

    +

    <%= _("Your") %> <%= link_to Rails.configuration.branding[:application][:name], root_url %> <%= _("account has been locked due to an excessive number of unsuccessful sign in attempts.") %>

    -

    <%= t('custom_devise.click_to_unlock') %>

    +

    <%= _("Click the link below to unlock your account") %>:

    -

    <%= link_to t('custom_devise.unlock'), unlock_url(@resource, :unlock_token => @token) %>

    \ No newline at end of file +

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

    +<% end %> \ No newline at end of file diff --git a/app/views/devise/registrations/_external_identifier.html.erb b/app/views/devise/registrations/_external_identifier.html.erb index bbc8d75..226b270 100644 --- a/app/views/devise/registrations/_external_identifier.html.erb +++ b/app/views/devise/registrations/_external_identifier.html.erb @@ -1,27 +1,21 @@ -
    ); background-size: 16px 16px;"> - +
    <% if id.nil? || id.identifier == '' %> - - <%= link_to "#{t("identifier_schemes.schemes.#{scheme.name}.connect")}", - Rails.application.routes.url_helpers.send( - "user_#{scheme.name.downcase}_omniauth_authorize_path" - ), - title: t("identifier_schemes.schemes.#{scheme.name}.connect_tooltip") %> - + <%= link_to "#{_("Link account with #{scheme.description} ID")}", + Rails.application.routes.url_helpers.send( + "user_#{scheme.name.downcase}_omniauth_authorize_path" + ), + title: t("identifier_schemes.schemes.#{scheme.name}.connect_tooltip", default: "") + %> <% else %> - <% if t("identifier_schemes.schemes.#{scheme.name}.user_landing_page").nil? %> - <%= t("identifier_schemes.schemes.connect_success").gsub(/%\{scheme\}/, scheme.name.capitalize) %> - - <% else %> - <% uri = t("identifier_schemes.schemes.#{scheme.name}.user_landing_page").gsub(/%\{id\}/, id.identifier) %> - <%= link_to uri, uri, target: '_blank', - title: t("identifier_schemes.schemes.#{scheme.name}.connect_tooltip") %> + <% if scheme.user_landing_url.nil? %> + <%= _("Your account has been linked to #{scheme.description}.") %> + <% else %> + <%= link_to "#{_("Your account has been linked to #{scheme.description}.")}", "#{scheme.user_landing_url}/#{id.identifier}", target: '_blank', + title: t("identifier_schemes.schemes.#{scheme.name}.connect_tooltip", default: "") %> <% end %> - - <%= link_to image_tag('remove.png', height: '16px', width: '16px'), + <%= link_to ''.html_safe, destroy_user_identifier_path(id), method: :delete, - title: t("identifier_schemes.schemes.#{scheme.name}.disconnect_tooltip"), - data: {confirm: t("identifier_schemes.schemes.#{scheme.name}.disconnect_confirmation")} %> + title: _("Unlink your account from #{scheme.description}. You can link again at any time."), + data: {confirm: _("Are you sure you want to unlink #{scheme.description} ID?")} %> <% end %>
    diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb index ae0c08c..8bb0f82 100644 --- a/app/views/devise/registrations/edit.html.erb +++ b/app/views/devise/registrations/edit.html.erb @@ -1,146 +1,117 @@ -

    <%= t("helpers.edit_profile") %>

    - -<%= raw t("helpers.user_details_text_html") %> +
    +

    <%= _('Edit profile') %>

    -
    - <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: {method: :put}) do |f| %> - <%= hidden_field_tag :unlink_flag, "false", id: "unlink_flag" %> - -
    +

    + <%= _("Please note that your email address is used as your username. If you change this, remember to use your new email address on sign in.") %> +

    -

    <%= raw t("helpers.user_details_paragraph_html") %>

    + <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: {method: :put, class: "roadmap-form white_background"}) do |f| %> + +
    + <%= _('You can edit any of the details below.') %> + + <%= hidden_field_tag :unlink_flag, "false", id: "unlink_flag" %> - - - - - - - - - - - - - - - - - - "> - - - - - - - - - <% @identifier_schemes.each do |scheme| %> - - - - - <% end %> - - - <% unless @user.api_token.blank? %> - - - - - - - - - <% end %> -
    <%= (t("helpers.email") + " *") %><%= f.email_field :email, as: :email %>
    <%= t("helpers.first_name") %><%= f.text_field :firstname, as: :string, - id: "first_time_login_firstname", - autofocus: true, - class: "text_field has-tooltip", - "data-toggle" => "tooltip", - "data-trigger" => "focus" , - "title" => t("helpers.first_name_help_text") %>
    <%= t("helpers.last_name") %><%= f.text_field :surname, - as: :string, id: "first_time_login_surname", - class: "text_field has-tooltip", - "data-toggle" => "tooltip", - "data-trigger" => "focus" , - "title" => t("helpers.surname_help_text") %>
    <%= t("helpers.org_type.organisation") %><%= collection_select(:user, - :org_id, @orgs, - :id, :name, {include_blank: constant("organisation_types.organisation")}, - { class: "typeahead org_sign_up" }) %>
    <%= t('helpers.user_details_language') %> - - - -
    <%= scheme.name %> - <%= render partial: 'external_identifier', - locals: {scheme: scheme, - id: current_user.identifier_for(scheme)} %> -
    <%= t("helpers.api_token") %><%= @user.api_token %>
    <%= t("helpers.api_info") %><%= link_to( t("helpers.api_use"), controller: "token_permission_types", action: "index")%>
    -
    -

    - <% if Rails.application.config.shibboleth_enabled %> - <% if resource.shibboleth_id.nil? || resource.shibboleth_id.length == 0 then %> - <%= link_to t("helpers.shibboleth_to_link_text"), user_omniauth_shibboleth_path, class: "a-orange" %> - <% else %> - <%= t("helpers.shibboleth_linked_text") %> - - <%= t("helpers.shibboleth_unlink_label")%> - +

    + <%= f.label :email, _('Email') + " *" %> + <%= f.email_field :email, as: :email, class: "input-medium has-tooltip", + "data-toggle": "tooltip", "data-trigger": "focus", + "title": _('Please enter your current password below when changing your email address.') %> +
    +
    + <%= f.label :firstname, _('First name')+ " *" %> + <%= f.text_field :firstname, as: :string, + id: "first_time_login_firstname", + autofocus: true, + class: "input-medium has-tooltip", + "data-toggle" => "tooltip", + "data-trigger" => "focus" , + "title" => _('Please enter your first name.') %> +
    +
    + <%= f.label :surname, _('Last name') + " *" %> + <%= f.text_field :surname, as: :string, id: "first_time_login_surname", + class: "input-medium has-tooltip", "data-toggle" => "tooltip", + "data-trigger" => "focus" , + "title" => _('Please enter your surname or family name.') %> +
    +
    + <%= f.label :org, _('Organisation') + " *" %> + <%= render partial: "shared/accessible_combobox", + locals: {name: "#{resource_name}[org_name]", + id: "#{resource_name}_org_name", + default_selection: @default_org, + models: @orgs, + attribute: 'name', + classes: 'fixed-width-large'} %> +
    + + <% if MANY_LANGUAGES %> +
    + <% lang = current_user.language.nil? ? FastGettext.default_locale : current_user.language.abbreviation %> + <%= f.label :language, _('Language') %> + +
    <% end %> - <% end %> -

    -
    -
    -
    -

    - <%= raw t("helpers.edit_password_info")%> -

    - - <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> -
    <%= t('custom_devise.waiting_for_confirmation') %><%= resource.unconfirmed_email %>
    - <% end %> - - - - - - - - - - - - -
    <%= t("helpers.current_password") %> - <%= f.password_field :current_password, as: :password %> -
    <%= t("helpers.new_password") %><%= f.password_field :password, as: :password, autocomplete: "off" %> -
    <%= t("helpers.password_conf") %><%= f.password_field :password_confirmation, as: :password, autocomplete: "off" %>
    -
    - <%= f.submit t("helpers.submit.save"), class: "btn btn-primary" %> - <%= link_to t("helpers.submit.cancel"), :back, class: "btn btn-primary" %> -
    + + <% @identifier_schemes.each do |scheme| %> +
    + +
    + <%= render partial: 'external_identifier', + locals: {scheme: scheme, + id: current_user.identifier_for(scheme)} %> +
    +
    + <% end %> + + <% unless @user.api_token.blank? %> +
    + <%= f.label :api_token, _('API token') %><%= @user.api_token %> +
    +
    + <%= link_to( _('How to use the API'), controller: "token_permission_types", action: "index")%> +
    + <% end %> + +
    + + <%= _('If you would like to change your password please complete the following fields.') %> + +
    + <%= f.label :current_password, _('Current password') %> + <%= f.password_field :current_password, as: :password, class: 'input-medium' %> +
    + +
    + <%= f.label :password, _('New password') %> + <%= f.password_field :password, as: :password, autocomplete: "off", class: 'input-medium' %> +
    + +
    + <%= f.label :password_confirmation, _('Password confirmation') %> + <%= f.password_field :password_confirmation, as: :password, autocomplete: "off", + class: 'input-medium' %> +
    + +
    + + +
    +
    + <% end %> -
    -
    - - - - diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb index 5406165..0c689be 100644 --- a/app/views/devise/registrations/new.html.erb +++ b/app/views/devise/registrations/new.html.erb @@ -1,7 +1,7 @@ -

    <%= t('helpers.sign_up') %>

    -<% unless session[:shibboleth_data].nil? %> +

    <%= _('Create account') %>

    +<% unless session["devise.shibboleth_data"].nil? %>

    - <%= raw t('helpers.sign_up_shibboleth_alert_text_html')%> + <%= (_("%{application_name} doesn't recognise your institutional credentials - either you haven't created an account with us or you haven't linked these details to your existing account.
    * If you do not have an account with %{application_name}, please complete the form below.
    * If you have an account with %{application_name}, please Sign in so we can link your account to your institutional credentials.
    Once you have created and/or linked your account, you'll be able to sign in with your institutional credentials directly.") % { :application_name => Rails.configuration.branding[:application][:name] }).html_safe %>

    <% cookies[:show_shib_link] = { value: 'show_shib_link', expires: 3.hours.from_now } %> <% end %> @@ -10,4 +10,4 @@
    <%= render :partial => 'shared/register_form', locals: {extended: true} %> -
    \ No newline at end of file +
    diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 95c5cf1..90556a7 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -1,15 +1,15 @@ -

    <%= t("helpers.sign_in") %>

    +

    <%= _('Sign in') %>

    <%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
    - + - + @@ -24,7 +24,7 @@
    <%= t("helpers.email") %><%= _('Email') %> <%= f.email_field :email, :autofocus => true %>
    <%= t("helpers.password") %><%= _('Password') %> <%= f.password_field :password %>
    - <%= f.submit t("helpers.sign_in"), :class => "btn btn-primary" %> + <%= f.submit _('Sign in'), :class => "btn btn-primary" %>
    <% end %> diff --git a/app/views/devise/shared/_links.erb b/app/views/devise/shared/_links.erb index 44a1965..3469473 100644 --- a/app/views/devise/shared/_links.erb +++ b/app/views/devise/shared/_links.erb @@ -1,13 +1,13 @@ <%- if devise_mapping.recoverable? && controller_name != 'passwords' %> - <%= link_to t('helpers.forgot_password'), new_password_path(resource_name), :class => "a-orange"%>
    + <%= link_to _('Forgot your password?'), new_password_path(resource_name), :class => "a-orange"%>
    <% end -%> <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> - <%= link_to t('helpers.no_pass_instructions'), new_confirmation_path(resource_name), :class => "a-orange"%>
    + <%= link_to _("Didn't receive confirmation instructions?"), new_confirmation_path(resource_name), :class => "a-orange"%>
    <% end -%> <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> - <%= link_to t('helpers.no_unlock_instructions'), new_unlock_path(resource_name), :class => "a-orange" %>
    + <%= link_to _("Didn't receive unlock instructions?"), new_unlock_path(resource_name), :class => "a-orange" %>
    <% end -%> <%#- if devise_mapping.omniauthable? %> diff --git a/app/views/guidance_groups/admin_edit.html.erb b/app/views/guidance_groups/admin_edit.html.erb index f81dbfc..4e9b870 100644 --- a/app/views/guidance_groups/admin_edit.html.erb +++ b/app/views/guidance_groups/admin_edit.html.erb @@ -2,10 +2,10 @@ <% javascript 'admin.js' %>

    - <%= t('org_admin.guidance.guidance_group_label') %> + <%= _('Guidance group') %>
    - <%= link_to t("org_admin.guidance.view_all_guidance"), + <%= link_to _('View all guidance'), admin_index_guidance_path, class: 'btn btn-primary' %>
    @@ -20,7 +20,7 @@ - + - - <% if @guidance_group.published == true then %> - - - - - <% end %> - - + + + + + + @@ -65,14 +62,14 @@
    - <%= f.submit t('helpers.submit.save'), class: 'btn btn-primary' %> + <%= f.submit _('Save'), class: 'btn btn-primary' %> <% if @guidance_group.published == false then %> - <%= f.submit t('helpers.submit.publish'), name: "save_publish", class: "btn btn-primary" %> + <%= f.submit _('Publish'), name: "save_publish", class: "btn btn-primary" %> <% end %> - <%= link_to t('helpers.submit.cancel'), :back, class: 'btn cancel' %> + <%= link_to _('Cancel'), :back, class: 'btn cancel' %>

    <% end %> - \ No newline at end of file + diff --git a/app/views/guidance_groups/admin_new.html.erb b/app/views/guidance_groups/admin_new.html.erb index 712cf83..2c466cb 100644 --- a/app/views/guidance_groups/admin_new.html.erb +++ b/app/views/guidance_groups/admin_new.html.erb @@ -2,10 +2,10 @@ <% javascript 'admin.js' %>

    - <%= t("org_admin.guidance.guidance_group_label") %> + <%= _('Guidance group') %>
    - <%= link_to t("org_admin.guidance.view_all_guidance"), + <%= link_to _('View all guidance'), admin_index_guidance_path, class: "btn btn-primary" %>
    @@ -20,22 +20,22 @@

    <%= t('org_admin.guidance_group.name_label') %><%= _('Name') %>
    <%= f.text_field :name, @@ -29,33 +29,30 @@
    - <%= link_to(image_tag('help_button.png'), '#', class: 'guidance_group_title_popover', rel: "popover", 'data-html' => "true", 'data-content' => t('org_admin.guidance_group.title_help_text_html')) %> + <%= link_to(image_tag('help_button.png'), '#', "data-toggle": "popover", rel: "popover", 'data-html' => "true", 'data-content' => _('Add an appropriate name for your guidance group. This name will be used to tell the end user where the guidance has come from. It will be appended to text identifying the theme e.g. "[guidance group name]: guidance on data sharing" so we suggest you just use the institution or department name.')) %>
    <%= t('org_admin.templates.published_label') %> -
    - <%= f.check_box :published %> -
    -
    - -
    -
    <%= t('org_admin.guidance_group.subset') %><%= _('Published') %>
    - <%= f.check_box :optional_subset %> <%= t('org_admin.guidance_group.subset_eg') %> + <%= f.check_box :published %>
    - <%= link_to(image_tag('help_button.png'), '#', class: 'guidance_group_subset_popover', rel: "popover", 'data-html' => "true", 'data-content' => t('org_admin.guidance_group.subset_option_help_text')) %> + +
    +
    <%= _('Optional subset') %> +
    + <%= f.check_box :optional_subset %> <%= _('e.g. School/ Department') %> +
    +
    + <%= link_to(image_tag('help_button.png'), '#', "data-toggle": "popover", rel: "popover", 'data-html' => "true", 'data-content' => _("If the guidance is only meant for a subset of users e.g. those in a specific college or institute, check this box. Users will be able to select to display this subset guidance when answering questions in the 'create plan' wizard.")) %>
    - + - + @@ -43,8 +43,8 @@
    - <%= f.submit t("helpers.submit.save"), name: "draft", class: "btn btn-primary" %> - <%= link_to t("helpers.submit.cancel"), :back, class: "btn cancel btn-secondary" %> + <%= f.submit _('Save'), name: "draft", class: "btn btn-primary" %> + <%= link_to _('Cancel'), :back, class: "btn cancel btn-secondary" %>

    <% end %> diff --git a/app/views/guidance_groups/admin_show.html.erb b/app/views/guidance_groups/admin_show.html.erb index fba06cc..d73054d 100644 --- a/app/views/guidance_groups/admin_show.html.erb +++ b/app/views/guidance_groups/admin_show.html.erb @@ -1,11 +1,11 @@ <%= stylesheet_link_tag "admin" %>

    - <%= t("org_admin.guidance.guidance_group_label") %> + <%= _('Guidance group') %>
    - <%= link_to t("org_admin.guidance.view_all_guidance"), + <%= link_to _('View all guidance'), admin_index_guidance_path, class: "btn btn-primary" %>
    @@ -19,43 +19,43 @@

    <%= t('org_admin.guidance_group.name_label') %><%= _('Name') %>
    <%= f.text_field :name, as: :string, class: "text_field" %>
    - <%= link_to( image_tag("help_button.png"), "#", class: 'guidance_group_title_popover', rel: "popover", 'data-html' => "true", 'data-content' => t("org_admin.guidance_group.title_help_text_html"))%> + <%= link_to( image_tag("help_button.png"), "#", "data-toggle": "popover", rel: "popover", 'data-html' => "true", 'data-content' => _('Add an appropriate name for your guidance group. This name will be used to tell the end user where the guidance has come from. It will be appended to text identifying the theme e.g. "[guidance group name]: guidance on data sharing" so we suggest you just use the institution or department name.'))%>
    <%= t('org_admin.guidance_group.subset') %><%= _('Optional subset') %>
    - <%= f.check_box :optional_subset %> <%= t('org_admin.guidance_group.subset_eg') %> + <%= f.check_box :optional_subset %> <%= _('e.g. School/ Department') %>
    - <%= link_to( image_tag('help_button.png'), '#', class: 'guidance_group_subset_popover', rel: "popover", 'data-html' => "true", 'data-content' => t('org_admin.guidance_group.subset_option_help_text'))%> + <%= link_to( image_tag('help_button.png'), '#', "data-toggle": "popover", rel: "popover", 'data-html' => "true", 'data-content' => _("If the guidance is only meant for a subset of users e.g. those in a specific college or institute, check this box. Users will be able to select to display this subset guidance when answering questions in the 'create plan' wizard."))%>
    - + - + - + - + - +
    <%= t("org_admin.guidance_group.name_label") %><%= _('Name') %> <%= raw @guidance_group.name %>
    <%= t('org_admin.templates.published_label') %><%= _('Published') %> <% if @guidance_group.published.nil? || !@guidance_group.published then %> - <%= t("helpers.no_label") %> + <%= _('No') %> <% else %> - <%= t("helpers.yes_label") %> + <%= _('Yes') %> <% end %>
    <%= t("org_admin.guidance_group.subset") %><%= _('Optional subset') %> <% if @guidance_group.optional_subset.nil? || !@guidance_group.optional_subset then %> - <%= t('helpers.no_label') %> + <%= _('No') %> <% else %> - <%= t('helpers.yes_label') %> + <%= _('Yes') %> <% end %>
    <%= t("org_admin.guidance.created") %><%= _('Created') %> <%= l @guidance_group.created_at.to_date, formats: :short %>
    <%= t("org_admin.guidance.last_updated") %><%= _('Last updated') %> <%= l @guidance_group.updated_at.to_date, formats: :short %>
    - <%= link_to t("helpers.submit.edit"), admin_edit_guidance_group_path(@guidance_group.id), class: "btn btn-primary" %> - <%= link_to t("helpers.submit.back"), :back, class: "btn cancel" %> + <%= link_to _('Edit'), admin_edit_guidance_group_path(@guidance_group.id), class: "btn btn-primary" %> + <%= link_to _('Back'), :back, class: "btn cancel" %>

    diff --git a/app/views/guidances/_add_guidance.html.erb b/app/views/guidances/_add_guidance.html.erb new file mode 100644 index 0000000..ca49a90 --- /dev/null +++ b/app/views/guidances/_add_guidance.html.erb @@ -0,0 +1,83 @@ + +
    + <%= form_for :guidance, url: {action: "admin_create"}, html: {id: "new_guidance_form"} do |f| %> + + + + + + + + + + + + + + + + + +
    <%= _('Text') %> +
    + <%= text_area_tag("guidance-text", "", class: "tinymce") %> +
    +
    + <%= link_to( image_tag("help_button.png"), "#", "data-toggle": "popover", rel: "popover", "data-html" => "true", "data-content" => _('Enter your guidance here. You can include links where needed.'))%> +
    +
    +
    <%= _('Should this guidance apply:') %> + +
    <%= _('Published') %> +
    + <%= f.check_box :published , as: :check_boxes %> +
    +
    <%= _('Guidance group') %> +
    + <%= f.collection_select(:guidance_group_ids, + GuidanceGroup.where(org_id: current_user.org_id).order("name ASC"), + :id, :name, {prompt: false, include_blank: _('None')}, {multiple: false})%> +
    +
    + <%= link_to( image_tag("help_button.png"), "#", "data-toggle": "popover", rel: "popover", "data-html" => "true", "data-content" => _('Select which group this guidance relates to.'))%> +
    +
    +
    + + + +
    + <%= _('Save')%> + + <%= link_to _('Cancel'), :back, class: "btn cancel" %> +
    + +
    + <%= tinymce :content_css => asset_path('application.css') %> + <% end %> +
    + + + + + \ No newline at end of file diff --git a/app/views/guidances/_edit_guidance.html.erb b/app/views/guidances/_edit_guidance.html.erb new file mode 100644 index 0000000..ffae58d --- /dev/null +++ b/app/views/guidances/_edit_guidance.html.erb @@ -0,0 +1,26 @@ + +<%= form_for(suggested_answer, url: admin_update_suggested_answer_path(suggested_answer), html: { method: :put}) do |f| %> + <%= f.hidden_field :org_id, value: current_user.org_id %> + + + + + + +
    <%= _('Suggested answer/ Example')%> +
      +
    • <%= f.select :is_example, {_('Example Answer') => true, _('Suggested answer') => false} %>
    • +
    • <%= f.text_area :text, rows: 5 %>
    • +
    +
    +
    + + +
    + <%= f.submit _('Save'), class: "btn btn-primary" %> + <%= link_to _('Delete'), admin_destroy_suggested_answer_path(id: suggested_answer.id), + confirm: _("You are about to delete a suggested answer/ example for '%{question_text}'. Are you sure?") % { :question_text => question.text }, method: :delete, class: "btn btn-primary"%> + <%= hidden_field_tag :question_id, question.id, class: "question_id" %> + <%= link_to _('Cancel'), "#", class: "btn cancel cancel_edit_suggested_answer" %> +
    +<%end%> diff --git a/app/views/guidances/_guidance_display.html.erb b/app/views/guidances/_guidance_display.html.erb new file mode 100644 index 0000000..b3bce3b --- /dev/null +++ b/app/views/guidances/_guidance_display.html.erb @@ -0,0 +1,36 @@ + + +
    +
    + <% if !question.get_guidance_annotation(current_user.org).nil? && question.get_guidance_annotation(current_user.org) != "" %> +
    + +
    +
    <%= raw question.get_guidance_annotation(current_user.org).text %>
    +
    +
    + <% end %> + + <% question.guidance_for_org(current_user.org).each_pair do |title,guidance| %> +
    + +
    +
    <%= raw guidance.text %>
    +
    +
    + <% end %> +
    + +
    diff --git a/app/views/guidances/admin_edit.html.erb b/app/views/guidances/admin_edit.html.erb index 055334d..769fc6e 100644 --- a/app/views/guidances/admin_edit.html.erb +++ b/app/views/guidances/admin_edit.html.erb @@ -2,13 +2,13 @@ <% javascript 'admin.js' %>

    - <%= t('org_admin.guidance_label') %> + <%= _('Guidance') %>
    - <%= link_to t("org_admin.guidance.add_guidance"), + <%= link_to _('Add guidance'), admin_new_guidance_path, class: 'btn btn-primary' %> - <%= link_to t("org_admin.guidance.view_all_guidance"), + <%= link_to _('View all guidance'), admin_index_guidance_path, class: 'btn btn-primary' %>
    @@ -23,64 +23,49 @@ - - + - - + - + - +
    <%= t('org_admin.guidance.text_label') %>
    +
    <%= _('Text') %> +
    <%= text_area_tag("guidance-text", @guidance.text, class: "tinymce") %>
    - <%= link_to( image_tag('help_button.png'), '#', class: 'guidance_text_popover', rel: "popover", 'data-html' => "true", 'data-content' => t('org_admin.guidance.text_help_text_html'))%> + <%= link_to( image_tag('help_button.png'), '#', "data-toggle": "popover", rel: "popover", 'data-html' => "true", 'data-content' => _('Enter your guidance here. You can include links where needed.'))%>
    <%= t('org_admin.guidance.by_theme_or_by_question') %>
    - <% if !@guidance.question_id.nil? then %> - <% select_op = 2 %> - <% else %> - <% select_op = 1%> - <% end %> - <%= hidden_field 'select_op', value: select_op, id: 'edit_guid_ques_flag' %> - - <%= select_tag "g_options", options_for_select({t('org_admin.guidance.by_themes_label') => 1, - t('org_admin.guidance.by_question_label') => 2}, select_op) %> -
    -
    - <%= link_to( image_tag('help_button.png'), '#', class: 'guidance_apply_to_popover', rel: "popover", 'data-html' => "true", 'data-content' => t('org_admin.guidance.apply_to_help_text_html'))%> -
    -
    - -
    <%= _('Themes') %> +
    <%= f.collection_select(:theme_ids, @themes, :id, :title, {prompt: false, include_blank: 'None'}, {multiple: true})%>
    - <%= link_to( image_tag('help_button.png'), '#', class: 'guidance_by_themes_popover', rel: "popover", 'data-html' => "true", 'data-content' => t('org_admin.guidance.by_themes_help_text_html'))%> + <%= link_to( image_tag('help_button.png'), '#', "data-toggle": "popover", rel: "popover", 'data-html' => "true", 'data-content' => _('Select which theme(s) this guidance relates to.'))%>
    -
    <%= t('org_admin.guidance.published') %><%= _('Published') %>
    <%= f.check_box :published , as: :check_boxes%>
    <%= t('org_admin.guidance.guidance_group_label') %><%= _('Guidance group') %>
    <%= f.collection_select(:guidance_group_id, @guidance_groups, :id, :name, {prompt: false, include_blank: 'None'}, {multiple: false})%>
    - <%= link_to( image_tag('help_button.png'), '#', class: 'guidance_group_select_popover', rel: "popover", 'data-html' => "true", 'data-content' => t('org_admin.guidance.guidance_group_select_help_text_html'))%> + <%= link_to( image_tag('help_button.png'), '#', "data-toggle": "popover", rel: "popover", 'data-html' => "true", 'data-content' => _('Select which group this guidance relates to.'))%>
    @@ -92,12 +77,12 @@
    - <%= t('helpers.submit.save')%> - <%= link_to t('helpers.submit.cancel'), :back, class: 'btn cancel' %> + <%= _('Save')%> + <%= link_to _('Cancel'), :back, class: 'btn cancel' %>

    - <%= tinymce content_css: asset_path('application.css') %> + <%= tinymce :content_css => asset_path('application.css') %> <%end%> @@ -106,12 +91,12 @@ diff --git a/app/views/guidances/admin_index.html.erb b/app/views/guidances/admin_index.html.erb index a660213..6010b35 100644 --- a/app/views/guidances/admin_index.html.erb +++ b/app/views/guidances/admin_index.html.erb @@ -3,15 +3,15 @@

    - <%= t("org_admin.guidance_group.guidance_group_list") %> + <%= _('Guidance group list') %>

    - <%= raw t("org_admin.guidance_group.guidance_group_text_html")%> + <%= raw _("

    First create a guidance group. This could be institution wide or a subset e.g. a particular College / School, Institute or department. When you create guidance you'll be asked to assign it to a guidance group.

    ")%>
    - <%= link_to t("org_admin.guidance_group.add_guidance_group"), admin_new_guidance_group_path(), class: "btn btn-primary" %> + <%= link_to _('Add guidance group'), admin_new_guidance_group_path(), class: "btn btn-primary" %>
    @@ -20,11 +20,11 @@ - - - - - + + + + + @@ -35,16 +35,16 @@ @@ -52,9 +52,9 @@ <%= l guidance_gr.updated_at.to_date, formats: :short %> <% end %> @@ -66,16 +66,16 @@

    - <%= t("org_admin.guidance.guidance_list") %> + <%= _('Guidance list') %>

    - <%= raw t("org_admin.guidance.guidance_text_html")%> + <%= raw _('

    You can write pieces of guidance to be displayed by theme (e.g. generic guidance on storage and backup that should present across the board). Writing generic guidance by theme saves you time and effort as your advice will be automatically displayed across all templates rather than having to write guidance to accompany each.

    If you do have a need to provide guidance for specific funders that would not be useful to a wider audience (e.g. if you have specific instructions for applicants to BBSRC for example), you can do so by adding guidance to a specific question when you edit your template.

    ')%>
    - <%= link_to t("org_admin.guidance.add_guidance"), + <%= link_to _('Add guidance'), admin_new_guidance_path(), class: "btn btn-primary" %>
    @@ -88,12 +88,11 @@
    <%= t("org_admin.guidance_group.name_label") %><%= t("org_admin.guidance.published") %><%= t("org_admin.guidance_group.subset") %><%= t("org_admin.guidance.last_updated") %><%= t("org_admin.guidance.actions") %><%= _('Name') %><%= _('Published') %><%= _('Optional subset') %><%= _('Last updated') %><%= _('Actions') %>
    <% if guidance_gr.published.nil? || guidance_gr.published == false then%> - <%= t("helpers.no_label")%> + <%= _('No')%> <% else %> - <%= t("helpers.yes_label")%> + <%= _('Yes')%> <% end %> <% if guidance_gr.optional_subset.nil? || guidance_gr.optional_subset == false then%> - <%= t("helpers.no_label")%> + <%= _('No')%> <% else %> - <%= t("helpers.yes_label")%> + <%= _('Yes')%> <% end %> - <%= link_to t("helpers.view"), admin_show_guidance_group_path(guidance_gr), class: "dmp_table_link"%>
    - <%= link_to t("helpers.submit.edit"), admin_edit_guidance_group_path(guidance_gr), class: "dmp_table_link"%>
    - <%= link_to t("helpers.submit.delete"), admin_destroy_guidance_group_path(guidance_gr), data: {confirm: t("org_admin.guidance_group.delete_message", guidance_group_name: guidance_gr.name )}, method: :delete, class: "dmp_table_link"%> + <%= link_to _('View'), admin_show_guidance_group_path(guidance_gr), class: "dmp_table_link"%>
    + <%= link_to _('Edit'), admin_edit_guidance_group_path(guidance_gr), class: "dmp_table_link"%>
    + <%= link_to _('Delete'), admin_destroy_guidance_group_path(guidance_gr), data: {confirm: _("You are about to delete '%{guidance_group_name}'. This will affect guidance. Are you sure?") % { :guidance_group_name => guidance_gr.name }}, method: :delete, class: "dmp_table_link"%>
    - - - - - - + + + + + @@ -114,15 +113,6 @@ - <% end %> - <% if !guidance.question_id.nil? then %> - - <% else %> - - <% end %> <% if guidance.guidance_group.present? then %> <% end %> diff --git a/app/views/guidances/admin_new.html.erb b/app/views/guidances/admin_new.html.erb index 43e620c..a67fe0e 100644 --- a/app/views/guidances/admin_new.html.erb +++ b/app/views/guidances/admin_new.html.erb @@ -2,10 +2,10 @@ <% javascript 'admin.js' %>

    - <%= t('org_admin.guidance.new_label') %> + <%= _('New guidance') %>
    - <%= link_to t("org_admin.guidance.view_all_guidance"), + <%= link_to _('View all guidance'), admin_index_guidance_path, class: 'btn btn-primary' %>
    @@ -18,75 +18,51 @@ <%= form_for :guidance, url: {action: 'admin_create'}, html: {id: 'new_guidance_form'} do |f| %>

    <%= t("org_admin.guidance.text_label") %><%= t("org_admin.guidance.themes_label") %><%= t("org_admin.guidance.question_label") %><%= t("org_admin.guidance.guidance_group_label") %><%= t("org_admin.guidance.last_updated") %><%= t("org_admin.guidance.actions") %><%= _('Text') %><%= _('Themes') %><%= _('Guidance group') %><%= _('Last updated') %><%= _('Actions') %>
    - <%= raw guidance.question.text.truncate(70, omission: t('helpers.truncate_continued')) %> - - - - <%= guidance.guidance_group.name %> @@ -136,10 +126,10 @@ <%= l guidance.updated_at.to_date, formats: :short %> - <%= link_to t("helpers.view"), admin_show_guidance_path(guidance), class: "dmp_table_link"%>
    - <%= link_to t("helpers.submit.edit"), admin_edit_guidance_path(guidance), class: "dmp_table_link"%>
    - <%= link_to t("helpers.submit.delete"), admin_destroy_guidance_path(guidance), - data: {confirm: t("org_admin.guidance.delete_message_html", guidance_summary: truncate(sanitize(guidance.text,tags: %w(br a)), length: 20 , omission: t('helpers.truncate_continued')) )}, method: :delete, class: "dmp_table_link"%> + <%= link_to _('View'), admin_show_guidance_path(guidance), class: "dmp_table_link"%>
    + <%= link_to _('Edit'), admin_edit_guidance_path(guidance), class: "dmp_table_link"%>
    + <%= link_to _('Delete'), admin_destroy_guidance_path(guidance), + data: {confirm: _("You are about to delete '%{guidance_summary}'. Are you sure?") % { :guidance_summary => truncate(sanitize(guidance.text,tags: %w(br a)), length: 20 , omission: _('... (continued)'))} }, method: :delete, class: "dmp_table_link"%>
    - - + - - + - + - + +
    <%= t('org_admin.guidance.text_label') %>
    +
    <%= _('Text') %> +
    <%= text_area_tag("guidance-text", "", class: "tinymce") %>
    - <%= link_to( image_tag('help_button.png'), '#', class: 'guidance_text_popover', rel: "popover", 'data-html' => "true", 'data-content' => t('org_admin.guidance.text_help_text_html'))%> + <%= link_to( image_tag('help_button.png'), '#', "data-toggle": "popover", rel: "popover", 'data-html' => "true", 'data-content' => _('Enter your guidance here. You can include links where needed.'))%>
    <%= t('org_admin.guidance.by_theme_or_by_question') %>
    - <%= select_tag "g_options", options_for_select([[t('org_admin.guidance.by_themes_label'), 1], - [t('org_admin.guidance.by_question_label'), 2]]) %> -
    -
    - <%= link_to( image_tag('help_button.png'), '#', class: 'guidance_apply_to_popover', rel: "popover", 'data-html' => "true", 'data-content' => t('org_admin.guidance.apply_to_help_text_html'))%> -
    -
    - -
    <%= _('Themes') %> +
    <%= f.collection_select(:theme_ids, @themes, :id, :title, {prompt: false, include_blank: 'None'}, {multiple: true})%>
    - <%= link_to( image_tag('help_button.png'), '#', class: 'guidance_by_themes_popover', rel: "popover", 'data-html' => "true", 'data-content' => t('org_admin.guidance.by_themes_help_text_html'))%> + <%= link_to( image_tag('help_button.png'), '#', "data-toggle": "popover", rel: "popover", 'data-html' => "true", 'data-content' => _('Select which theme(s) this guidance relates to.'))%>
    -
    - +
    <%= t('org_admin.guidance.published') %><%= _('Published') %>
    <%= f.check_box :published , as: :check_boxes%>
    - <%= link_to( image_tag('help_button.png'), '#', class: 'guidance_group_subset_popover', rel: "popover", 'data-html' => "true", 'data-content' => t('org_admin.guidance.guidance_group_published_help_text_html'))%> + <%= link_to( image_tag('help_button.png'), '#', "data-toggle": "popover", rel: "popover", 'data-html' => "true", 'data-content' => _("Check this box when you are ready for this guidance to appear on user's plans."))%>
    <%= t('org_admin.guidance.guidance_group_label') %><%= _('Guidance group') %>
    <%= f.collection_select(:guidance_group_id, @guidance_groups, :id, :name, {prompt: false, include_blank: 'None'}, {multiple: false})%>
    - <%= link_to( image_tag('help_button.png'), '#', class: 'guidance_group_select_popover', rel: "popover", 'data-html' => "true", 'data-content' => t('org_admin.guidance.guidance_group_select_help_text_html'))%> + <%= link_to( image_tag('help_button.png'), '#', "data-toggle": "popover", rel: "popover", 'data-html' => "true", 'data-content' => _('Select which group this guidance relates to.'))%>
    @@ -97,13 +73,13 @@
    - <%= t("helpers.submit.save")%> + <%= _('Save')%> - <%= link_to t('helpers.submit.cancel'), :back, class: 'btn cancel' %> + <%= link_to _('Cancel'), :back, class: 'btn cancel' %>

    - <%= tinymce content_css: asset_path('application.css') %> + <%= tinymce :content_css => asset_path('application.css') %> <%end%> @@ -112,12 +88,12 @@ \ No newline at end of file diff --git a/app/views/guidances/admin_show.html.erb b/app/views/guidances/admin_show.html.erb index 14356f8..4742641 100644 --- a/app/views/guidances/admin_show.html.erb +++ b/app/views/guidances/admin_show.html.erb @@ -1,14 +1,14 @@ <%= stylesheet_link_tag "admin" %>

    - <%= t("org_admin.guidance_label") %> + <%= _('Guidance') %>
    - <%= link_to t("org_admin.guidance.add_guidance"), + <%= link_to _('Add guidance'), admin_new_guidance_path, class: "btn btn-primary" %> - <%= link_to t("org_admin.guidance.view_all_guidance"), + <%= link_to _('View all guidance'), admin_index_guidance_path, class: "btn btn-primary" %>
    @@ -22,52 +22,41 @@ - + - <% if @guidance.themes !=[] then %> - - - - - <% end %> - <% if !@guidance.question_id.nil? %> - - - - - <% end %> - + + + + + - + - + - +
    <%= t("org_admin.guidance.text_label") %><%= _('Text') %> <%= raw @guidance.text %>
    <%= t("org_admin.guidance.themes_label") %><% @guidance.themes.each do |th|%> - <%= th.title %> - <% end %> -
    <%= t("org_admin.guidance.question_label") %><%= raw @guidance.question.text %>
    <%= t("org_admin.guidance.guidance_group_label") %><%= _('Themes') %><%= @guidance.themes.order(:title).collect{|t| t.title}.join(', ') %>
    <%= _('Guidance group') %> <%= @guidance.guidance_group.name %>
    <%= t("org_admin.guidance.published") %><%= _('Published') %> <%if @guidance.published == false || @guidance.published.nil? then%> - <%= t("helpers.no_label")%> + <%= _('No')%> <% else %> - <%= t("helpers.yes_label")%> + <%= _('Yes')%> <% end %>
    <%= t("org_admin.guidance.created") %><%= _('Created') %> <%= l @guidance.created_at.to_date, formats: :short %>
    <%= t("org_admin.guidance.last_updated") %><%= _('Last updated') %> <%= l @guidance.updated_at.to_date, formats: :short %>
    - <%= link_to t("helpers.submit.edit"), admin_edit_guidance_path(@guidance.id), class: "btn btn-primary"%> - <%= link_to t("helpers.submit.back"), :back, class: "btn cancel" %> + <%= link_to _('Edit'), admin_edit_guidance_path(@guidance.id), class: "btn btn-primary"%> + <%= link_to _('Back'), :back, class: "btn cancel" %>

    diff --git a/app/views/guidances/update_phases.js.erb b/app/views/guidances/update_phases.js.erb deleted file mode 100644 index 3be4344..0000000 --- a/app/views/guidances/update_phases.js.erb +++ /dev/null @@ -1,5 +0,0 @@ -$('#phases_select').html("<%= escape_javascript(options_for_select(@phases)) %>"); -$('#versions_select').html("<%= escape_javascript(options_for_select(@versions)) %>"); -$('#sections_select').html("<%= escape_javascript(options_for_select(@sections)) %>"); -$('#questions_select').html("<%= escape_javascript(options_for_select(@questions)) %>"); - \ No newline at end of file diff --git a/app/views/guidances/update_questions.js.erb b/app/views/guidances/update_questions.js.erb deleted file mode 100644 index 56f5ceb..0000000 --- a/app/views/guidances/update_questions.js.erb +++ /dev/null @@ -1 +0,0 @@ -$('#questions_select').html("<%= escape_javascript(options_for_select(@questions)) %>hiya"); \ No newline at end of file diff --git a/app/views/guidances/update_sections.js.erb b/app/views/guidances/update_sections.js.erb deleted file mode 100644 index 710716c..0000000 --- a/app/views/guidances/update_sections.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -$('#sections_select').html("<%= escape_javascript(options_for_select(@sections)) %>"); -$('#questions_select').html("<%= escape_javascript(options_for_select(@questions)) %>"); \ No newline at end of file diff --git a/app/views/guidances/update_versions.js.erb b/app/views/guidances/update_versions.js.erb deleted file mode 100644 index f8bcf54..0000000 --- a/app/views/guidances/update_versions.js.erb +++ /dev/null @@ -1,3 +0,0 @@ -$('#versions_select').html("<%= escape_javascript(options_for_select(@versions)) %>"); -$('#sections_select').html("<%= escape_javascript(options_for_select(@sections)) %>"); -$('#questions_select').html("<%= escape_javascript(options_for_select(@questions)) %>"); \ No newline at end of file diff --git a/app/views/home/index.html.erb b/app/views/home/index.html.erb index 40441b0..92bfeb2 100644 --- a/app/views/home/index.html.erb +++ b/app/views/home/index.html.erb @@ -38,9 +38,9 @@
    - <%= _('Sign up') %> + <%= _('Create account') %>

    - <%= _('New to %{application_name}? Sign up today.') % {:application_name => Rails.configuration.branding[:application][:name]} %> + <%= _('New to %{application_name}? Create an account today.') % {:application_name => Rails.configuration.branding[:application][:name]} %>

    diff --git a/app/views/layouts/_footer.html.erb b/app/views/layouts/_footer.html.erb index 897d824..4866e06 100644 --- a/app/views/layouts/_footer.html.erb +++ b/app/views/layouts/_footer.html.erb @@ -14,8 +14,8 @@
    @@ -33,11 +33,11 @@ -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/layouts/_navigation.html.erb b/app/views/layouts/_navigation.html.erb index 5400e0d..57bfe0b 100644 --- a/app/views/layouts/_navigation.html.erb +++ b/app/views/layouts/_navigation.html.erb @@ -1,4 +1,3 @@ - diff --git a/app/views/layouts/_signin_signout.html.erb b/app/views/layouts/_signin_signout.html.erb index e975dc6..ec99f37 100644 --- a/app/views/layouts/_signin_signout.html.erb +++ b/app/views/layouts/_signin_signout.html.erb @@ -12,7 +12,17 @@
  • <%= link_to _('Super admin area'), "/admin", class: "signIn_dropdown_link" %>
  • <% end %> <% if current_user.can_org_admin? && !current_user.org_id.nil? %> -
  • <%= link_to _("Admin area"), admin_index_template_path(current_user.org_id), class: "signIn_dropdown_link" %>
  • + <% if current_user.can_modify_org_details? && current_user.org.abbreviation.blank? %> +
  • <%= link_to _("Admin area"), admin_show_org_path(current_user.org_id), class: "signIn_dropdown_link" %>
  • + <% elsif current_user.can_modify_templates?%> +
  • <%= link_to _("Admin area"), admin_index_template_path(current_user.org_id), class: "signIn_dropdown_link" %>
  • + <% elsif current_user.can_modify_guidance? %> +
  • <%= link_to _("Admin area"), admin_index_guidance_path(current_user.org_id), class: "signIn_dropdown_link" %>
  • + <% elsif current_user.can_modify_org_details? %> +
  • <%= link_to _("Admin area"), admin_show_org_path(current_user.org_id), class: "signIn_dropdown_link" %>
  • + <% elsif current_user.can_grant_permissions? %> +
  • <%= link_to _("Admin area"), admin_index_users_path, class: "signIn_dropdown_link" %>
  • + <% end %> <% end %>
  • <%= link_to _('Sign out'), destroy_user_session_path, method: :delete, class: "signIn_dropdown_link" %>
  • @@ -21,7 +31,7 @@
  • <% unless controller_name == "home" && action_name == "index" then %> <%= _('Sign in')%> / - <%= _('Sign up')%> + <%= _('Create account')%> <% else %> <%= raw " " %> <% end %> @@ -29,3 +39,7 @@ <% end %> + + diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index e8a3467..483511b 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -1,5 +1,5 @@ - + <%= _('%{application_name}') % { :application_name => Rails.configuration.branding[:application][:name] } %> <%= favicon_link_tag "favicon.ico" %> @@ -62,12 +62,14 @@ <%= render "layouts/header" %> + +
    <% if notice %> -

    <%= notice %>

    +

    <%= raw notice %>

    <% end %> <% if alert %> -

    <%= alert %>

    +

    <%= raw alert %>

    <% end %>
    diff --git a/app/views/notes/_add.html.erb b/app/views/notes/_add.html.erb new file mode 100644 index 0000000..2817b90 --- /dev/null +++ b/app/views/notes/_add.html.erb @@ -0,0 +1,24 @@ + + +<% + new_note = Note.new + questionid = question.id +%> + +<%= form_for( :new_note, + url: notes_path, + remote: true, + html: {method: :post, class: "add_note_form roadmap-form"}, + id: "new_note_form_#{questionid}") do |f| %> + <%= f.hidden_field :user_id, value: current_user.id %> + <%= f.hidden_field :question_id, value: questionid %> + <%= f.hidden_field :answer_id, value: answer.id %> + <%= f.hidden_field :plan_id, value: plan_id %> + +
    + <%= label_tag "#{questionid}new_note_text", _('Share note with collaborators') %> + <%= text_area_tag "#{questionid}new_note_text", nil, class: "tinymce" %> + <%= tinymce :content_css => asset_path('application.css') %> + +
    +<% end %> diff --git a/app/views/notes/_archive.html.erb b/app/views/notes/_archive.html.erb new file mode 100644 index 0000000..eae2154 --- /dev/null +++ b/app/views/notes/_archive.html.erb @@ -0,0 +1,20 @@ +<%= form_for(note, + url: archive_note_path(note), + remote: true, + class: "archive_note_form", + id: "archive_note_form_#{note.id}") do |f| %> + + <%= f.hidden_field :id, :value => note.id %> + <%= f.hidden_field :archived_by, :value => current_user.id %> + + <%= render :partial => "/notes/view", locals: {note: note} %> + +

    <%= _('Are you sure you want to remove this note?')%>

    + + +
    + <%= f.submit _('Remove'), onclick: "archive_note(#{note.id}, #{question_id})", :class => "btn btn-primary archive_comment_submit_button" %> + <%= link_to _('Cancel'), "#", onclick: "cancel_archive_note(#{note.id})", :class => "cancel_archive_comment btn cancel" %> +
    +
    +<% end %> diff --git a/app/views/notes/_edit.html.erb b/app/views/notes/_edit.html.erb new file mode 100644 index 0000000..17a75bc --- /dev/null +++ b/app/views/notes/_edit.html.erb @@ -0,0 +1,15 @@ + + +<%= form_for(note, + url: note_path(note), + remote: true, + html: {method: :put, class: "edit_note_form roadmap-form"}, + id: "edit_note_form_#{note.id}") do |f| %> + +
    + <%= f.hidden_field :id, :value => note.id %> + + <%= text_area_tag("#{note.id}_note_text".to_sym, note.text , class: "tinymce") %> + <%= f.submit _('Save'), :class => "form-submit edit_note_submit_button" %> +
    +<%end%> diff --git a/app/views/notes/_list.html.erb b/app/views/notes/_list.html.erb new file mode 100644 index 0000000..daf6a20 --- /dev/null +++ b/app/views/notes/_list.html.erb @@ -0,0 +1,85 @@ + + +<% if notes.count > 1 then%> + <% style_to_add = "height:150px; overflow-y:auto;" %> +<%else%> + <% style_to_add = "" %> +<%end%> + +
    + +
    + + + <% notes.each do |note|%> + + + + + <%end%> + +
    + <% user = note.user.name %> + <%= user %>
    + (<%= l note.updated_at, format: :custom %>) +
    + + <% if note.archived %> + + <% if note.archived_by == current_user.id %> + <%= _('Note removed by you')%> + <% else %> + <% archived_by_user = User.find(note.archived_by) %> + <%= _('Note removed by')%> <%= archived_by_user.name %> + <%end%> + + <%else%> + + <%= link_to _('View'),"#question-form-#{question_id}", onclick: "view_note_button(#{note.id}, #{question_id})", :class => "dmp_table_link view_comment_button" %> + + <% if current_user.id == note.user_id %> + <%= link_to _('Edit'),"#question-form-#{question_id}", onclick: "edit_note(#{note.id}, #{question_id})", :class => "dmp_table_link edit_comment_button" %> + <%= link_to _('Remove'),"#question-form-#{question_id}", onclick: "archive_note(#{note.id}, #{question_id})", :class => "dmp_table_link archive_comment_button" %> + <% end%> + + <% if plan.administerable_by?(current_user.id) && current_user.id != note.user_id %> + <%= hidden_field_tag :note_id, note.id, :class => "comment_id" %> + <%= link_to _('Remove'),"#question-form-#{question_id}", onclick: "archive_note(#{note.id}, #{question_id})", :class => "dmp_table_link archive_comment_button" %> + <% end%> + <%end%> + +
    +
    + +
    + + +<% notes_not_archived = notes.select { |n| n.archived.nil? } %> +<% latest_note = notes_not_archived.sort { |x,y| y.updated_at <=> x.updated_at }.first %> +<% if !latest_note.nil? then%> +
    + <%= render :partial => "/notes/view", locals: {note: latest_note} %> +
    +
    +<%end%> + +<%notes.each do |note|%> + + + + + + + + + +<%end%> diff --git a/app/views/notes/_view.html.erb b/app/views/notes/_view.html.erb new file mode 100644 index 0000000..0610f0c --- /dev/null +++ b/app/views/notes/_view.html.erb @@ -0,0 +1,11 @@ + +<% user = User.find(note.user_id) %> +
    +
    +
    +
      +
    • <%= _('Noted by:')%>

    • +
    • <%= user.name%> (<%= l note.updated_at, format: :custom %>)
    • +
    • <%= raw note.text %>
    • +
    +
    diff --git a/app/views/notes/archive.js.erb b/app/views/notes/archive.js.erb new file mode 100644 index 0000000..f2687fa --- /dev/null +++ b/app/views/notes/archive.js.erb @@ -0,0 +1,29 @@ + +// remove all tinymce explicitly or re-init will not work later +tinymce.remove(".tinymce"); + +// render the list of notes and invisible view and edit sections +<% listlabel = "#comment-question-area-#{@question.id}" %> +$("<%=listlabel%>").html( + "<%= escape_javascript( render partial: '/phases/note', locals: {question: @question, answer: @answer, plan: @plan } ) %>" +); + +// TODO: this duplicates what is in the .yml file +// DRY it out! +tinymce.init({ + selector: ".tinymce", + statusbar: false, + menubar: false, + toolbar: "bold italic | bullist numlist | link | table", + plugins: [ "table", "link", "paste" ], + target_list: false, + autoresize_min_height: 130, + extended_valid_elements: [ "a[href|target=_blank]" ], + paste_auto_cleanup_on_paste : true, + paste_remove_styles: true, + paste_retain_style_properties: "none", + paste_convert_middot_lists: true, + paste_remove_styles_if_webkit: true, + paste_remove_spans: true, + paste_strip_class_attributes: "all" +}); diff --git a/app/views/notes/create.js.erb b/app/views/notes/create.js.erb new file mode 100644 index 0000000..4cd1b85 --- /dev/null +++ b/app/views/notes/create.js.erb @@ -0,0 +1,31 @@ + +// rewrite the number of notes heading e.g. Notes(3) +<% noteslabel = "#notes_number_#{@question.id}" %> +$("<%=noteslabel%>").html("Notes (<%= @num_notes %>)"); + +// need to remove the existing tinymce editor otherwise +tinymce.remove(".tinymce"); + +// render the list of notes and invisible view and edit sections +<% listlabel = "#comment-question-area-#{@question.id}" %> +$("<%=listlabel%>").html( + "<%= escape_javascript( render partial: '/phases/note', locals: {question: @question, answer: @answer, plan: @plan } ) %>" +); + +tinymce.init({ + selector: ".tinymce", + statusbar: false, + menubar: false, + toolbar: "bold italic | bullist numlist | link | table", + plugins: [ "table", "link", "paste" ], + target_list: false, + autoresize_min_height: 130, + extended_valid_elements: [ "a[href|target=_blank]" ], + paste_auto_cleanup_on_paste : true, + paste_remove_styles: true, + paste_retain_style_properties: "none", + paste_convert_middot_lists: true, + paste_remove_styles_if_webkit: true, + paste_remove_spans: true, + paste_strip_class_attributes: "all" +}); diff --git a/app/views/notes/update.js.erb b/app/views/notes/update.js.erb new file mode 100644 index 0000000..45c5eb5 --- /dev/null +++ b/app/views/notes/update.js.erb @@ -0,0 +1,27 @@ + +// need to remove the existing tinymce editor otherwise +tinymce.remove(".tinymce"); + +// render the list of notes and invisible view and edit sections +<% listlabel = "#comment-question-area-#{@question.id}" %> +$("<%=listlabel%>").html( + "<%= escape_javascript( render partial: '/phases/note', locals: {question: @question, answer: @answer, plan: @plan } ) %>" +); + +tinymce.init({ + selector: ".tinymce", + statusbar: false, + menubar: false, + toolbar: "bold italic | bullist numlist | link | table", + plugins: [ "table", "link", "paste" ], + target_list: false, + autoresize_min_height: 130, + extended_valid_elements: [ "a[href|target=_blank]" ], + paste_auto_cleanup_on_paste : true, + paste_remove_styles: true, + paste_retain_style_properties: "none", + paste_convert_middot_lists: true, + paste_remove_styles_if_webkit: true, + paste_remove_spans: true, + paste_strip_class_attributes: "all" +}); diff --git a/app/views/orgs/admin_edit.html.erb b/app/views/orgs/admin_edit.html.erb index 67030c7..3bbc468 100644 --- a/app/views/orgs/admin_edit.html.erb +++ b/app/views/orgs/admin_edit.html.erb @@ -2,7 +2,7 @@ <% javascript 'admin.js' %>

    - <%= t('org_admin.org_details_label') %> + <%= _('Organisation details') %>

    @@ -13,12 +13,12 @@ - - + + - + - + - + <%end%> - + - + - - + + - - + + - - + +
    <%= t('org_admin.org_name') %><%= f.text_field :name, as: :string, class: 'text_field has-tooltip', data_toggle: "tooltip", title: t('org_admin.name_help_text') %><%= _('Name') %><%= f.text_field :name, as: :string, class: 'text_field has-tooltip', data_toggle: "tooltip", title: _("Please enter your organisation's name.") %>
    <%= t('org_admin.org_abbr') %><%= _('Abbreviation') %>
    <%= f.text_field :abbreviation, as: :string, class: 'text_field' %> @@ -30,40 +30,40 @@ <% if @org.logo.present? %>
    <%= t('org_admin.org_logo') %><%= _('Logo') %> <%= image_tag @org.logo.url %>
    <%= f.check_box :remove_logo %>   <%= t('org_admin.remove_logo') %><%= f.check_box :remove_logo %>   <%= _('If you decide to use the default DMPRoadmap logo, please check this box to remove your current logo.') %>
    <%= t('org_admin.new_org_logo') %><%= _('Upload a new logo file') %> <%= f.file_field :logo %>
    <%= t('org_admin.org_banner_text') %><%= _('Top banner text') %> <%= text_area_tag("org_banner_text", @org.banner_text, class: "tinymce") %>
    <%= t('org_admin.org_target_url') %><%= f.text_field :target_url, as: :string, class: 'text_field has-tooltip', data_toggle: "tooltip", title: t('org_admin.target_url_help_text') %><%= _('Website') %><%= f.text_field :target_url, as: :string, class: 'text_field has-tooltip', data_toggle: "tooltip", title: _('Please enter a valid web address.') %>
    <%= t('org_admin.org_contact_email') %><%= f.text_field :contact_email, as: :string, class: 'text_field has-tooltip', data_toggle: "tooltip", title: t('org_admin.org_contact_email_help_text') %><%= _('Contact Email') %><%= f.text_field :contact_email, as: :string, class: 'text_field has-tooltip', data_toggle: "tooltip", title: _('The email address of an administrator at your organisation. Your users will use this address if they have questions.') %>
    <%= t('org_admin.org_type') %><%= @org.organisation_type %><%= _('Organisation type') %><%= @org.type %>
    @@ -71,13 +71,13 @@
    - <%= f.submit t('helpers.submit.save'), class: 'btn btn-primary' %> - <%= link_to t('helpers.submit.cancel'), :back, class: 'btn btn-primary' %> + <%= f.submit _('Save'), class: 'btn btn-primary' %> + <%= link_to _('Cancel'), :back, class: 'btn btn-primary' %>
    <% end %>
    -<%= tinymce content_css: asset_path('application.css') %> +<%= tinymce :content_css => asset_path('application.css') %> diff --git a/app/views/orgs/admin_show.html.erb b/app/views/orgs/admin_show.html.erb index 55ed7b1..a3da37b 100644 --- a/app/views/orgs/admin_show.html.erb +++ b/app/views/orgs/admin_show.html.erb @@ -1,9 +1,9 @@ <%= stylesheet_link_tag "admin" %>

    - <%= t('org_admin.org_details_label') %> + <%= _('Organisation details') %>

    -<%= t('org_admin.org_text')%> +<%= _('These are the basic details for your organisation.')%>
    @@ -14,7 +14,7 @@ <% if @org.name.present? then %> - + <% if @org.logo.present? then %> @@ -25,48 +25,52 @@ <% if @org.abbreviation.present? then %> - + + <% else %> + + + <% end %> <% if @org.banner_text.present? then %> - + <% end %> <% if @org.target_url.present? then %> - + <% end %> <% if @org.contact_email.present? then %> - + <% end %> <% if @org.org_type != 0 then %> - - + + <% end %> <% if @org.parent_id.present? then %> - + <% end %> - +
    <%= t('org_admin.org_name') %><%= _('Name') %> <%= @org.name %>
    <%= t('org_admin.org_abbr') %><%= _('Abbreviation') %> <%= @org.abbreviation %>
    <%= _('Abbreviation') %><%= _('Please add an abbreviation to your org for display with annotations!')%>
    <%= t('org_admin.org_banner_text') %><%= _('Top banner text') %> <%= raw @org.banner_text %>
    <%= t('org_admin.org_target_url') %><%= _('Website') %> <%= @org.target_url %>
    <%= t('org_admin.org_contact_email') %><%= _('Contact Email') %> <%= @org.contact_email %>
    <%= t('org_admin.org_type') %><%= @org.organisation_type %><%= _('Organisation type') %><%= @org.type %>
    <%= t('org_admin.parent_org') %><%= _('Main organisation') %> <%= @org.parent.name %>
    <%= t('org_admin.last_updated') %><%= _('Last updated') %> <%= l @org.updated_at.to_date, formats: :short %>
    @@ -75,7 +79,7 @@
    - <%= link_to t("helpers.submit.edit"), admin_edit_org_path(current_user.org), class: 'btn btn-primary'%> + <%= link_to _('Edit'), admin_edit_org_path(current_user.org), class: 'btn btn-primary'%>

    diff --git a/app/views/phases/_add_note.html.erb b/app/views/phases/_add_note.html.erb deleted file mode 100644 index 41d72f5..0000000 --- a/app/views/phases/_add_note.html.erb +++ /dev/null @@ -1,28 +0,0 @@ - - - -<% new_note = Note.new - if !answer.nil? - answerid = answer["id"] - else - answerid = answer_obj.id - end -%> - -<%= form_for :new_note, - :url => {:controller => :notes, :action => :create }, - :html=>{:method=>:post, :id => "new_note_form_#{answerid}", :class => "add_note_form"} do |f| %> - <%= f.hidden_field :user_id, :value => current_user.id %> - <%= f.hidden_field :answer_id, :value => answerid %> - <%= f.hidden_field :question_id, :value => question["id"] %> - <%= f.hidden_field :plan_id, :value => plan_data["id"] %> - - <%= text_area_tag("#{answerid}new_note_text".to_sym, "" , class: "tinymce") %> -
    - - -
    - <%= f.submit t("helpers.submit.save"), :class => "btn btn-primary new_comment_submit_button" %> -
    -
    -<%end%> diff --git a/app/views/phases/_answer_form.html.erb b/app/views/phases/_answer_form.html.erb index 74ae43a..c95732b 100644 --- a/app/views/phases/_answer_form.html.erb +++ b/app/views/phases/_answer_form.html.erb @@ -2,221 +2,121 @@ **Project: DMPRoadmap **Description: This block sets up the type of question, its guidance. **Arguments transferred: an instance of "question" - **Copyright: Digital Curation Centre and University of California Curation Center + **Copyright: Digital Curation Centre and California Digital Library -->
    - <% - q_format = question["question_format"] - answer = nil - answer_obj = nil - if question.has_key?("answers") - answer = question["answers"].first - answer_obj = Answer.find(answer["id"]) + answers = question.plan_answers(plan.id) + if answers.present? + answer = answers.first else - answer_obj = Answer.new + answer = Answer.new({ plan_id: plan.id, question_id: question.id, user_id: current_user.id }) + if question.default_value.present? + answer.text = question.default_value + end end - question_obj = Question.find(question["id"]) %> - -
    " class="question-form"> - <%= semantic_form_for answer_obj, :url => {:controller => :answers, :action => :update }, :html=>{:method=>:put}, :remote => true do |f| %> - <%= f.inputs do %> - <%= f.input :plan_id, :as => :hidden, :input_html => { :value => @plan_data["id"] } %> - <%= f.input :user_id, :as => :hidden, :input_html => { :value => current_user.id } %> - <%= f.input :question_id, :as => :hidden, :input_html => { :value => question["id"], :class => "question_id" } %> - - - - <%= raw question["text"] %> - - - <% if question.has_key?("suggested_answer") && question["suggested_answer"]["text"].present? %> - <% suggested_answer = question["suggested_answer"] %> -
    - - <% if suggested_answer["is_example"] then %> - <%= t("org_admin.questions.example_answer_label")%> - <%else%> - <%= t("org_admin.questions.suggested_answer_label")%> - <%end%> - - -
    -

    - <%= raw suggested_answer["text"] %> -

    -
    -
    - <% end %> - - - <% if [ @checkbox, @multi, @radio, @dropdown ].include?( q_format["id"] ) %> - <% options = question.options.order("number") %> - - - <% if q_format.id == @checkbox %> - <%= f.input :options, :as => :check_boxes, :collection => options, :label => false, :input_html => { :id => "options-#{question.id}" } %> - <% elsif q_format.id == @multi %> - <%= f.input :options, :as => :select, :collection => options, :label => false, :input_html => { :multiple => true , :id => "options-#{question.id}" } %> - <% elsif q_format.id == @radio %> -
      - <% options.each do |op| %> -
    1. - <% if answer.option_ids[0] == op.id then%> - <%= f.radio_button :option_ids, op.id, :checked => true, id: "answer_option_ids_#{op.id}"%> - <%else%> - <%= f.radio_button :option_ids, op.id, :checked => false, id: "answer_option_ids_#{op.id}"%> - <% end %> - <%= raw op.text %>
    2. - <% end %> -
    - <% elsif q_format.id == @dropdown %> - <%= f.input :options, :as => :select, :collection => options, :label => false, :input_html => { :multiple => false, :id => "options-#{question.id}" } %> - <% end %> - - - - <% if question.option_comment_display == true %> - <%= label_tag("answer-text-#{question.id}".to_sym, t("helpers.comment")) %> - <%= text_area_tag("answer-text-#{question.id}".to_sym, answer.text, class: "tinymce") %> - <%end%> - <% end %> - - <% if q_format["id"] == @textfield %> - <%= text_field_tag("answer-text-#{question.id}".to_sym, strip_tags(answer.text), class: "question_text_field") %> - <% elsif q_format["id"] == @textarea %> - <%= text_area_tag("answer-text-#{question["id"]}".to_sym, answer_obj.text, class: "tinymce") %> - <% end %> - - <% end %> - - - <%= f.actions do %> - <%= f.action :submit, :label => t("helpers.save"), :button_html => { :class => "btn btn-primary"} %> -
  • " class="saving-message" style="display:none;"><%= t("helpers.saving")%>
  • - <% end %> - <% end %> +
    +
    " class="answer-locking">
    +
    "> + <%= render(partial: 'answers/new_edit', locals: { question: question, answer: answer, readonly: readonly }) %> +
    +
    " class="answer-status"> + <%= render(partial: 'answers/status', locals: { answer: answer }) %> +
    - - <% if answer.nil? || !answer.has_key?("created_at") || answer["created_at"].nil? %> - -status" class="label label-warning answer-status"><%= t("helpers.notanswered") %> - <% else %> - -status" class="label label-info answer-status"><%= t("helpers.answered_by")%><%= answer_obj.created_at %><%= t("helpers.answered_by_part2")%><%= answer_obj.user.name %> - <% end %> - --unsaved" class="label label-inverse answer-unsaved" style="display:none;"><%= t("helpers.unsaved") %>
    -
    " class="question_right_column_nav"> - <% comments = answer_obj.notes.all %> - <%= hidden_field_tag :question_id, question["id"], :class => "question_id" %> +
    + <% comments = answer.notes.all %> + <%= hidden_field_tag :question_id, question.id, class: "question_id" %> + <% active_tab = nil %>
      - <% if (!question["guidance"].nil? && question["guidance"] != "") || question.has_key?("theme_guidance") then %> - - <% css_style_comment_div = "display: none;"%> - <% css_style_guidance_div = ""%> -
    • - <%= link_to t("helpers.guidance_accordion_label"), "#", :class => "guidance_accordion_button" %> -
    • -
    • - <% if comments.count > 0 then%> - <% comments_label_with_count = "#{t("helpers.comment_accordion_label")} (#{comments.count})"%> - <%= link_to comments_label_with_count , "#", :class => "comments_accordion_button" %> - <%else%> - <%= link_to t("helpers.add_comment_accordion_label"), "#", :class => "comments_accordion_button" %> - <%end%> -
    • - <%else%> - - <% css_style_comment_div = ""%> - <% css_style_guidance_div = "display: none;"%> -
    • - <% if comments.count > 0 then%> - <% comments_label_with_count = "#{t("helpers.comment_accordion_label")} (#{comments.count})"%> -

      <%= comments_label_with_count %>

      - <%else%> -

      <%= t("helpers.add_comment_accordion_label") %>

      - <%end%> + <% annotations = question.annotations.where(type: Annotation.types[:guidance]) %> + <% if annotations.present? || question_guidances.present? %> + <% active_tab = 'guidance_tab' %> +
    • + <%= link_to _('Guidance'), "#", class: "right_column_tab_link" %>
    • - <%end%> + <% else %> + <% active_tab = 'note_tab' %> + <% end %> +
    • "> + <% if comments.count > 0 %> + <%= link_to "#{_('Notes')} (#{comments.count})" , "#", id: "notes_number_#{question.id}", class: "right_column_tab_link" %> + <% else %> + <%= link_to _('Share note'), "#", id: "notes_number_#{question.id}", class: "right_column_tab_link" %> + <% end %> +
    - -
    " style="<%= css_style_guidance_div%>" > -
    -guidance"> + +
    +
    - - <% if question["guidance"].present? %> -
    + + <% num_annotations = 0 %> + <% if annotations.present? %> + <% annotations.each do |annotation| %> - - +
    - -
    " class="guidance-accordion-body collapse"> -
    <%= raw question["guidance"] %>
    -
    + + -
    + +
    +
    <%= raw annotation.text %>
    +
    + <% num_annotations += 1%> +
    + <% end %> <% end %> - - <% gnum = 0 %> - <% if question.has_key?("theme_guidance") %> - <% question["theme_guidance"].each_key do |theme| %> - <% question["theme_guidance"][theme].each do |guidance| %> - <% - orgname = guidance["org"] - gnum = gnum + 1 - text = guidance["text"] - %> - -
    - - -
    - -guidance" href="#collapse-guidance-<%= gnum %>-<%= question["id"] %>"> -
    - <%= orgname %> guidance on <%= theme %> -
    -
    + <% guidance_accordion_id = num_annotations %> + <% question_guidances.each_pair do |theme, group| %> + <% group.each do |gobj| %> +
    + +
    +
    <%= raw gobj[:text] %>
    +
    + <% guidance_accordion_id += 1 %>
    - - -
    " class="guidance-accordion-body collapse"> -
    <%= raw text %>
    -
    -
    - <% end %> - <% end %> - <% end %> + <% end %> + <% end %>
    -
    - - -
    " style="<%= css_style_comment_div%>"> - <%= render :partial => "note", locals: {question: question, answer_obj: answer_obj, answer: answer, plan: plan, plan_data: plan_data}%> +
    + +
    + <%= render partial: "note", locals: {question: question, answer: answer, plan: plan, suffix: "" }%>
    -
    -<% if last_question_id == question["id"] then %> +<% if last_question_id == question.id then %>
    <% else %>
    diff --git a/app/views/phases/_answer_form_ro.html.erb b/app/views/phases/_answer_form_ro.html.erb deleted file mode 100644 index 64a0fb0..0000000 --- a/app/views/phases/_answer_form_ro.html.erb +++ /dev/null @@ -1,248 +0,0 @@ - -<% answer = @plan.answer(question.id) %> - -
    - - <% q_format = question.question_format%> - - <% if readonly != "always" then %> -
    > - <%= semantic_form_for answer, :url => {:controller => :answers, :action => :create }, :html=>{:method=>:post}, :remote => true do |f| %> - <%= f.inputs do %> - <%= f.input :plan_id, :as => :hidden %> - <%= f.input :user_id, :as => :hidden, :input_html => { :value => current_user.id } %> - <%= f.input :question_id, :as => :hidden, :input_html => { :class => "question_id" } %> - - - - <%= raw question.text %> - - - <% suggested_answer = question.suggested_answers.where(org_id: @plan.template.org_id).first %> - <% if suggested_answer.present? %> -
    - - <% if suggested_answer.is_example? then %> - <%= t("org_admin.questions.example_answer_label")%> - <%else%> - <%= t("org_admin.questions.suggested_answer_label")%> - <%end%> - -
    -

    - <%= raw suggested_answer.text %> -

    -
    -
    - <% end %> - - - <% if q_format.title == t("helpers.checkbox") || q_format.title == t("helpers.multi_select_box") || q_format.title == t("helpers.radio_buttons") || q_format.title == t("helpers.dropdown") then%> - <% options = question.options.order("number") %> - - <% if q_format.title == t("helpers.checkbox") then %> - <% if readonly then %> - <%= f.input :options, :as => :check_boxes, :collection => options, :label => false, input_html => { :disabled => true, :id => "options-#{question.id}" } %> - <% else %> - <%= f.input :options, :as => :check_boxes, :collection => options, :label => false, :input_html => { :id => "options-#{question.id}" } %> - <% end %> - - <% elsif q_format.title == t("helpers.multi_select_box") then %> - <% if readonly then %> - <%= f.input :options, :as => :select, :collection => options, :label => false, :input_html => { :multiple => true, :disabled => true , :id => "options-#{question.id}" } %> - <% else %> - <%= f.input :options, :as => :select, :collection => options, :label => false, :input_html => { :multiple => true , :id => "options-#{question.id}" } %> - <% end %> - - <% elsif q_format.title == t("helpers.radio_buttons") then%> -
      - <% options.each do |op| %> -
    1. - <% if answer.option_ids[0] == op.id then%> - <% if readonly then %> - <%= f.radio_button :option_ids, op.id, :checked => true, disabled: true, id: "answer_option_ids_#{op.id}"%> - <% else %> - <%= f.radio_button :option_ids, op.id, :checked => true, id: "answer_option_ids_#{op.id}"%> - <% end %> - <%else%> - <% if readonly then %> - <%= f.radio_button :option_ids, op.id, :checked => false, disabled: true, id: "answer_option_ids_#{op.id}"%> - <% else %> - <%= f.radio_button :option_ids, op.id, :checked => false, id: "answer_option_ids_#{op.id}"%> - <% end %> - <% end %> - <%= op.text %>
    2. - <% end %> -
    - - <% elsif q_format.title == t("helpers.dropdown") then%> - <% if readonly then %> - <%= f.input :options, :as => :select, :collection => options, :label => false, :input_html => { :multiple => false, :disabled => true, :id => "options-#{question.id}" } %> - <% else %> - <%= f.input :options, :as => :select, :collection => options, :label => false, :input_html => { :multiple => false, :id => "options-#{question.id}" } %> - <% end %> - <% end %> - - <% if question.option_comment_display == true then%> - <%= label_tag("answer-text-#{question.id}".to_sym, t("helpers.comment")) %> - <%= text_area_tag("answer-text-#{question.id}".to_sym, answer.text, class: "tinymce") %> - <%end%> - - - <% elsif q_format.title == t("helpers.text_field") then %> - <%= text_field_tag("answer-text-#{question.id}".to_sym, strip_tags(answer.text), class: "question_text_field") %> - - <% elsif q_format.title == t("helpers.text_area") then%> - <%= text_area_tag("answer-text-#{question.id}".to_sym, answer.text, class: "tinymce") %> - <% end %> - - <% end %> - - - <%= f.actions do %> - <% if readonly then %> - <%= f.action :submit, :label => t("helpers.save"), :button_html => { :class => "btn btn-primary"}, :input_html => { :disabled => true } %> - <% else %> - <%= f.action :submit, :label => t("helpers.save"), :button_html => { :class => "btn btn-primary"} %> - <% end %> - - <% end %> - <% end %> -
    - <% end %> - -
    > -

    <%= question.text %>

    -
    - <% if q_format.title == t("helpers.checkbox") || q_format.title == t("helpers.multi_select_box") || q_format.title == t("helpers.radio_buttons") || q_format.title == t("helpers.dropdown") %> -
      - <% if answer.options.is_a? Option then %> -
    • <%= answer.options.text %>
    • - <% else %> - <% answer.options.each do |o| %> -
    • <%= o.text %>
    • - <% end %> - <% end %> -
    - <% end %> -
    - <%= raw answer.text %> -
    -
    -
    - <% if answer.created_at.nil? then %> - <%= t("helpers.notanswered") %> - <% else %> - <%= t("helpers.answered_by")%><%= answer.created_at %><%= t("helpers.answered_by_part2")%><%= answer.user.name %> - <% end %> - -
    - - - -
    -
    - <% @comments = Notes.where("question_id = ? AND plan_id = ?", question.id, answer.plan_id ) %> - <%= hidden_field_tag :question_id, question.id, :class => "question_id" %> - <% @question_guidances = @plan.guidance_for_question(question) %> -
      - <% if (!question.guidance.nil? && question.guidance != "") || @question_guidances.count > 0 then %> - - <% css_style_comment_div = "display: none;"%> - <% css_style_guidance_div = ""%> -
    • - <%= link_to t("helpers.guidance_accordion_label"), "#", :class => "guidance_accordion_button" %> -
    • -
    • - <% if @comments.count > 0 then%> - <% comments_label_with_count = "#{t("helpers.comment_accordion_label")} (#{@comments.count})"%> - <%= link_to comments_label_with_count , "#", :class => "comments_accordion_button" %> - <%else%> - <%= link_to t("helpers.add_comment_accordion_label"), "#", :class => "comments_accordion_button" %> - <%end%> -
    • - <%else%> - - <% css_style_comment_div = ""%> - <% css_style_guidance_div = "display: none;"%> -
    • - <% if @comments.count > 0 then%> - <% comments_label_with_count = "#{t("helpers.comment_accordion_label")} (#{@comments.count})"%> -

      <%= comments_label_with_count %>

      - <%else%> -

      <%= t("helpers.add_comment_accordion_label") %>

      - <%end%> -
    • - <%end%> -
    -
    - - - -
    -
    - - <% if !question.guidance.nil? && question.guidance != "" then %> - - <% end %> - - <% @question_guidances.each_pair do |group,themes| %> - <% themes.each_pair do |theme,guidances| %> - <% guidances.each do |guidance| %> - - <% end %> - <% end %> - <% end %> -
    -
    - - -
    - <%= render :partial => "comments", locals: {questionId: question.id, plan_id: answer.plan_id }%> -
    - - - -
    - -<% if last_question_id == question.id then %> -
    -<% else %> -
    -<% end %> diff --git a/app/views/phases/_archive_note.html.erb b/app/views/phases/_archive_note.html.erb deleted file mode 100644 index daee904..0000000 --- a/app/views/phases/_archive_note.html.erb +++ /dev/null @@ -1,23 +0,0 @@ - -<%= form_for(Note.new, :url => {:controller => :notes, :action => :archive } , :html => { :method => :put, :class => "archive_note_form", :id => "archive_note_form_#{note["id"]}"}) do |f| %> - <%= f.hidden_field :id, :value => note["id"] %> - <%= f.hidden_field :archived_by, :value => current_user.id %> - - <%= render :partial => "view_note", locals: {note: note} %> - - <% if current_user.id == note["user_id"] then %> - <%= t('helpers.notes.archive_own_note_question')%> - <% button_label = t("helpers.notes.archive_own_comment_button_label") %> - <% else%> - <%= t("helpers.notes.archive_note_question")%> - <% button_label = t("helpers.notes.archive_comment_button_label") %> - <%end%> - - -
    - <%= hidden_field_tag :note_id, note["id"], :class => "comment_id" %> - <%= f.submit button_label, :class => "btn btn-primary archive_comment_submit_button" %> - <%= link_to t("helpers.submit.cancel"), "#", :class => "cancel_archive_comment btn cancel" %> -
    -
    -<%end%> diff --git a/app/views/phases/_edit_note.html.erb b/app/views/phases/_edit_note.html.erb deleted file mode 100644 index 366945f..0000000 --- a/app/views/phases/_edit_note.html.erb +++ /dev/null @@ -1,16 +0,0 @@ - - -<%= form_for(Note.new, :url => {:controller => :notes, :action => :update } , :html => { :method => :put, :class => "edit_note_form", :id=> "edit_note_form_#{note["id"]}"}) do |f| %> - <%= f.hidden_field :id, :value => note["id"] %> - - <%= text_area_tag("#{note["id"]}_note_text".to_sym, note["text"] , class: "tinymce") %> -
    - - -
    - <%= hidden_field_tag :answer, note["answer_id"], :class => "answer_id" %> - <%= hidden_field_tag :note_id, note["id"], :class => "note_id" %> - <%= f.submit t("helpers.submit.save"), :class => "btn btn-primary edit_note_submit_button" %> -
    -
    -<%end%> diff --git a/app/views/phases/_edit_phase.html.erb b/app/views/phases/_edit_phase.html.erb new file mode 100644 index 0000000..40ae572 --- /dev/null +++ b/app/views/phases/_edit_phase.html.erb @@ -0,0 +1,46 @@ + + +<%= form_for(phase, url: admin_update_phase_path(phase.id), html: { method: :put}) do |f| %> + +

    + <%= _('Phase details')%> +

    +
    + <%= raw _("

    Here you set the title that users will see. If you intend to have multiple phases for you DMP, this should be clear in the title and description.

    ")%> +

    +
    +
    + + + + + + + + + + + + + + +
    <%= _('Title') %><%= f.text_field :title, + as: :string, + class: 'text_field has-tooltip', 'data-toggle' => "tooltip", 'title' => _('Enter a title for the phase e.g. intial DMP, full DMP... This is what users will see in the tabs when completing a plan. If you only have one phase, call it something generic e.g. Glasgow DMP') %>
    <%= _('Order of display') %><%= f.number_field :number, in: 0..5, class: "number_field has-tooltip", 'data-toggle' => "tooltip", 'title' => _('This allows you to order the phases of your template.') %>
    <%= _('Description') %> +
    + <%= text_area_tag("phase-desc", phase.description, class: "tinymce") %> +
    +
    + <%= link_to( image_tag('help_button.png'), '#', "data-toggle": "popover", rel: "popover", 'data-html' => "true", 'data-content' => _("Enter a basic description. This will be presented to users on the 'Admin Plan' tab, above the summary of the sections and questions which they will be asked to answer."))%> +
    +
    +
    +
    + + +
    + <%= f.submit _('Save'), class: 'btn btn-primary' %> + <%= link_to _('Cancel'), admin_show_phase_path(phase), class: 'btn cancel' %> +
    + +<% end %> \ No newline at end of file diff --git a/app/views/phases/_list_notes.html.erb b/app/views/phases/_list_notes.html.erb deleted file mode 100644 index 7d6315a..0000000 --- a/app/views/phases/_list_notes.html.erb +++ /dev/null @@ -1,91 +0,0 @@ - - -<% if notes.count > 1 then%> - <% style_to_add = "height:150px; overflow-y:auto;" %> -<%else%> - <% style_to_add = "" %> -<%end%> - - -<% notes.sort! {|x,y| y["updated_at"] <=> x["updated_at"] } %> - -
    - -
    - - - <% notes.each do |c|%> - - - - - <%end%> - -
    - <% user = c["user"] %> - <% user = User.find(c["user_id"]) %> - <%= user["name"] %>
    - (<%= l c["updated_at"], format: :custom %>) -
    - - <% if c["archived"] %> - - <% if c["archived_by"] == current_user.id %> - <%= t("helpers.comments.retracted")%> - <% else %> - <% archived_by_user = User.find(c["archived_by"]) %> - <%= t("helpers.comments.clear_by")%> <%= archived_by_user.name %> - <%end%> - - <%else%> - - <%= link_to t("helpers.comments.view_label"),"#", :class => "dmp_table_link view_comment_button" %> - <%= hidden_field_tag :note_id, c["id"], :class => "comment_id" %> - - <% if current_user.id == c["user_id"] %> - <%= link_to t("helpers.comments.edit_label"),"#", :class => "dmp_table_link edit_comment_button" %> - <%= hidden_field_tag :note_id, c["id"], :class => "comment_id" %> - <%= link_to t("helpers.comments.retract_label"),"#", :class => "dmp_table_link archive_comment_button" %> - <% end%> - - <% if plan.administerable_by?(current_user.id) && current_user.id != c["user_id"] %> - <%= hidden_field_tag :note_id, c["id"], :class => "comment_id" %> - <%= link_to t("helpers.comments.clear_label"),"#", :class => "dmp_table_link archive_comment_button" %> - <% end%> - <%end%> - -
    -
    - -
    - - -<% notes_not_archived = notes.select { |n| n["archived"].nil? } %> -<% latest_note = notes_not_archived.sort { |x,y| y["updated_at"] <=> x["updated_at"] }.first %> -<% if !latest_note.nil? then%> -
    " class ="view_comment_class"> - <%= render :partial => "view_note", locals: {note: latest_note} %> -
    -
    -<%end%> - -<%notes.each do |com|%> - -
    " class ="view_comment_class" style="display: none"> - <%= render :partial => "view_note", locals: {note: com} %> -
    -
    - - -
    " class ="edit_comment_class" style="display: none"> - <%= render :partial => "edit_note", locals: {note: com} %> -
    -
    - - -
    " class ="archive_comment_class" style="display: none"> - <%= render :partial => "archive_note", locals: {note: com} %> -
    -
    - -<%end%> diff --git a/app/views/phases/_note.html.erb b/app/views/phases/_note.html.erb index 659738a..c296d9b 100644 --- a/app/views/phases/_note.html.erb +++ b/app/views/phases/_note.html.erb @@ -1,36 +1,29 @@ - - - <% if answer.present? && answer.has_key?("notes") %> - <% notes = answer["notes"] %> - <% answerid = answer["id"] %> - <%= hidden_field_tag :answer_id, answer["id"] %> + <% if answer.present? && answer.notes.any? %> + <% notes = answer.notes.all.to_a.sort! {|x,y| y.updated_at <=> x.updated_at } %> + <% questionid = question.id %> + <%= hidden_field_tag :question_id, questionid, class: "question_id" %> -
    - <%= link_to t("helpers.comments.add_comment_label"),'#', :class => "btn btn-primary add_comment_button" %> +
    + <%= link_to _('Add note'), + "#question-form-#{questionid}", + class: "btn btn-primary add_comment_button", + onclick: "add_note_button(#{questionid})" + %>
    - <%= render :partial => "list_notes", locals: {question: question, notes: notes, plan:plan} %> + <%= render :partial => "/notes/list", locals: {question_id: question.id, notes: notes, plan: plan} %> -
    - - -
    - <%= link_to t("helpers.comments.add_comment_label"),'#', :class => "btn btn-primary add_comment_button" %> -
    - -<%= render :partial => "/plans/plan_nav_tabs", locals: {plan: @plan, plan_data: @plan_data, active: @phase.title } %> - +<%= render :partial => "/plans/plan_nav_tabs", locals: {plan: @plan, active: @phase.title} %>
    - <% @phase_data["sections"].each do |section| %> + <% @phase.sections.order(:number).each do |section| %> - <% sectionid = section["id"] %> - - - <% if session[:question_id_comments].to_i != 0 then %> - <% question_from_comment = Question.find(session[:question_id_comments])%> - <% if sectionid == question_from_comment.section_id then %> - <%= hidden_field_tag :comment_section_id, question_from_comment.section_id, :class => "comment_section_id" %> - <%end%> - <% end%> - - + <% sectionid = section.id %>
    - - - <% num_section_questions = section["questions"].count %> - <% num_section_answers = section["nanswers"] %> - <% question_word = "questions" %> - <% if num_section_questions == 1 then %> - <% question_word = "question" %> - <% end %> - <% section_status = "#{num_section_questions} #{question_word}, #{num_section_answers} answered" %> -
    - "> -
    "> - <%= section["title"] %> - <% if num_section_questions.to_i > num_section_answers.to_i then %> - (<%= section_status %>) - <% else %> - (<%= section_status %>) - <% end %> + +
    + <%= render :partial => "/sections/progress", locals: { section: section, plan: @plan } %>
    @@ -84,7 +42,7 @@
    - <%= raw section["description"] %> + <%= raw section.description %>
    @@ -103,26 +61,22 @@
    - <% section["questions"].each do |question| %> - <% if question["id"] == session[:question_id_comments].to_i then id_css = "current_question" end %> + <% section.questions.each do |question| %> + <% if question.id == session[:question_id_comments].to_i then id_css = "current_question" end %>
    - <% partialname = "answer_form" - if @readonly - partialname += "_ro" - end - %> - - <% guidances = question["guidances"] %> - - <%= render partial: partialname, + + <% guidances = @question_guidance[question.id] %> + + <%= render partial: 'answer_form', locals: { plan: @plan, - plan_data: @plan_data, question: question, - last_question_id: section["questions"].last["id"] + question_guidances: guidances, + last_question_id: section.questions.last.id, + readonly: @readonly } %> -
    +
    <% end %>
    @@ -134,35 +88,31 @@
    <% end %>
    - - <%= tinymce :content_css => asset_path("application.css"), :setup => "function(editor){editor.on('change', function(e){$.fn.check_textarea(editor)});}" %>
    -<%= render :partial => "plans/export", locals: {plan: @plan, plan_data: @plan_data} %> - -<% session.delete(:question_id_comments)%> +<%= render :partial => "plans/export", locals: {plan: @plan, plan_data: @plan_data, phase: @phase } %> diff --git a/app/views/plans/_answer_form.html.erb b/app/views/plans/_answer_form.html.erb deleted file mode 100644 index dd256e4..0000000 --- a/app/views/plans/_answer_form.html.erb +++ /dev/null @@ -1,260 +0,0 @@ - -<% answer = @plan.answer(question.id) %> - -
    - - <% q_format = question.question_format%> - - <% if readonly != "always" then %> -
    > - <%= semantic_form_for answer, :url => {:controller => :answers, :action => :create }, :html=>{:method=>:post}, :remote => true do |f| %> - <%= f.inputs do %> - <%= f.input :plan_id, :as => :hidden %> - <%= f.input :user_id, :as => :hidden, :input_html => { :value => current_user.id } %> - <%= f.input :question_id, :as => :hidden, :input_html => { :class => "question_id" } %> - - - - <%= raw question.text %> - - - <% suggested_answer = question.suggested_answers.find_by_organisation_id(@plan.project.organisation_id) %> - <% if !suggested_answer.nil? && suggested_answer.text != "" then %> -
    - - <% if suggested_answer.is_example? then %> - <%= t("org_admin.questions.example_answer_label")%> - <%else%> - <%= t("org_admin.questions.suggested_answer_label")%> - <%end%> - -
    -

    - <%= raw suggested_answer.text %> -

    -
    -
    - <% end %> - - - <% if q_format.title == "Check box" || - q_format.title == "Multi select box" || - q_format.title == "Radio buttons" || - q_format.title == "Dropdown" then%> - <% options = question.options.order("number") %> - - <% if q_format.title == "Check box" then %> - <% if readonly then %> - <%= f.input :options, :as => :check_boxes, :collection => options, :label => false, input_html => { :disabled => true, :id => "options-#{question.id}" } %> - <% else %> - <%= f.input :options, :as => :check_boxes, :collection => options, :label => false, :input_html => { :id => "options-#{question.id}" } %> - <% end %> - - <% elsif q_format.title == "Multi select box" then %> - <% if readonly then %> - <%= f.input :options, :as => :select, :collection => options, :label => false, :input_html => { :multiple => true, :disabled => true , :id => "options-#{question.id}" } %> - <% else %> - <%= f.input :options, :as => :select, :collection => options, :label => false, :input_html => { :multiple => true , :id => "options-#{question.id}" } %> - <% end %> - - <% elsif q_format.title == "Radio buttons" then%> -
      - <% options.each do |op| %> -
    1. - <% if answer.option_ids[0] == op.id then%> - <% if readonly then %> - <%= f.radio_button :option_ids, op.id, :checked => true, disabled: true, id: "answer_option_ids_#{op.id}"%> - <% else %> - <%= f.radio_button :option_ids, op.id, :checked => true, id: "answer_option_ids_#{op.id}"%> - <% end %> - <%else%> - <% if readonly then %> - <%= f.radio_button :option_ids, op.id, :checked => false, disabled: true, id: "answer_option_ids_#{op.id}"%> - <% else %> - <%= f.radio_button :option_ids, op.id, :checked => false, id: "answer_option_ids_#{op.id}"%> - <% end %> - <% end %> - <%= op.text %>
    2. - <% end %> -
    - - <% elsif q_format.title == "Dropdown" then%> - <% if readonly then %> - <%= f.input :options, :as => :select, :collection => options, :label => false, :input_html => { :multiple => false, :disabled => true, :id => "options-#{question.id}" } %> - <% else %> - <%= f.input :options, :as => :select, :collection => options, :label => false, :input_html => { :multiple => false, :id => "options-#{question.id}" } %> - <% end %> - <% end %> - - <% if question.option_comment_display == true then%> - <%= label_tag("answer-text-#{question.id}".to_sym, t("helpers.comment")) %> - <%= text_area_tag("answer-text-#{question.id}".to_sym, answer.text, class: "tinymce") %> - <%end%> - - - <% elsif q_format.title == "Text field" then %> - <%= text_field_tag("answer-text-#{question.id}".to_sym, strip_tags(answer.text), class: "question_text_field") %> - - <% elsif q_format.title == "Text area" then%> - <%= text_area_tag("answer-text-#{question.id}".to_sym, answer.text, class: "tinymce") %> - <% end %> - - <% end %> - - - <%= f.actions do %> - <% if readonly then %> - <%= f.action :submit, :label => t("helpers.save"), :button_html => { :class => "btn btn-primary"}, :input_html => { :disabled => true } %> - <% else %> - - - <% end %> - - <% end %> - <% end %> -
    - <% end %> - -
    > -

    <%= question.text %>

    -
    - <% if q_format.title == "Check box" || - q_format.title == "Multi select box" || - q_format.title == "Radio buttons" || - q_format.title == "Dropdown" %> -
      - <% if answer.options.is_a? Option then %> -
    • <%= answer.options.text %>
    • - <% else %> - <% answer.options.each do |o| %> -
    • <%= o.text %>
    • - <% end %> - <% end %> -
    - <% end %> -
    - <%= raw answer.text %> -
    -
    -
    - <% if answer.created_at.nil? then %> - <%= t("helpers.notanswered") %> - <% else %> - <%= t("helpers.answered_by")%><%= answer.created_at %><%= t("helpers.answered_by_part2")%><%= answer.user.name %> - <% end %> - -
    - - - -
    -
    - <% @comments = Comment.where("question_id = ? AND plan_id = ?", question.id, answer.plan_id ) %> - <%= hidden_field_tag :question_id, question.id, :class => "question_id" %> - <% @question_guidances = @plan.guidance_for_question(question) %> -
      - <% if (!question.guidance.nil? && question.guidance != "") || @question_guidances.count > 0 then %> - - <% css_style_comment_div = "display: none;"%> - <% css_style_guidance_div = ""%> -
    • - <%= link_to t("helpers.guidance_accordion_label"), "#", :class => "guidance_accordion_button" %> -
    • -
    • - <% if @comments.count > 0 then%> - <% comments_label_with_count = "#{t("helpers.comment_accordion_label")} (#{@comments.count})"%> - <%= link_to comments_label_with_count , "#", :class => "comments_accordion_button" %> - <%else%> - <%= link_to t("helpers.add_comment_accordion_label"), "#", :class => "comments_accordion_button" %> - <%end%> -
    • - <%else%> - - <% css_style_comment_div = ""%> - <% css_style_guidance_div = "display: none;"%> -
    • - <% if @comments.count > 0 then%> - <% comments_label_with_count = "#{t("helpers.comment_accordion_label")} (#{@comments.count})"%> -

      <%= comments_label_with_count %>

      - <%else%> -

      <%= t("helpers.add_comment_accordion_label") %>

      - <%end%> -
    • - <%end%> -
    -
    - - - -
    -
    - - <% if !question.guidance.nil? && question.guidance != "" then %> - - <% end %> - - <% @question_guidances.each_pair do |group,themes| %> - <% themes.each_pair do |theme,guidances| %> - <% guidances.each do |guidance| %> - - <% end %> - <% end %> - <% end %> -
    -
    - - -
    - <%= render :partial => "comments", locals: {questionId: question.id, plan_id: answer.plan_id }%> -
    - - - -
    - -<% if last_question_id == question.id then %> -
    -<% else %> -
    -<% end %> diff --git a/app/views/plans/_answer_form_ro.html.erb b/app/views/plans/_answer_form_ro.html.erb new file mode 100644 index 0000000..e035e1c --- /dev/null +++ b/app/views/plans/_answer_form_ro.html.erb @@ -0,0 +1,51 @@ + +<% answer = @plan.answer(question.id) %> + +
    + + <% q_format = question.question_format%> + +
    +

    <%= question.text %>

    + +
    + <% if q_format.title == "Check box" || q_format.title == "Multi select box" || + q_format.title == "Radio buttons" || q_format.title == "Dropdown" %> +
      + <% if answer.question_options.is_a? Array then %> +
    • <%= answer.question_options.text %>
    • + <% else %> + <% answer.question_options.each do |o| %> +
    • <%= o.text %>
    • + <% end %> + <% end %> +
    + <% end %> + +
    + <%= raw answer.text %> +
    +
    +
    + + <% if answer.created_at.nil? then %> + <%= _('Not answered yet') %> + <% else %> + <%= _('Answered')%><%= answer.created_at %><%= _(' by')%><%= answer.user.name %> + <% end %> + + + +
    + + +<% if last_question_id == question.id then %> +
    +<% else %> +
    +<% end %> diff --git a/app/views/plans/_available_templates.html.erb b/app/views/plans/_available_templates.html.erb new file mode 100644 index 0000000..59eb6fa --- /dev/null +++ b/app/views/plans/_available_templates.html.erb @@ -0,0 +1,20 @@ +<%= _('Which DMP template would you like to use?') %> + + + + + +
    + <%= _('We found multiple DMP templates corresponding to your funder.') %> +
    + + \ No newline at end of file diff --git a/app/views/plans/_dropdowns_new_plan.html.erb b/app/views/plans/_dropdowns_new_plan.html.erb deleted file mode 100644 index 5413579..0000000 --- a/app/views/plans/_dropdowns_new_plan.html.erb +++ /dev/null @@ -1,41 +0,0 @@ - - -<%= semantic_form_for @plan, :url => {:controller => :plans, :action => :create }, :html=>{:method=>:post} do |f| %> - <%= f.inputs do %> - <%= hidden_field_tag :default_tag, "false" ,:id => "default_tag" %> -
    - -

    <%= t('helpers.project.create_page.title') %>

    -
    -

    <%= raw t('helpers.project.create_page.desc_html')%>

    -
    - - - - <% end %> - - - <%= f.actions do %> - <%= f.action :submit, - :as => :button, - :input_html => { :id => "create-plan-button", :class => "btn btn-primary"}, - :label => t('helpers.project.create') %> - <% end %> - -<% end %> diff --git a/app/views/plans/_export.html.erb b/app/views/plans/_export.html.erb index 876ab64..cd7ed05 100644 --- a/app/views/plans/_export.html.erb +++ b/app/views/plans/_export.html.erb @@ -1,9 +1,9 @@ -

    + <% end %> + <% end %> diff --git a/app/views/plans/export.pdf.erb b/app/views/plans/export.pdf.erb index 77d68cb..b9ab084 100644 --- a/app/views/plans/export.pdf.erb +++ b/app/views/plans/export.pdf.erb @@ -3,11 +3,7 @@ - <% if @plan.project.dmptemplate.phases.count > 1 then %> - <%= "#{@plan.project.title} - #{@plan.title}" %> - <% else %> - <%= @plan.project.title %> - <% end %> + <%= @plan.title %>