diff --git a/.gitignore b/.gitignore
index 33c0294..2b59cc6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,9 @@
# Ignore the test DB
db/test.sqlite3
+# Ignore the SimpleCov output
+coverage
+
# Ignore database configuration and token secrets
config/database.yml
config/secrets.yml
diff --git a/.travis.yml b/.travis.yml
index 6bbd6e5..bc14e2d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,6 +5,9 @@
before_script:
- cp config/database_example.yml config/database.yml
- cp config/secrets_example.yml config/secrets.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
script:
diff --git a/Gemfile b/Gemfile
index 6c77fdc..35ee76e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -15,10 +15,10 @@
# ------------------------------------------------
# DATABASE/SERVER
+gem 'mysql2', '~> 0.3.18'
gem 'pg'
gem 'flag_shih_tzu' # Allows for bitfields in activereccord
-
# ------------------------------------------------
# JS <-> RUBY BRIDGE
gem 'libv8'
@@ -47,6 +47,8 @@
gem 'devise_invitable'
gem 'omniauth'
gem 'omniauth-shibboleth'
+gem 'omniauth-orcid'
+
#rolify for roles
gem 'rolify'
# Gems for repository integration
@@ -63,7 +65,7 @@
gem 'jquery-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 'contact_us', '>= 1.2.0' # COULD BE EASILY REPLACED WITH OUR OWN CODE
gem 'recaptcha'
gem 'dragonfly' # LOGO UPLOAD
@@ -103,7 +105,9 @@
gem 'minitest-rails-capybara'
gem 'minitest-reporters'
gem 'rack-test'
+ gem 'webmock'
gem 'sqlite3'
+ gem 'simplecov', require: false
end
group :development do
diff --git a/Gemfile.lock b/Gemfile.lock
index 432daf6..8359a7c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -108,6 +108,8 @@
concurrent-ruby (1.0.2)
contact_us (1.2.0)
rails (>= 4.2.0)
+ crack (0.4.3)
+ safe_yaml (~> 1.0.0)
daemons (1.2.4)
debug_inspector (0.0.2)
devise (4.2.0)
@@ -119,6 +121,7 @@
devise_invitable (1.7.0)
actionmailer (>= 4.0.0)
devise (>= 4.0.0)
+ docile (1.1.5)
dragonfly (1.0.12)
addressable (~> 2.3)
multi_json (~> 1.0)
@@ -146,6 +149,7 @@
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)
actionpack
@@ -169,6 +173,7 @@
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)
@@ -211,13 +216,26 @@
minitest (>= 5.0)
ruby-progressbar
multi_json (1.12.1)
+ multi_xml (0.5.5)
multipart-post (2.0.0)
+ mysql2 (0.3.21)
nokogiri (1.6.8)
mini_portile2 (~> 2.1.0)
pkg-config (~> 1.1.7)
+ oauth2 (1.2.0)
+ faraday (>= 0.8, < 0.10)
+ jwt (~> 1.0)
+ multi_json (~> 1.3)
+ multi_xml (~> 0.5)
+ rack (>= 1.2, < 3)
omniauth (1.3.1)
hashie (>= 1.2, < 4)
rack (>= 1.0, < 3)
+ omniauth-oauth2 (1.4.0)
+ oauth2 (~> 1.0)
+ omniauth (~> 1.2)
+ omniauth-orcid (1.2.1)
+ omniauth-oauth2 (~> 1.3)
omniauth-shibboleth (1.2.1)
omniauth (>= 1.0.0)
orm_adapter (0.5.0)
@@ -274,6 +292,7 @@
rolify (5.1.0)
ruby-progressbar (1.8.1)
rubyzip (1.2.0)
+ safe_yaml (1.0.4)
sass (3.4.22)
sass-rails (5.0.6)
railties (>= 4.0.0, < 6)
@@ -282,6 +301,11 @@
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
sax-machine (1.3.2)
+ simplecov (0.12.0)
+ docile (~> 1.1.0)
+ json (>= 1.8, < 3)
+ simplecov-html (~> 0.10.0)
+ simplecov-html (0.10.0)
sprockets (3.7.0)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
@@ -321,6 +345,10 @@
binding_of_caller (>= 0.7.2)
railties (>= 4.0)
sprockets-rails (>= 2.0, < 4.0)
+ webmock (2.1.0)
+ addressable (>= 2.3.6)
+ crack (>= 0.3.2)
+ hashdiff
wicked_pdf (1.1.0)
wkhtmltopdf-binary (0.12.3)
xpath (2.0.0)
@@ -354,7 +382,9 @@
libv8
minitest-rails-capybara
minitest-reporters
+ mysql2 (~> 0.3.18)
omniauth
+ omniauth-orcid
omniauth-shibboleth
pg
protected_attributes
@@ -368,6 +398,7 @@
responders (~> 2.0)
rolify
sass-rails
+ simplecov
sqlite3
swagger-docs
therubyracer (>= 0.11.4)
@@ -376,6 +407,7 @@
twitter-bootstrap-rails (= 2.2.8)
uglifier
web-console (~> 2.0)
+ webmock
wicked_pdf
wkhtmltopdf-binary
yaml_db!
diff --git a/README.md b/README.md
index 597ae17..88ceaba 100644
--- a/README.md
+++ b/README.md
@@ -15,87 +15,22 @@
#### Summary
-#### Pre-requisites
-Roadmap is a Ruby on Rails application and you will need to have:
-1. Ruby >= 2.0.0p247
-2. Rails >= 4.0
-3. MySql >= 5.0
+#### Installation and Requirements
+See the [Installation Guide](https://github.com/DMPRoadmap/roadmap/wiki/Installation)
-Further details on how to install Ruby on Rails applications are available from the Ruby on Rails site: http://rubyonrails.org
+#### 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 mysql db. Select UTF-8 Unicode (utf8mb4) encoding.
-* Fork the repository and then clone it onto your server
-
-> > 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
-
-* 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:migrate
-
-> > rake db:seed
-
-* Setup the devise authentication gem
-
-> > rails generate devise:install (Is this really necessary?)
-
-* 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' - 'password1'
#### Troubleshooting
-##### Installation - OSX:
-
-```
-An error occurred while installing libv8 (3.11.8.17), and Bundler cannot continue.
-
-Make sure that `gem install libv8 -v '3.11.8.17'` succeeds before bundling.
-```
-
-If you are installing on a system that already has v8 installed then you may need to install the libv8 gem manually using your system's current v8 engine. If you're using homebrew to manage your packages you should run 'brew update' and 'brew upgrade' to make sure you have the latest packages
-
-> > gem uninstall -a libv8
-
-> > gem install libv8 -v '<>' -- --with-system-v8
-
-> > bundle install
+See the [Troubleshooting Guide](https://github.com/DMPRoadmap/roadmap/wiki/Troubleshooting)
#### 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
-Fork this repository and make your modifications in a new branch. Then create a pull request to our 'development' branch. We will reject any pull request made against the 'master' branch. Once your pull request has been submitted the team will review your request and accept it if appropriate.
-
-Join the developer email listserv at www.jiscmail.ac.uk/DMPONLINE-DEV
+See the [Contributor Guide](https://github.com/DMPRoadmap/roadmap/wiki/Contributing)
#### License
The DMP Roadmap project uses the MIT License.
diff --git a/app/admin/org_token_permission.rb b/app/admin/org_token_permission.rb
deleted file mode 100644
index 4075d5cf..0000000
--- a/app/admin/org_token_permission.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-ActiveAdmin.register OrgTokenPermission do
- permit_params :organisation_id, :token_permission_type_id
-
- menu priority: 40, label: proc{ I18n.t('admin.org_token_permission')}, parent: "Api"
-
- index do
- column I18n.t('admin.org') do |n|
- link_to n.organisation, [:admin,n]
- end
- column I18n.t('admin.token_permission') do |n|
- link_to n.token_permission_type, [:admin,n]
- end
-
- actions
- end
-
- show do
- attributes_table do
- row :organisation_id
- row :token_permission_type_id
- end
- end
-
- controller do
- def permitted_params
- params.permit!
- end
- end
-
-
-end
diff --git a/app/controllers/api/v0/base_controller.rb b/app/controllers/api/v0/base_controller.rb
index 7e939fd..b36bfa8 100644
--- a/app/controllers/api/v0/base_controller.rb
+++ b/app/controllers/api/v0/base_controller.rb
@@ -131,7 +131,7 @@
# end
# end
# end
- OrgTokenPermission.where(organisation_id: @user.organisation_id).find_each do |org_token_permission|
+ 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
diff --git a/app/controllers/api/v0/dmptemplates_controller.rb b/app/controllers/api/v0/dmptemplates_controller.rb
deleted file mode 100644
index 0e0a256..0000000
--- a/app/controllers/api/v0/dmptemplates_controller.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-module Api
- module V0
- class DmptemplatesController < Api::V0::BaseController
- before_action :authenticate
-
-
- ##
- # GET
- # @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"))
- @all_templates = Dmptemplate.all
- respond_with @all_templates
- else
- #render unauthorised
- render json: I18n.t("api.no_auth_for_endpoint"), status: 401
- end
-
- end
- end
- end
-end
\ No newline at end of file
diff --git a/app/controllers/api/v0/guidance_groups_controller.rb b/app/controllers/api/v0/guidance_groups_controller.rb
index a22c9b2..d300b39 100644
--- a/app/controllers/api/v0/guidance_groups_controller.rb
+++ b/app/controllers/api/v0/guidance_groups_controller.rb
@@ -5,7 +5,7 @@
def show
# check if the user has permission to use the guidances api
- if has_auth(constant("api_endpoint_types.guidances"))
+ 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
@@ -18,7 +18,7 @@
end
def index
- if has_auth(constant("api_endpoint_types.guidances"))
+ if has_auth(constant("token_permission_types.guidances"))
@all_viewable_groups = GuidanceGroup.all_viewable(@user)
respond_with @all_viewable_groups
else
diff --git a/app/controllers/api/v0/plans_controller.rb b/app/controllers/api/v0/plans_controller.rb
new file mode 100644
index 0000000..ad76c3d
--- /dev/null
+++ b/app/controllers/api/v0/plans_controller.rb
@@ -0,0 +1,104 @@
+module Api
+ module V0
+ class ProjectsController < 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
+ 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
+ organization = Org.find_by name: params[:template][:organisation]
+
+ # if organization exists
+ if !organization.nil?
+ # if organization is funder
+ if organization.organisation_type == (OrganisationType.find_by(name: constant("organisation_types.funder")))
+ # if organization has only 1 template
+ if organization.dmptemplates.length == 1
+ # set template id
+ dmptemplate = organization.dmptemplates.first
+ # else if params.template.name specified && params.template.name == one of organization's tempates
+ elsif !organization.dmptemplates.find_by title: params[:template][:name].nil?
+ # set template id
+ dmptemplate = organization.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
+
+ 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
+
+ # 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 = Project.new
+ @project.title = params[:project][:title]
+ @project.dmptemplate = dmptemplate
+ @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
+ else
+
+ render json: I18n.t("api.no_auth_for_endpoint"), status: 400 and return
+ 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/projects_controller.rb b/app/controllers/api/v0/projects_controller.rb
deleted file mode 100644
index ad76c3d..0000000
--- a/app/controllers/api/v0/projects_controller.rb
+++ /dev/null
@@ -1,104 +0,0 @@
-module Api
- module V0
- class ProjectsController < 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
- 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
- organization = Org.find_by name: params[:template][:organisation]
-
- # if organization exists
- if !organization.nil?
- # if organization is funder
- if organization.organisation_type == (OrganisationType.find_by(name: constant("organisation_types.funder")))
- # if organization has only 1 template
- if organization.dmptemplates.length == 1
- # set template id
- dmptemplate = organization.dmptemplates.first
- # else if params.template.name specified && params.template.name == one of organization's tempates
- elsif !organization.dmptemplates.find_by title: params[:template][:name].nil?
- # set template id
- dmptemplate = organization.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
-
- 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
-
- # 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 = Project.new
- @project.title = params[:project][:title]
- @project.dmptemplate = dmptemplate
- @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
- else
-
- render json: I18n.t("api.no_auth_for_endpoint"), status: 400 and return
- 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 ec21140..f893bc5 100644
--- a/app/controllers/api/v0/statistics_controller.rb
+++ b/app/controllers/api/v0/statistics_controller.rb
@@ -8,7 +8,7 @@
# @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("api_endpoint_types.statistics"))
+ if has_auth(constant("token_permission_types.statistics"))
users = restrict_date_range(@user.organisations.first.users)
confirmed_users = []
users.each do |user|
@@ -29,7 +29,7 @@
# @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("api_endpoint_types.statistics"))
+ if has_auth(constant("token_permission_types.statistics"))
template = Dmptemplate.find(params[:id])
if template.organisation == @user.organisations.first
@template_count = restrict_date_range(template.projects).count
@@ -48,7 +48,7 @@
# 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("api_endpoint_types.statistics"))
+ if has_auth(constant("token_permission_types.statistics"))
@org_projects = []
@user.organisations.first.users.each do |user|
user.projects.each do |project|
@@ -70,7 +70,7 @@
# 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("api_endpoint_types.statistics"))
+ if has_auth(constant("token_permission_types.statistics"))
@org_projects = []
@user.organisations.first.users.each do |user|
user.projects.each do |project|
diff --git a/app/controllers/api/v0/templates_controller.rb b/app/controllers/api/v0/templates_controller.rb
new file mode 100644
index 0000000..3ab1207
--- /dev/null
+++ b/app/controllers/api/v0/templates_controller.rb
@@ -0,0 +1,34 @@
+module Api
+ module V0
+ class TemplatesController < Api::V0::BaseController
+ before_action :authenticate
+
+
+ ##
+ # GET
+ # @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
+
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb
index a64e773..6ce60fc 100644
--- a/app/controllers/plans_controller.rb
+++ b/app/controllers/plans_controller.rb
@@ -353,71 +353,51 @@
@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)
+ 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 ||= nil
+ #ep.format = request.format.try(:symbol)
ep.format = request.format.to_sym
- plan_settings = @plan.settings(:export)
+ 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.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
- 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
- end
- end
-
-
-
- private
-
-
- def get_most_recent( templates )
- groups = Hash.new
- templates.each do |t|
- k = t.dmptemplate_id
- if !groups.has_key?(k)
- groups[k] =t
- else
- other = groups[k]
- if other.version < t.version
- groups[k] = t
- end
- end
- end
- groups.values
- end
-
+ 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
+
+ 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
+ end
+ end
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 4e6d8e9..b23c6ca 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -169,116 +169,127 @@
# 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
+
+ # 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
+ # 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 = orgs_of_type(constant("organisation_types.funder")) + orgs_of_type(constant("organisation_types.institution")) + Org.orgs_with_parent_of_type(constant("organisation_types.institution"))
- guidance_groups = {}
- ggs = GuidanceGroup.guidance_groups_excluding(excluded_orgs)
- ggs.each do |gg|
- guidance_groups[gg.id] = gg.name
- end
+ 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 = orgs_of_type(constant("organisation_types.funder")) + orgs_of_type(constant("organisation_types.institution")) + Org.orgs_with_parent_of_type(constant("organisation_types.institution"))
+ 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
+ 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
+ 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
+ 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
+ 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
+ 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
- private
- 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] }
+ 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
@@ -294,7 +305,7 @@
# -----------------------------------------------------------
def get_always_available_guidance
# Exclude Funders, Institutions, or children of Institutions
- excluded_orgs = orgs_of_type(constant("organisation_types.funder")) +
+ 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"))
@@ -333,4 +344,42 @@
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/registrations_controller.rb b/app/controllers/registrations_controller.rb
index 0f74a00..a82b679 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -5,6 +5,31 @@
@languages = Language.all.order("name")
@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)
+ end
+
+ # GET /resource
+ def new
+ oauth = {provider: nil, uid: nil}
+ IdentifierScheme.all.each do |scheme|
+ oauth = session["devise.#{scheme.name.downcase}_data"] unless session["devise.#{scheme.name.downcase}_data"].nil?
+ end
+
+ @user = User.new
+
+ unless oauth.nil?
+ # The OAuth provider could not be determined or there was no unique UID!
+ if oauth[:provider].nil? || oauth[:uid].nil?
+ flash[:notice] = t('identifier_schemes.new_login_failure')
+
+ else
+ # Connect the new user with the identifier sent back by the OAuth provider
+ flash[:notice] = t('identifier_schemes.new_login_success')
+ UserIdentifier.create(identifier_scheme: oauth[:provider].upcase,
+ identifier: oauth[:uid],
+ user: @user)
+ end
+ end
end
# POST /resource
@@ -43,11 +68,16 @@
def update
- if user_signed_in? then
+ if user_signed_in? then
@user = User.find(current_user.id)
+ @orgs = Org.where(parent_id: nil).order("name")
+ @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
else
- render(file: File.join(Rails.root, 'public/403.html'), status: 403, layout: false)
+ render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false)
end
end
@@ -95,8 +125,11 @@
end
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case his password changed
- sign_in @user, bypass: true
- redirect_to({controller: "registrations", action: "edit"}, {notice: I18n.t('helpers.project.details_update_success')})
+
+ sign_in @user, bypass_sign_in: true
+
+ redirect_to({:controller => "registrations", :action => "edit"}, {:notice => I18n.t('helpers.project.details_update_success')})
+
else
render "edit"
end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 2bf4305..89a5f44 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -1,8 +1,22 @@
class SessionsController < Devise::SessionsController
+ # POST /auth/:provider/callback
+ # ---------------------------------------------------------------------
+=begin
+ def oauth_create
+ existing_user = User.find_by_email(params[:user][:email])
+
+ unless params[:omniauth].nil?
+ existing_user = UserIdentifier.find_by(identifier: params[:omniauth][:auth])
+ end
+ end
+=end
+
# Capture the user's shibboleth id if they're coming in from an IDP
+ # ---------------------------------------------------------------------
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])
diff --git a/app/controllers/settings/projects_controller.rb b/app/controllers/settings/projects_controller.rb
index 6ba2cd3..8b0f800 100644
--- a/app/controllers/settings/projects_controller.rb
+++ b/app/controllers/settings/projects_controller.rb
@@ -36,7 +36,7 @@
@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]
+ @all_columns -= ['name']
end
def settings_json
diff --git a/app/controllers/static_pages_controller.rb b/app/controllers/static_pages_controller.rb
index c371a2f..da81ea8 100644
--- a/app/controllers/static_pages_controller.rb
+++ b/app/controllers/static_pages_controller.rb
@@ -14,5 +14,62 @@
def roadmap
end
+
+ # GET /projects/publicly_available
+ # -----------------------------------------------------------
+ def public_plans
+ @projects = Project.publicly_visible.order(title: :asc)
+ end
+ # GET /projects/[:project_slug]/public_export
+ # -------------------------------------------------------------
+ def public_export
+ @project = Project.find(params[:id])
+
+ # Force PDF response
+ request.format = :pdf
+
+ # if the project is designated as public
+ if @project.visibility == :publicly_visible
+ @plan = @project.plans.first
+
+ 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
+
+ @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
+
+ 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
+ # 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
+ end
end
\ No newline at end of file
diff --git a/app/controllers/templates_controller.rb b/app/controllers/templates_controller.rb
index 075371b..5601a7b 100644
--- a/app/controllers/templates_controller.rb
+++ b/app/controllers/templates_controller.rb
@@ -3,445 +3,289 @@
# [+Copyright:+] Digital Curation Centre and University of California Curation Center
class TemplatesController < ApplicationController
+ respond_to :html
after_action :verify_authorized
# GET /dmptemplates
def admin_index
authorize Template
- #institutional templates
- @dmptemplates_own = Template.own_institutional_templates(current_user.org_id)
+ #institutional templates
+ all_versions_own_templates = Template.where(org_id: current_user.org_id, customization_of: nil).order(version: :desc)
+ current_templates = {}
+ all_versions_own_templates.each do |temp|
+ if current_templates[temp.dmptemplate_id].nil?
+ current_templates[temp.dmptemplate_id] = temp
+ end
+ end
+ @templates_own = current_templates.values
#funders templates
- @dmptemplates_funders = Template.funders_templates
+ @templates_funders = Template.funders_templates
end
+
# GET /dmptemplates/1
def admin_template
- @dmptemplate = Dmptemplate.find(params[:id])
- authorize @dmptemplate
- respond_to do |format|
- format.html # show.html.erb
- end
+ @template = Template.find(params[:id])
+ authorize @template
end
-
# PUT /dmptemplates/1
def admin_update
- @dmptemplate = Dmptemplate.find(params[:id])
- authorize @dmptemplate
- @dmptemplate.description = params["template-desc"]
- respond_to do |format|
- if @dmptemplate.update_attributes(params[:dmptemplate])
- format.html { redirect_to admin_template_dmptemplate_path(params[:dmptemplate]), notice: I18n.t('org_admin.templates.updated_message') }
- else
- format.html { render action: "edit" }
- end
- end
+ @template = Template.find(params[:id])
+ authorize @template
+ @template.description = params["template-desc"]
+ if @template.update_attributes(params[:template])
+ redirect_to admin_template_template_path(params[:template]), notice: I18n.t('org_admin.templates.updated_message')
+ else
+ render action: "edit"
+ end
end
# GET /dmptemplates/new
def admin_new
- @dmptemplate = Dmptemplate.new
- authorize @dmptemplate
- respond_to do |format|
- format.html # new.html.erb
- end
+ authorize Template
end
+
# POST /dmptemplates
+ # creates a new template with version 0 and new dmptemplate_id
def admin_create
- @dmptemplate = Dmptemplate.new(params[:dmptemplate])
- @dmptemplate.organisation_id = current_user.organisation.id
- @dmptemplate.description = params['template-desc']
- authorize @dmptemplate
- respond_to do |format|
- if @dmptemplate.save
- format.html { redirect_to admin_template_dmptemplate_path(@dmptemplate), notice: I18n.t('org_admin.templates.created_message') }
- else
- format.html { render action: "admin_new" }
- end
+ @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
+ if @template.save
+ redirect_to admin_template_template_path(@template), notice: I18n.t('org_admin.templates.created_message')
+ else
+ render action: "admin_new"
end
end
-
# DELETE /dmptemplates/1
def admin_destroy
- @dmptemplate = Dmptemplate.find(params[:id])
- authorize @dmptemplate
- @dmptemplate.destroy
- respond_to do |format|
- format.html { redirect_to admin_index_dmptemplate_path }
- end
- end
+ @template = Template.find(params[:id])
+ authorize @template
+ @template.destroy
+ redirect_to admin_index_template_path
+ end
-
-
- # PHASES
-
- #show and edit a phase of the template
- def admin_phase
- @phase = Phase.find(params[:id])
- authorize @phase.dmptemplate
- if !params.has_key?(:version_id) then
- @edit = 'false'
- #check for the most recent published version, if none is available then return the most recent one
- versions = @phase.versions.where('published = ?', true).order('updated_at DESC')
- if versions.any?() then
- @version = versions.first
- else
- @version = @phase.versions.order('updated_at DESC').first
- end
- # When the version_id is passed as an argument
- else
- @edit = params[:edit]
- @version = Version.find(params[:version_id])
- end
- #verify if there are any sections if not create one
- @sections = @version.sections
- if !@sections.any?() || @sections.count == 0 then
- @section = @version.sections.build
- @section.title = ''
- @section.version_id = params[:version_id]
- @section.number = 1
- @section.organisation_id = current_user.organisation.id
- @section.published = 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) then
- @open = true
- @section_id = params[:section_id].to_i
- end
- if params.has_key?(:question_id) then
- @question_id = params[:question_id].to_i
- end
- respond_to do |format|
- format.html
- end
- end
-
-
- #preview a phase
- def admin_previewphase
- @version = Version.find(params[:id])
- authorize @version.phase.dmptemplate
- respond_to do |format|
- format.html
- end
- end
-
-
- #add a new phase to a template
- def admin_addphase
- @dmptemplate = Dmptemplate.find(params[:id])
- @phase = Phase.new
- authorize @dmptemplate
- if @dmptemplate.phases.count == 0 then
- @phase.number = '1'
- else
- @phase.number = @dmptemplate.phases.count + 1
- end
- respond_to do |format|
- format.html
- end
- end
-
-
- #create a phase
- def admin_createphase
- @phase = Phase.new(params[:phase])
- authorize @phase.dmptemplate
- @phase.description = params["phase-desc"]
- @version = @phase.versions.build
- @version.title = "#{@phase.title} v.1"
- @version.phase_id = @phase.id
- @version.number = 1
- @version.published = false
- respond_to do |format|
- if @phase.save
- format.html { redirect_to admin_phase_dmptemplate_path(:id => @phase.id, :version_id => @version.id, :edit => 'true'), notice: I18n.t('org_admin.templates.created_message') }
- else
- format.html { render action: "admin_phase" }
- end
- end
+ # GET /templates/1
+ def admin_template_history
+ @template = Template.find(params[:id])
+ authorize @template
+ @templates = Template.where(dmptemplate_id: @template.dmptemplate_id).order(:version)
end
- #update a phase of a template
- def admin_updatephase
- @phase = Phase.find(params[:id])
- authorize @phase.dmptemplate
- @phase.description = params["phase-desc"]
- respond_to do |format|
- if @phase.update_attributes(params[:phase])
- format.html { redirect_to admin_phase_dmptemplate_path(@phase), notice: I18n.t('org_admin.templates.updated_message') }
- else
- format.html { render action: "admin_phase" }
- end
- end
- end
- #delete a version, sections and questions
- def admin_destroyphase
- @phase = Phase.find(params[:phase_id])
- authorize @phase.dmptemplate
- @dmptemplate = @phase.dmptemplate
+ # 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
- respond_to do |format|
- format.html { redirect_to admin_template_dmptemplate_path(@dmptemplate), notice: I18n.t('org_admin.templates.destroyed_message') }
- end
- end
-
-# VERSIONS
-
- #update a version of a template
- def admin_updateversion
- @version = Version.find(params[:id])
- authorize @version.phase.dmptemplate
- @version.description = params["version-desc"]
- @phase = @version.phase
- if @version.published && !@phase.dmptemplate.published then
- @phase.dmptemplate.published = true
- end
- if @version.published == true then
- @all_versions = @phase.versions.where('published = ?', true)
- @all_versions.each do |v|
- if v.id != @version.id && v.published == true then
- v.published = false
- v.save
- end
- end
- end
- respond_to do |format|
- if @version.update_attributes(params[:version])
- format.html { redirect_to admin_phase_dmptemplate_path(@phase, :version_id => @version.id, :edit => 'false'), notice: I18n.t('org_admin.templates.updated_message') }
- else
- format.html { render action: "admin_phase" }
- end
- end
- end
-
- #clone a version of a template
- def admin_cloneversion
- @old_version = Version.find(params[:version_id])
- authorize @old_version.phase.dmptemplate
- @version = @old_version.amoeba_dup
- @phase = @version.phase
- respond_to do |format|
- if @version.save
- format.html { redirect_to admin_phase_dmptemplate_path(@phase, :version_id => @version.id, :edit => 'true'), notice: I18n.t('org_admin.templates.updated_message') }
- else
- format.html { render action: "admin_phase" }
- end
- end
- end
-
- #delete a version, sections and questions
- def admin_destroyversion
- @version = Version.find(params[:version_id])
- authorize @version.phase.dmptemplate
- @phase = @version.phase
- @version.destroy
- respond_to do |format|
- format.html { redirect_to admin_phase_dmptemplate_path(@phase), notice: I18n.t('org_admin.templates.destroyed_message') }
- end
- end
-
+ redirect_to admin_template_template_path(@template), notice: I18n.t('org_admin.templates.destroyed_message')
+ end
# SECTIONS
- #create a section
- def admin_createsection
+ #create a section
+ def admin_createsection
@section = Section.new(params[:section])
- authorize @section.version.phase.dmptemplate
+ authorize @section.phase.template
@section.description = params["section-desc"]
- respond_to do |format|
- if @section.save
- format.html { redirect_to admin_phase_dmptemplate_path(:id => @section.version.phase_id, :version_id => @section.version_id, :section_id => @section.id, :edit => 'true'), notice: I18n.t('org_admin.templates.created_message') }
- else
- format.html { render action: "admin_phase" }
- end
- end
+ 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.version.phase.dmptemplate
- @section.description = params["section-desc-#{params[:id]}"]
- @version = @section.version
- @phase = @version.phase
- respond_to do |format|
- if @section.update_attributes(params[:section])
- format.html { redirect_to admin_phase_dmptemplate_path(:id => @phase.id, :version_id => @version.id, :section_id => @section.id , :edit => 'true'), notice: I18n.t('org_admin.templates.updated_message') }
- else
- format.html { render action: "admin_phase" }
- 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
+ end
- #delete a section and questions
- def admin_destroysection
- @section = Section.find(params[:section_id])
- authorize @section.version.phase.dmptemplate
- @version = @section.version
- @phase = @version.phase
+ #delete a section and questions
+ def admin_destroysection
+ @section = Section.find(params[:section_id])
+ authorize @section.phase.template
+ @phase = @section.phase
@section.destroy
- respond_to do |format|
- format.html { redirect_to admin_phase_dmptemplate_path(:id => @phase.id, :version_id => @version.id, :edit => 'true' ), notice: I18n.t('org_admin.templates.destroyed_message') }
- end
- end
+ 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.version.phase.dmptemplate
+ #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"]
- respond_to do |format|
- if @question.save
- format.html { redirect_to admin_phase_dmptemplate_path(:id => @question.section.version.phase_id, :version_id => @question.section.version_id, :section_id => @question.section_id, :question_id => @question.id, :edit => 'true'), notice: I18n.t('org_admin.templates.created_message') }
- else
- format.html { render action: "admin_phase" }
- end
- end
- end
-
- #update a question of a template
- def admin_updatequestion
- @question = Question.find(params[:id])
- authorize @question.section.version.phase.dmptemplate
- @question.guidance = params["question-guidance-#{params[:id]}"]
- @question.default_value = params["question-default-value-#{params[:id]}"]
- @section = @question.section
- @version = @section.version
- @phase = @version.phase
- respond_to do |format|
- if @question.update_attributes(params[:question])
- format.html { redirect_to admin_phase_dmptemplate_path(:id => @phase.id, :version_id => @version.id, :section_id => @section.id, :question_id => @question.id, :edit => 'true'), notice: I18n.t('org_admin.templates.updated_message') }
- else
- format.html { render action: "admin_phase" }
- end
+ 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
+ end
- #delete a version, sections and questions
- def admin_destroyquestion
- @question = Question.find(params[:question_id])
- authorize @question.section.version.phase.dmptemplate
- @section = @question.section
- @version = @section.version
- @phase = @version.phase
+ #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
- respond_to do |format|
- format.html { redirect_to admin_phase_dmptemplate_path(:id => @phase.id, :version_id => @version.id, :section_id => @section.id, :edit => 'true'), notice: I18n.t('org_admin.templates.destroyed_message') }
- end
- end
+ 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 ANSWERS
+ #create suggested answers
+ def admin_createsuggestedanswer
@suggested_answer = SuggestedAnswer.new(params[:suggested_answer])
- authorize @suggested_answer.question.section.version.phase.dmptemplate
- respond_to do |format|
- if @suggested_answer.save
- format.html { redirect_to admin_phase_dmptemplate_path(:id => @suggested_answer.question.section.version.phase_id, :version_id => @suggested_answer.question.section.version_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
- format.html { render action: "admin_phase" }
- end
+ 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.version.phase.dmptemplate
+ #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
- @version = @section.version
- @phase = @version.phase
-
- respond_to do |format|
- if @suggested_answer.update_attributes(params[:suggested_answer])
- format.html { redirect_to admin_phase_dmptemplate_path(:id => @phase.id, :version_id => @version.id, :section_id => @section.id, :question_id => @question.id, :edit => 'true'), notice: I18n.t('org_admin.templates.updated_message') }
- else
- format.html { render action: "admin_phase" }
- end
- end
- end
-
- #delete a suggested answer
- def admin_destroysuggestedanswer
- @suggested_answer = SuggestedAnswer.find(params[:suggested_answer])
- authorize @suggested_answer.question.section.version.phase.dmptemplate
- @question = @suggested_answer.question
- @section = @question.section
- @version = @section.version
- @phase = @version.phase
- @suggested_answer.destroy
- respond_to do |format|
- format.html { redirect_to admin_phase_dmptemplate_path(:id => @phase.id, :version_id => @version.id, :section_id => @section.id, :edit => 'true'), notice: I18n.t('org_admin.templates.destroyed_message') }
- end
- end
-
-# GUIDANCES
-
- #create a guidance
- def admin_createguidance
- @question = Question.find(params[:question][:id])
- authorize @question.section.version.phase.dmptemplate
- @guidance = Guidance.new(params[:guidance])
- @guidance.question_id = @question.id
- #@question.guidance = params["new-question-guidance"]
- #@question.default_value = params["new-question-default-value"]
- respond_to do |format|
- if @guidance.save
- format.html { redirect_to admin_phase_dmptemplate_path(:id => @question.section.version.phase_id, :version_id => @question.section.version_id, :section_id => @question.section_id, :question_id => @question.id, :edit => 'true'), notice: I18n.t('org_admin.templates.created_message') }
- else
- format.html { render action: "admin_phase" }
- end
- end
- end
-
- #update a guidance of a template
- def admin_updateguidance
- @question = Question.find(params[:id])
- authorize @question.section.version.phase.dmptemplate
- @question.guidance = params["question-guidance-#{params[:id]}"]
- @question.default_value = params["question-default-value-#{params[:id]}"]
- @section = @question.section
- @version = @section.version
- @phase = @version.phase
- respond_to do |format|
- if @question.update_attributes(params[:question])
- format.html { redirect_to admin_phase_dmptemplate_path(:id => @phase.id, :version_id => @version.id, :section_id => @section.id, :question_id => @question.id, :edit => 'true'), notice: I18n.t('org_admin.templates.updated_message') }
- else
- format.html { render action: "admin_phase" }
- end
+ @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 version, sections and guidance
- def admin_destroyguidance
- @question = Question.find(params[:question_id])
- authorize @question.section.version.phase.dmptemplate
- @section = @question.section
- @version = @section.version
- @phase = @version.phase
- @question.destroy
- respond_to do |format|
- format.html { redirect_to admin_phase_dmptemplate_path(:id => @phase.id, :version_id => @version.id, :section_id => @section.id, :edit => 'true'), notice: I18n.t('org_admin.templates.destroyed_message') }
- 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
diff --git a/app/controllers/user_identifiers_controller.rb b/app/controllers/user_identifiers_controller.rb
new file mode 100644
index 0000000..040a50b
--- /dev/null
+++ b/app/controllers/user_identifiers_controller.rb
@@ -0,0 +1,25 @@
+class UserIdentifiersController < ApplicationController
+
+ # 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
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/app/controllers/users/omniauth_callback_controller.rb b/app/controllers/users/omniauth_callback_controller.rb
deleted file mode 100644
index ee19c5c..0000000
--- a/app/controllers/users/omniauth_callback_controller.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
-
- 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
-end
diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb
new file mode 100644
index 0000000..9b65b77
--- /dev/null
+++ b/app/controllers/users/omniauth_callbacks_controller.rb
@@ -0,0 +1,116 @@
+class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
+ ##
+ # Dynamically build a handler for each omniauth provider
+ # -------------------------------------------------------------
+ IdentifierScheme.where(active: true).each do |scheme|
+ define_method(scheme.name.downcase) do
+ handle_omniauth(scheme)
+ end
+ end
+
+ ##
+ # Processes callbacks from an omniauth provider and directs the user to
+ # the appropriate page:
+ # Not logged in and uid had no match ---> Sign Up page
+ # Not logged in and uid had a match ---> Sign In and go to Home Page
+ # Signed in and uid had no match --> Save the uid and go to the Profile Page
+ # Signed in and uid had a match --> Go to the Home Page
+ #
+ # @scheme [IdentifierScheme] The IdentifierScheme for the provider
+ # -------------------------------------------------------------
+ def handle_omniauth(scheme)
+ user = User.from_omniauth(request.env["omniauth.auth"].nil? ? request.env : request.env["omniauth.auth"])
+
+ # If the user isn't logged in
+ if current_user.nil?
+ # If the uid didn't have a match in the system send them to register
+ if user.nil?
+ session["devise.#{scheme.name.downcase}_data"] = request.env["omniauth.auth"]
+ flash[:notice] = t('identifier_schemes.new_login_success')
+ redirect_to new_user_registration_url
+
+ # Otherwise sign them in
+ else
+ sign_in_and_redirect user, event: :authentication
+ set_flash_message(:notice, :success, kind: scheme.name) if is_navigational_format?
+ end
+
+ # The user is already logged in and just registering the uid with us
+ else
+ # If the user could not be found by that uid then attach it to their record
+ if user.nil?
+ if UserIdentifier.create(identifier_scheme: scheme,
+ identifier: request.env["omniauth.auth"].uid,
+ user: current_user)
+
+ flash[:notice] = t('identifier_schemes.connect_success', scheme: scheme.name)
+ else
+ flash[:notice] = t('identifier_schemes.connect_failure', scheme: scheme.name)
+ end
+ end
+
+ # Redirect to the User Profile page
+ 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
+end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 56f99a5..73851a3 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -1,41 +1,26 @@
module ApplicationHelper
- def resource_name
- :user
- end
-
- def resource
- @resource ||= User.new
- end
-
- def devise_mapping
- @devise_mapping ||= Devise.mappings[:user]
- end
-
- def javascript(*files)
- content_for(:head) { javascript_include_tag(*files) }
- end
- def link_to_add_object(name, f, association, css_class, i)
- new_object = f.object.class.reflect_on_association(association).klass.new
- fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
- j = i + 1
- new_object.number = j
- render(association.to_s.singularize + "_fields", :f => builder)
- end
- link_to_function(name, "add_object(this, \"#{association}\", \"#{escape_javascript(fields)}\")", :class => css_class)
+ def resource_name
+ :user
+ end
+
+ # ---------------------------------------------------------------------------
+ def resource
+ @resource ||= User.new
+ end
+
+ # ---------------------------------------------------------------------------
+ def devise_mapping
+ @devise_mapping ||= Devise.mappings[:user]
end
- def link_to_function(name, *args, &block)
- html_options = args.extract_options!.symbolize_keys
-
- function = block_given? ? update_page(&block) : args[0] || ''
- onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
- href = html_options[:href] || '#'
-
- content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick))
+ # ---------------------------------------------------------------------------
+ def javascript(*files)
+ content_for(:head) { javascript_include_tag(*files) }
end
- def hash_to_json_object(obj_name, hash)
+ # ---------------------------------------------------------------------------
+ def hash_to_js_json_variable(obj_name, hash)
"".html_safe
end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 4b326c1..e445a1a 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -44,10 +44,18 @@
shared_num = project.project_groups.count - 1
text = shared_num > 0 ? (t("helpers.yes_label") + " (with #{shared_num} people) ") : t("helpers.no_label")
[ "dmp_td_small", text ]
+ when 'visibility'
+ ["dmp_td_small", (project.visibility.nil? ? I18n.t("helpers.project.visibilities.labels.organisationally_visible") : I18n.t("helpers.project.visibilities.labels.#{project.visibility}"))]
when 'last_edited'
[ "dmp_td_small", l(project.latest_update.to_date, formats: :short) ]
when 'description'
[ "dmp_td_medium", (project.try(col) || "Unknown") ]
+ when 'non_link_name'
+ [ "dmp_td_big", project.title ]
+ when 'template'
+ ["dmp_td_big", project.dmptemplate.title]
+ when 'organisation'
+ ["dmp_td_medium", (project.organisation.nil? ? project.owner.organisation.name : project.organisation.name)]
else
[ "dmp_td_small", (project.try(col) || "Unknown") ]
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index e283051..ba5e6fa 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -6,7 +6,7 @@
# Define abilities for the passed in user here. For example:
#
user ||= User.new # guest user (not logged in)
- if user.has_role? constant("user_role_types.super_admin")
+ if user.has_role? constant("roles.super_admin")
can :manage, :all
else
can :read, :all
diff --git a/app/models/answer.rb b/app/models/answer.rb
index 02a1533..f27602f 100644
--- a/app/models/answer.rb
+++ b/app/models/answer.rb
@@ -1,4 +1,5 @@
class Answer < ActiveRecord::Base
+
##
# Associations
belongs_to :question
@@ -7,8 +8,32 @@
has_many :notes, dependent: :destroy
has_and_belongs_to_many :question_options, join_table: "answers_question_options"
+ has_many :notes
+
##
# 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, :option_ids , :as => [:default, :admin]
+ attr_accessible :text, :plan_id, :question_id, :user_id, :question_option_ids,
+ :question, :user, :plan, :question_options, :notes, :note_ids,
+ :as => [:default, :admin]
+
+ ##
+ # Validations
+ validates :user, :plan, :question, presence: true
+
+ # Make sure there is only one answer per question!
+ validates :question, uniqueness: {scope: [:plan],
+ message: I18n.t('helpers.answer.only_one_per_question')}
+
+ # The answer MUST have a text value if the question is NOT option based or a question_option if
+ # it is option based.
+ validates :text, presence: true, if: Proc.new{|a|
+ (a.question.nil? ? false : !a.question.question_format.option_based?)
+ }
+ validates :question_options, presence: true, if: Proc.new{|a|
+ (a.question.nil? ? false : a.question.question_format.option_based?)
+ }
+
+ # Make sure the plan and question are associated with the same template!
+ validates :plan, :question, answer_for_correct_template: true
end
diff --git a/app/models/exported_plan.rb b/app/models/exported_plan.rb
index 589f096..eb57e5c 100644
--- a/app/models/exported_plan.rb
+++ b/app/models/exported_plan.rb
@@ -1,7 +1,8 @@
class ExportedPlan < ActiveRecord::Base
include GlobalHelpers
- attr_accessible :plan_id, :user_id, :format, :as => [:default, :admin]
+# TODO: REMOVE AND HANDLE ATTRIBUTE SECURITY IN THE CONTROLLER!
+ attr_accessible :plan_id, :user_id, :format, :user, :plan, :as => [:default, :admin]
#associations between tables
belongs_to :plan
@@ -10,6 +11,7 @@
VALID_FORMATS = ['csv', 'html', 'json', 'pdf', 'text', 'xml', 'docx']
validates :format, inclusion: { in: VALID_FORMATS, message: I18n.t('helpers.plan.export.not_valid_format') }
+ validates :plan, :format, presence: true
# Store settings with the exported plan so it can be recreated later
# if necessary (otherwise the settings associated with the plan at a
@@ -18,10 +20,13 @@
s.key :export, defaults: Settings::Template::DEFAULT_SETTINGS
end
- # Getters to match Settings::Dmptemplate::VALID_ADMIN_FIELDS
+# TODO: Consider removing the accessor methods, they add no value. The view/controller could
+# just access the value directly from the project/plan: exported_plan.plan.project.title
+
+ # Getters to match Settings::Template::VALID_ADMIN_FIELDS
def project_name
name = self.plan.project.title
- name += " - #{self.plan.title}" if self.plan.project.dmptemplate.phases.count > 1
+ name += " - #{self.plan.title}" if self.plan.project.template.phases.count > 1
name
end
@@ -46,7 +51,7 @@
end
def funder
- org = self.plan.project.dmptemplate.try(:organisation)
+ org = self.plan.project.template.try(:organisation)
org.name if org.present? && org.organisation_type.try(:name) == constant("organisation_types.funder")
end
@@ -54,6 +59,16 @@
plan.project.organisation.try(:name)
end
+ def orcid
+ scheme = IdentifierScheme.find_by(name: 'orcid')
+ if self.user.nil?
+ ''
+ else
+ orcid = self.user.user_identifiers.where(identifier_scheme: scheme).first
+ (orcid.nil? ? '' : orcid.identifier)
+ end
+ end
+
# sections taken from fields settings
def sections
sections = self.plan.sections
@@ -92,18 +107,18 @@
def as_txt
output = "#{self.plan.project.title}\n\n#{self.plan.version.phase.title}\n"
-
-
-puts "SETTINGS: #{self.plan.inspect}"
-
- output += "\nDetails:\n#{self.plan.settings[:export][:fields][:admin].collect{|f| f.to_s}.join('\n')}\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"
+ end
self.sections.each do |section|
output += "\n#{section.title}\n"
self.questions_for_section(section).each do |question|
qtext = sanitize_text( question.text.gsub(/
/, ' * ') )
- output += "\n#{qtext}\n"
+ output += "\n* #{qtext}"
answer = self.plan.answer(question.id, false)
if answer.nil? || answer.text.nil? then
diff --git a/app/models/file_type.rb b/app/models/file_type.rb
deleted file mode 100644
index 7c836dc..0000000
--- a/app/models/file_type.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-class FileType < ActiveRecord::Base
- #attr_accessible :name, :icon_location, :icon_name, :icon_size
-end
diff --git a/app/models/file_upload.rb b/app/models/file_upload.rb
deleted file mode 100644
index eef1ca3..0000000
--- a/app/models/file_upload.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class FileUpload < ActiveRecord::Base
- ##
- # Associations
- belongs_to :file_type
-end
diff --git a/app/models/guidance.rb b/app/models/guidance.rb
index b6048f4..31f9012 100644
--- a/app/models/guidance.rb
+++ b/app/models/guidance.rb
@@ -13,10 +13,8 @@
##
# Associations
belongs_to :guidance_group
- belongs_to :question
+# 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"
@@ -27,15 +25,20 @@
+ validates :text, presence: true
+
+
##
# Determine if a guidance is in a group which belongs to a specified organisation
#
# @param org_id [Integer] the integer id for an organisation
# @return [Boolean] true if this guidance is in a group belonging to the specified organisation, false otherwise
def in_group_belonging_to?(org_id)
- if guidance_group.org_id == org_id
- return true
- end
+ unless guidance_group.nil?
+ if guidance_group.org.id == org_id
+ return true
+ end
+ end
return false
end
@@ -44,7 +47,7 @@
#
# @param org_id [Integer] the integer id for an organisation
# @return [Array] list of guidance
- def self.by_organisation(org_id)
+ def self.by_org(org_id)
org_guidance = []
# TODO: re-write below querry when guidance_in_group removed from model
Org.find_by(id: org_id).guidance_groups.each do |group|
@@ -83,27 +86,24 @@
guidance = Guidance.find_by(id: id)
viewable = false
- # guidances may belong to many guidance groups, so we check the above case for each
- guidance.guidance_groups.each do |guidance_group|
-
- # guidances are viewable if they are owned by any of the user's organisations
- user.org do |org|
- if guidance_group.org.id == org.id
+ unless guidance.nil?
+ unless guidance.guidance_group.nil?
+ # guidances are viewable if they are owned by any of the user's organisations
+ if guidance.guidance_group.org == user.org
+ viewable = true
+ end
+ # guidance groups are viewable if they are owned by the Managing Curation Center
+ 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
-
- # guidance groups are viewable if they are owned by the Managing Curation Center
- if guidance_group.organisation.id == Org.find_by( name: GlobalHelpers.constant("organisation_types.managing_organisation")).id
- viewable = true
- end
-
- # guidance groups are viewable if they are owned by a funder
- if guidance_group.organisation.organisation_type == OrganisationType.find_by( name: GlobalHelpers.constant("organisation_types.funder"))
- viewable = true
- end
end
-
+
return viewable
end
@@ -117,22 +117,20 @@
# @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.find_by name: GlobalHelpers.constant("organisation_types.managing_organisation")).guidance_groups
+ managing_groups = Org.managing_orgs.collect{|o| o.guidance_groups}
# find all groups owned by a Funder organisation
funder_groups = []
- funders = OrganisationType.find_by( name: GlobalHelpers.constant("organisation_types.funder"))
- funders.organisations.each do |funder|
+ funders = Org.funders
+ funders.each do |funder|
funder_groups += funder.guidance_groups
end
# find all groups owned by any of the user's organisations
- organisation_groups = []
- user.organisations.each do |organisation|
- organisation_groups += organisation.guidance_groups
- end
+ 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.each do |group|
+ all_viewable_groups.flatten.each do |group|
all_viewable_guidances += group.guidances
end
# pass the list of viewable guidances to the view
diff --git a/app/models/guidance_group.rb b/app/models/guidance_group.rb
index e56b1cc..71535c3 100644
--- a/app/models/guidance_group.rb
+++ b/app/models/guidance_group.rb
@@ -5,15 +5,15 @@
belongs_to :org
has_many :guidances
# depricated but needed for migration "single_group_for_guidance"
- has_and_belongs_to_many :guidances, join_table: "guidance_in_group"
+ # has_and_belongs_to_many :guidances, join_table: "guidance_in_group"
##
# Possibly needed for active_admin
# -relies on protected_attributes gem as syntax depricated in rails 4.2
- attr_accessible :organisation_id, :name, :optional_subset, :published, :as => [:default, :admin]
- attr_accessible :dmptemplate_ids, :as => [:default, :admin]
+ attr_accessible :org_id, :name, :optional_subset, :published, :org, :guidances,
+ :as => [:default, :admin]
-
+ validates :name, :org, presence: true
# EVALUATE CLASS AND INSTANCE METHODS BELOW
@@ -23,15 +23,7 @@
-
-
- ##
- # Converts a guidance group to a string containing the display name
- #
- # @return [String] the name of the organisation, with or without the name of the guidance group
- def to_s
- "#{display_name}"
- end
+
##
# Converts the current guidance group to a string containing the display name.
@@ -53,14 +45,20 @@
#
# @param excluded_orgs [Array] a list of organisations to exclude in the result
# @return [Array] a list of guidance groups
- def self.guidance_groups_excluding(excluded_orgs)
- excluded_org_ids = Array.new
- excluded_orgs.each do |org|
- excluded_org_ids << org.id
- end
- return_orgs = GuidanceGroup.where("organisation_id NOT IN (?)", excluded_org_ids)
- return return_orgs
- end
+ def self.guidance_groups_excluding(excluded_orgs)
+ excluded_org_ids = Array.new
+
+ if excluded_orgs.is_a?(Array)
+ excluded_orgs.each do |org|
+ excluded_org_ids << org.id
+ end
+ else
+ excluded_org_ids << excluded_orgs
+ end
+
+ return_orgs = GuidanceGroup.where("org_id NOT IN (?)", excluded_org_ids)
+ return return_orgs
+ end
##
# Returns whether or not a given user can view a given guidance group
@@ -77,17 +75,17 @@
viewable = false
# groups are viewable if they are owned by any of the user's organisations
- if guidance_group.organisation == user.organisation
+ 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|
- if guidance_group.organisation.id == managing_group.id
+ 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.organisation.organisation_type == OrganisationType.find_by( name: GlobalHelpers.constant("organisation_types.funder"))
+ if guidance_group.org.org_type == 2
viewable = true
end
@@ -106,21 +104,21 @@
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|
+ 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
# find all groups owned by a Funder organisation
funder_groups = []
- funders = OrganisationType.find_by( name: GlobalHelpers.constant("organisation_types.funder"))
- funders.organisations.each do |funder|
+ funders = Org.where(org_type: 2)
+ funders.each do |funder|
funder_groups = funder_groups + funder.guidance_groups
end
- organisation_groups = [user.organisation.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.uniq{|x| x.id}
+ all_viewable_groups = all_viewable_groups.flatten.uniq{|x| x.id}
return all_viewable_groups
end
end
diff --git a/app/models/identifier_scheme.rb b/app/models/identifier_scheme.rb
new file mode 100644
index 0000000..45b8922
--- /dev/null
+++ b/app/models/identifier_scheme.rb
@@ -0,0 +1,6 @@
+class IdentifierScheme < ActiveRecord::Base
+ has_many :user_identifiers
+ has_many :users, through: :user_identifiers
+
+ validates :name, uniqueness: true, presence: true
+end
\ No newline at end of file
diff --git a/app/models/language.rb b/app/models/language.rb
index a2bdaa0..0bb5a35 100644
--- a/app/models/language.rb
+++ b/app/models/language.rb
@@ -2,7 +2,8 @@
##
# Associations
has_many :users
-
+ has_many :orgs
+
##
# Validations
validates :abbreviation, presence: true, uniqueness: true
diff --git a/app/models/new_plan.rb b/app/models/new_plan.rb
new file mode 100644
index 0000000..1dac7cd
--- /dev/null
+++ b/app/models/new_plan.rb
@@ -0,0 +1,5 @@
+class NewPlan < ActiveRecord::Base
+ belongs_to :template
+ has_many :roles
+ has_many :users, through: :roles
+end
diff --git a/app/models/note.rb b/app/models/note.rb
index d314d19..74b3078 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -7,6 +7,8 @@
##
# Possibly needed for active_admin
# -relies on protected_attributes gem as syntax depricated in rails 4.2
- attr_accessible :question_id, :text, :user_id, :archived, :plan_id, :archived_by, :as => [:default, :admin]
-
+ attr_accessible :text, :user_id, :answer_id, :archived, :archived_by,
+ :answer, :user, :as => [:default, :admin]
+
+ validates :text, :answer, :user, presence: true
end
diff --git a/app/models/org.rb b/app/models/org.rb
index 4ede001..1e6764d 100644
--- a/app/models/org.rb
+++ b/app/models/org.rb
@@ -11,7 +11,8 @@
has_many :templates
has_many :users
has_many :suggested_answers
- has_and_belongs_to_many :token_permission_types, join_table: "org_token_permissions"
+
+ has_and_belongs_to_many :token_permission_types, join_table: "org_token_permissions", unique: true
##
# Possibly needed for active_admin
@@ -19,7 +20,8 @@
attr_accessible :abbreviation, :banner_text, :logo, :remove_logo,
:logo_file_name, :name, :target_url,
:organisation_type_id, :wayfless_entity, :parent_id, :sort_name,
- :token_permission_type_ids, :language_id, :contact_email
+ :token_permission_type_ids, :language_id, :contact_email,
+ :language, :org_type, :region, :token_permission_types
##
# Validators
@@ -44,6 +46,9 @@
6 => :school,
column: 'org_type'
+ # Predefined queries for retrieving the managain organisation and funders
+ scope :managing_orgs, -> { where(name: GlobalHelpers.constant("organisation_types.managing_organisation")) }
+ scope :funders, -> { where(org_type: 2) }
# EVALUATE CLASS AND INSTANCE METHODS BELOW
@@ -190,7 +195,7 @@
#
# @return [Array] published dmptemplates
def published_templates
- return dmptemplates.where("published = ?", true)
+ return templates.where("published = ?", true)
end
def check_api_credentials
diff --git a/app/models/perm.rb b/app/models/perm.rb
index 7d17efb..114c0f0 100644
--- a/app/models/perm.rb
+++ b/app/models/perm.rb
@@ -7,4 +7,6 @@
# Possibly needed for active_admin
# -relies on protected_attributes gem as syntax depricated in rails 4.2
attr_accessible :name, :as => [:default, :admin]
+
+ validates :name, presence: true, uniqueness: true
end
diff --git a/app/models/phase.rb b/app/models/phase.rb
index a9814b9..49029f8 100644
--- a/app/models/phase.rb
+++ b/app/models/phase.rb
@@ -8,20 +8,22 @@
##
# Associations
- belongs_to :template, dependent: :destroy
+ belongs_to :template
has_many :sections, dependent: :destroy
has_many :questions, :through => :sections, dependent: :destroy
##
# Possibly needed for active_admin
# -relies on protected_attributes gem as syntax depricated in rails 4.2
- attr_accessible :description, :number, :title, :dmptemplate_id, :as => [:default, :admin]
+ attr_accessible :description, :number, :title, :template_id,
+ :template, :sections, :modifiable, :as => [:default, :admin]
##
# sluggable title
friendly_id :title, use: [:slugged, :history, :finders]
+ validates :title, :number, :template, presence: true
@@ -40,54 +42,48 @@
# returns the title of the phase
#
# @return [String] the title of the phase
- def to_s
- "#{title}"
- end
+ def to_s
+ "#{title}"
+ end
+# TODO: This function does not belong here anymore. It may be useless now.
##
- # returns the most_recent version of this phase
- #
- # @return [Version] the most recent version of this phase
- def latest_version
- return versions.order("number DESC").last
- end
-
- ##
- # returns either the latest published version of this phase
+ # returns either the latest published version of this phase
# also serves to verify if this phase has any published versions as returns nil
# if there are no published versions
#
# @return [Version, nil]
- def latest_published_version
- pub_vers = versions.where('published = ?', true).order('updated_at DESC')
- if pub_vers.any?() then
- return pub_vers.first
- else
- return nil
- end
- end
+# def latest_published_version
+# pub_vers = versions.where('published = ?', true).order('updated_at DESC')
+# if pub_vers.any?() then
+# return pub_vers.first
+# else
+# return nil
+# end
+# end
+# TODO: reevaluate this method. It seems like the 1st query is unecessary
##
- # verify if a phase has a published version or a version with one or more sections
+ # verify if a phase has a published version or a version with one or more sections
#
# @return [Boolean]
- def has_sections
- versions = self.versions.where('published = ?', true).order('updated_at DESC')
- if versions.any? then
- version = versions.first
- if !version.sections.empty? then
- has_section = true
- else
- has_section = false
- end
- else
- version = self.versions.order('updated_at DESC').first
- if !version.sections.empty? then
- has_section = true
- else
- has_section = false
- end
- end
- return has_section
- end
+ def has_sections
+ versions = self.versions.where('published = ?', true).order('updated_at DESC')
+ if versions.any? then
+ version = versions.first
+ if !version.sections.empty? then
+ has_section = true
+ else
+ has_section = false
+ end
+ else
+ version = self.versions.order('updated_at DESC').first
+ if !version.sections.empty? then
+ has_section = true
+ else
+ has_section = false
+ end
+ end
+ return has_section
+ end
end
diff --git a/app/models/plan.rb b/app/models/plan.rb
index ca035d5..b75a662 100644
--- a/app/models/plan.rb
+++ b/app/models/plan.rb
@@ -13,29 +13,39 @@
has_many :guidance_groups, through: :plan_guidance_groups
accepts_nested_attributes_for :template
+ has_many :exported_plans
##
# Possibly needed for active_admin
# -relies on protected_attributes gem as syntax depricated in rails 4.2
- attr_accessible :title, :identifier, :grant_number,
- :principal_investigator, :principal_investigator_identifier,
- :data_contact, :description
+ attr_accessible :locked, :project_id, :version_id, :version, :plan_sections,
+ :exported_plans, :project, :title, :template, :grant_number,
+ :identifier, :principal_investigator, :principal_investigator_identifier,
+ :description, :data_contact, :funder_name, :visibility, :exported_plans,
+ :roles, :users, :as => [:default, :admin]
+ accepts_nested_attributes_for :roles
+
+ # public is a Ruby keyword so using publicly
+ enum visibility: [:organisationally_visible, :publicly_visible, :is_test, :privately_visible]
+
+ validates :template, :title, :users, presence: true
+
##
# Constants
- A4_PAGE_HEIGHT = 297 #(in mm)
- A4_PAGE_WIDTH = 210 #(in mm)
- ROUNDING = 5 #round estimate up to nearest 5%
- 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
+ A4_PAGE_HEIGHT = 297 #(in mm)
+ A4_PAGE_WIDTH = 210 #(in mm)
+ ROUNDING = 5 #round estimate up to nearest 5%
+ 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
##
# Settings for the template
- has_settings :export, class_name: 'Settings::Template' do |s|
- s.key :export, defaults: Settings::Template::DEFAULT_SETTINGS
- end
- alias_method :super_settings, :settings
+ has_settings :export, class_name: 'Settings::Template' do |s|
+ s.key :export, defaults: Settings::Template::DEFAULT_SETTINGS
+ end
+ alias_method :super_settings, :settings
-
+
def new
if user_signed_in? then
@@ -60,17 +70,18 @@
##
- # Proxy through to the template settings (or defaults if this plan doesn't have
- # an associated template) if there are no settings stored for this plan.
- # `key` is required by rails-settings, so it's required here, too.
+ # Proxy through to the template settings (or defaults if this plan doesn't have
+ # an associated template) if there are no settings stored for this plan.
+ # `key` is required by rails-settings, so it's required here, too.
#
# @param key [Key] a key required by rails
# @return [Settings] settings for this plan's template
- def settings(key)
- self_settings = self.super_settings(key)
- return self_settings if self_settings.value?
- self.dmptemplate.settings(key)
- end
+ def settings(key)
+ self_settings = self.super_settings(key)
+ return self_settings if self_settings.value?
+# self.dmptemplate.settings(key)
+ self.template.settings(key) unless self.template.nil?
+ end
##
# returns the template for this plan, or generates an empty template and returns that
@@ -81,25 +92,7 @@
self.template
end
-# DON'T THINK WE NEED THIS ANYMORE - DELETE IF YOU ARE READING THIS
-# AND IT'S WORKING
-#
-# ##
-# # returns the title for this project as defined by the settings
-# #
-# # @return [String] the title for this project
-# def title
-# logger.debug "Title in settings: #{self.settings(:export).title}"
-# if self.settings(:export).title == ""
-# if !self.version.nil? && !self.version.phase.nil? && !self.version.phase.title? then
-# return self.version.phase.title
-# else
-# return I18n.t('tool_title2')
-# end
-# else
-# return self.settings(:export).title
-# end
-# end
+
##
# returns the most recent answer to the given question id
@@ -131,15 +124,6 @@
# returns all of the sections for this version of the plan, and for the project's organisation
#
# @return [Array,nil] either a list of sections, or nil if none were found
-# def sections
-# unless plan.organisation.nil? then
-# sections = version.global_sections + project.organisation.all_sections(version_id)
-# else
-# sections = version.global_sections
-# end
-# return sections.uniq.sort_by &:number
-# end
-
def set_possible_guidance_groups
# find all the themes in this plan
@@ -219,27 +203,27 @@
# @param theme [Theme] the theme object for the GuidanceGroup
# @param guidance [Guidance] the guidance object to be appended to the correct section of the array
# @return [{GuidanceGroup => {Theme => Array}}] the updated object which was passed in
- def add_guidance_to_array(guidance_array, guidance_group, theme, guidance)
- if guidance_array[guidance_group].nil? then
- guidance_array[guidance_group] = {}
- end
- if theme.nil? then
- if guidance_array[guidance_group]["no_theme"].nil? then
- guidance_array[guidance_group]["no_theme"] = []
- end
- if !guidance_array[guidance_group]["no_theme"].include?(guidance) then
- guidance_array[guidance_group]["no_theme"].push(guidance)
- end
- else
- if guidance_array[guidance_group][theme].nil? then
- guidance_array[guidance_group][theme] = []
- end
- if !guidance_array[guidance_group][theme].include?(guidance) then
- guidance_array[guidance_group][theme].push(guidance)
- end
- end
+ def add_guidance_to_array(guidance_array, guidance_group, theme, guidance)
+ if guidance_array[guidance_group].nil? then
+ guidance_array[guidance_group] = {}
+ end
+ if theme.nil? then
+ if guidance_array[guidance_group]["no_theme"].nil? then
+ guidance_array[guidance_group]["no_theme"] = []
+ end
+ if !guidance_array[guidance_group]["no_theme"].include?(guidance) then
+ guidance_array[guidance_group]["no_theme"].push(guidance)
+ end
+ else
+ if guidance_array[guidance_group][theme].nil? then
+ guidance_array[guidance_group][theme] = []
+ end
+ if !guidance_array[guidance_group][theme].include?(guidance) then
+ guidance_array[guidance_group][theme].push(guidance)
+ end
+ end
return guidance_array
- end
+ end
##
# determines if the plan is editable by the specified user
@@ -253,12 +237,14 @@
##
# determines if the plan is readable by the specified user
+ # TODO: introduce explicit readable rather than implicit
+ # currently role with no flags = readable
#
# @param user_id [Integer] the id for a user
# @return [Boolean] true if the user can read the plan
def readable_by?(user_id)
role = roles.where(user_id: user_id).first
- return role.present? && role.editor?
+ return role.present?
end
##
@@ -315,27 +301,27 @@
"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") ||
+ 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
- end
- end
+ 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
+ end
+ end
- status['space_used'] = estimate_space_used(space_used)
- return status
- end
+ status['space_used'] = estimate_space_used(space_used)
+ return status
+ end
##
@@ -344,35 +330,35 @@
# section: title, question text for each question, answer type and answer value
#
# @return [Details]
- def details
- details = {
- "project_title" => project.title,
- "phase_title" => version.phase.title,
- "sections" => {}
- }
- sections.sort_by(&:"number").each do |s|
- details["sections"][s.number] = {}
- details["sections"][s.number]["title"] = s.title
- details["sections"][s.number]["questions"] = {}
- s.questions.order("number").each do |q|
- details["sections"][s.number]["questions"][q.number] = {}
- details["sections"][s.number]["questions"][q.number]["question_text"] = q.text
- answer = answer(q.id, false)
- if ! answer.nil? then
+ def details
+ details = {
+ "project_title" => project.title,
+ "phase_title" => version.phase.title,
+ "sections" => {}
+ }
+ sections.sort_by(&:"number").each do |s|
+ details["sections"][s.number] = {}
+ details["sections"][s.number]["title"] = s.title
+ details["sections"][s.number]["questions"] = {}
+ s.questions.order("number").each do |q|
+ details["sections"][s.number]["questions"][q.number] = {}
+ details["sections"][s.number]["questions"][q.number]["question_text"] = q.text
+ answer = answer(q.id, false)
+ if ! answer.nil? then
q_format = q.question_format
- if (q_format.title == t("helpers.checkbox") || q_format.title == t("helpers.multi_select_box") ||
+ 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
- details["sections"][s.number]["questions"][q.number]["selections"] = {}
- answer.options.each do |o|
- details["sections"][s.number]["questions"][q.number]["selections"][o.number] = o.text
- end
- end
- details["sections"][s.number]["questions"][q.number]["answer_text"] = answer.text
- end
- end
- end
- return details
- end
+ details["sections"][s.number]["questions"][q.number]["selections"] = {}
+ answer.options.each do |o|
+ details["sections"][s.number]["questions"][q.number]["selections"][o.number] = o.text
+ end
+ end
+ details["sections"][s.number]["questions"][q.number]["answer_text"] = answer.text
+ end
+ end
+ end
+ return details
+ end
##
# determines wether or not a specified section of a plan is locked to a specified user and returns a status hash
@@ -380,55 +366,55 @@
# @param section_id [Integer] the setion to determine if locked
# @param user_id [Integer] the user to determine if locked for
# @return [Hash{String => Hash{String => Boolean, nil, String, Integer}}]
- def locked(section_id, user_id)
- plan_section = plan_sections.where("section_id = ? AND user_id != ? AND release_time > ?", section_id, user_id, Time.now).last
- if plan_section.nil? then
- status = {
- "locked" => false,
- "locked_by" => nil,
- "timestamp" => nil,
- "id" => nil
- }
- else
- status = {
- "locked" => true,
- "locked_by" => plan_section.user.name,
- "timestamp" => plan_section.updated_at,
- "id" => plan_section.id
- }
- end
- end
+ def locked(section_id, user_id)
+ plan_section = plan_sections.where("section_id = ? AND user_id != ? AND release_time > ?", section_id, user_id, Time.now).last
+ if plan_section.nil? then
+ status = {
+ "locked" => false,
+ "locked_by" => nil,
+ "timestamp" => nil,
+ "id" => nil
+ }
+ else
+ status = {
+ "locked" => true,
+ "locked_by" => plan_section.user.name,
+ "timestamp" => plan_section.updated_at,
+ "id" => plan_section.id
+ }
+ end
+ end
##
# for each section, lock the section with the given user_id
#
# @param user_id [Integer] the id for the user who can use the sections
- def lock_all_sections(user_id)
- sections.each do |s|
- lock_section(s.id, user_id, 1800)
- end
- end
+ def lock_all_sections(user_id)
+ sections.each do |s|
+ lock_section(s.id, user_id, 1800)
+ end
+ end
##
# for each section, unlock the section
#
# @param user_id [Integer] the id for the user to unlock the sections for
- def unlock_all_sections(user_id)
- plan_sections.where(:user_id => user_id).order("created_at DESC").each do |lock|
- lock.delete
- end
- end
+ def unlock_all_sections(user_id)
+ plan_sections.where(:user_id => user_id).order("created_at DESC").each do |lock|
+ lock.delete
+ end
+ end
##
# for each section, unlock the section
# Not sure how this is different from unlock_all_sections
#
# @param user_id [Integer]
- def delete_recent_locks(user_id)
- plan_sections.where(:user_id => user_id).each do |lock|
- lock.delete
- end
- end
+ def delete_recent_locks(user_id)
+ plan_sections.where(:user_id => user_id).each do |lock|
+ lock.delete
+ end
+ end
##
# Locks the specified section to only be used by the specified user, for the number of secconds specified
@@ -437,23 +423,23 @@
# @param user_id [Integer] the id of the user who can use the section
# @param release_time [Integer] the number of secconds the section will be locked for, defaults to 60
# @return [Boolean] wether or not the section was locked
- def lock_section(section_id, user_id, release_time = 60)
- status = locked(section_id, user_id)
- if ! status["locked"] then
- plan_section = PlanSection.new
- plan_section.plan_id = id
- plan_section.section_id = section_id
- plan_section.release_time = Time.now + release_time.seconds
- plan_section.user_id = user_id
- plan_section.save
- elsif status["current_user"] then
- plan_section = PlanSection.find(status["id"])
- plan_section.release_time = Time.now + release_time.seconds
- plan_section.save
- else
- return false
- end
- end
+ def lock_section(section_id, user_id, release_time = 60)
+ status = locked(section_id, user_id)
+ if ! status["locked"] then
+ plan_section = PlanSection.new
+ plan_section.plan_id = id
+ plan_section.section_id = section_id
+ plan_section.release_time = Time.now + release_time.seconds
+ plan_section.user_id = user_id
+ plan_section.save
+ elsif status["current_user"] then
+ plan_section = PlanSection.find(status["id"])
+ plan_section.release_time = Time.now + release_time.seconds
+ plan_section.save
+ else
+ return false
+ end
+ end
##
# unlocks the specified section for the specified user
@@ -461,28 +447,28 @@
# @param section_id [Integer] the id for the section to be unlocked
# @param user_id [Integer] the id for the user for whom the section was previously locked
# @return [Boolean] wether or not the lock was removed
- def unlock_section(section_id, user_id)
- plan_sections.where(:section_id => section_id, :user_id => user_id).order("created_at DESC").each do |lock|
- lock.delete
- end
- end
+ def unlock_section(section_id, user_id)
+ plan_sections.where(:section_id => section_id, :user_id => user_id).order("created_at DESC").each do |lock|
+ lock.delete
+ end
+ end
##
# returns the time of either the latest answer to any question, or the latest update to the model
#
# @return [DateTime] the time at which the plan was last changed
- def latest_update
- if answers.any? then
- last_answered = answers.order("updated_at DESC").first.updated_at
- if last_answered > updated_at then
- return last_answered
- else
- return updated_at
- end
- else
- return updated_at
- end
- end
+ def latest_update
+ if answers.any? then
+ last_answered = answers.order("updated_at DESC").first.updated_at
+ if last_answered > updated_at then
+ return last_answered
+ else
+ return updated_at
+ end
+ else
+ return updated_at
+ end
+ end
##
# returns an array of hashes. Each hash contains the question's id, the answer_id,
@@ -490,34 +476,34 @@
#
# @param section_id [Integer] the section to find answers of
# @return [Array nil,String,Integer,DateTime}]
- def section_answers(section_id)
- section = Section.find(section_id)
- section_questions = Array.new
- counter = 0
- section.questions.each do |q|
- section_questions[counter] = {}
- section_questions[counter]["id"] = q.id
- #section_questions[counter]["multiple_choice"] = q.multiple_choice
- q_answer = answer(q.id, false)
- if q_answer.nil? then
- section_questions[counter]["answer_id"] = nil
- if q.suggested_answers.find_by_organisation_id(project.organisation_id).nil? then
- section_questions[counter]["answer_text"] = ""
- else
- section_questions[counter]["answer_text"] = q.default_value
- end
- section_questions[counter]["answer_timestamp"] = nil
- section_questions[counter]["answer_options"] = Array.new
- else
- section_questions[counter]["answer_id"] = q_answer.id
- section_questions[counter]["answer_text"] = q_answer.text
- section_questions[counter]["answer_timestamp"] = q_answer.created_at
- section_questions[counter]["answer_options"] = q_answer.options.pluck(:id)
- end
- counter = counter + 1
- end
- return section_questions
- end
+ def section_answers(section_id)
+ section = Section.find(section_id)
+ section_questions = Array.new
+ counter = 0
+ section.questions.each do |q|
+ section_questions[counter] = {}
+ section_questions[counter]["id"] = q.id
+ #section_questions[counter]["multiple_choice"] = q.multiple_choice
+ q_answer = answer(q.id, false)
+ if q_answer.nil? then
+ section_questions[counter]["answer_id"] = nil
+ if q.suggested_answers.find_by_organisation_id(project.organisation_id).nil? then
+ section_questions[counter]["answer_text"] = ""
+ else
+ section_questions[counter]["answer_text"] = q.default_value
+ end
+ section_questions[counter]["answer_timestamp"] = nil
+ section_questions[counter]["answer_options"] = Array.new
+ else
+ section_questions[counter]["answer_id"] = q_answer.id
+ section_questions[counter]["answer_text"] = q_answer.text
+ section_questions[counter]["answer_timestamp"] = q_answer.created_at
+ section_questions[counter]["answer_options"] = q_answer.options.pluck(:id)
+ end
+ counter = counter + 1
+ end
+ return section_questions
+ end
@@ -530,6 +516,62 @@
Rails.logger.debug "RAY: assign_creator #{ user_id } to plan #{ self.inspect }"
add_user(user_id, true, true, true)
end
+
+
+
+
+ ##
+ # Based on the height of the text gathered so far and the available vertical
+ # space of the pdf, estimate a percentage of how much space has been used.
+ # This is highly dependent on the layout in the pdf. A more accurate approach
+ # would be to render the pdf and check how much space had been used, but that
+ # could be very slow.
+ # NOTE: This is only an estimate, rounded up to the nearest 5%; it is intended
+ # for guidance when editing plan data, not to be 100% accurate.
+ #
+ # @param used_height [Integer] an estimate of the height used so far
+ # @return [Integer] the estimate of space used of an A4 portrain
+ def estimate_space_used(used_height)
+ @formatting ||= self.settings(:export).formatting
+
+ return 0 unless @formatting[:font_size] > 0
+
+ margin_height = @formatting[:margin][:top].to_i + @formatting[:margin][:bottom].to_i
+ page_height = A4_PAGE_HEIGHT - margin_height # 297mm for A4 portrait
+ available_height = page_height * self.dmptemplate.settings(:export).max_pages
+
+ percentage = (used_height / available_height) * 100
+ (percentage / ROUNDING).ceil * ROUNDING # round up to nearest five
+ end
+
+ ##
+ # Take a guess at the vertical height (in mm) of the given text based on the
+ # font-size and left/right margins stored in the plan's settings.
+ # This assumes a fixed-width for each glyph, which is obviously
+ # incorrect for the font-face choices available; the idea is that
+ # they'll hopefully average out to that in the long-run.
+ # Allows for hinting different font sizes (offset from base via font_size_inc)
+ # and vertical margins (i.e. for heading text)
+ #
+ # @param text [String] the text to estimate size of
+ # @param font_size_inc [Integer] the size of the font of the text, defaults to 0
+ # @param vertical_margin [Integer] the top margin above the text, defaults to 0
+ def height_of_text(text, font_size_inc = 0, vertical_margin = 0)
+ @formatting ||= self.settings(:export).formatting
+ @margin_width ||= @formatting[:margin][:left].to_i + @formatting[:margin][:right].to_i
+ @base_font_size ||= @formatting[:font_size]
+
+ return 0 unless @base_font_size > 0
+
+ font_height = FONT_HEIGHT_CONVERSION_FACTOR * (@base_font_size + font_size_inc)
+ font_width = font_height * FONT_WIDTH_HEIGHT_RATIO # Assume glyph width averages at 2/5s the height
+ leading = font_height / 2
+
+ chars_in_line = (A4_PAGE_WIDTH - @margin_width) / font_width # 210mm for A4 portrait
+ num_lines = (text.length / chars_in_line).ceil
+
+ (num_lines * font_height) + vertical_margin + leading
+ end
diff --git a/app/models/question.rb b/app/models/question.rb
index 8b162a9..5493b79 100644
--- a/app/models/question.rb
+++ b/app/models/question.rb
@@ -20,8 +20,14 @@
##
# 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,:options_attributes, :suggested_answers_attributes, :option_comment_display, :theme_ids, :as => [:default, :admin]
+ attr_accessible :default_value, :dependency_id, :dependency_text, :guidance,:number,
+ :suggested_answer, :text, :section_id, :question_format_id,
+ :question_options_attributes, :suggested_answers_attributes,
+ :option_comment_display, :theme_ids, :section, :question_format,
+ :question_options, :suggested_answers, :answers, :themes,
+ :modifiable, :option_comment_display, :as => [:default, :admin]
+ validates :text, :section, :number, presence: true
# EVALUATE CLASS AND INSTANCE METHODS BELOW
@@ -38,80 +44,35 @@
"#{text}"
end
- def select_text
- cleantext = text.gsub(/<[^<]+>/, '')
- if cleantext.length > 120
- cleantext = cleantext.slice(0,120)
- end
- cleantext
- end
+# TODO: Commented this amoeba cloning gem definition out to see if its even used. The
+# amoeba documentations uses [object].amoeba_dup to clone the object, but that
+# command does not exist in the codebase
- amoeba do
- include_association :options
- include_association :suggested_answers
- clone [:themes]
- end
-
- #def question_type?
- # type_label = {}
- # if self.is_text_field?
- # type_label = 'Text field'
- # elsif self.multiple_choice?
- # type_label = 'Multiple choice'
- # else
- # type_label = 'Text area'
- # end
- # return type_label
- #end
+# amoeba do
+# include_association :options
+# include_association :suggested_answers
+# clone [:themes]
+# end
##
- # for each question theme, appends them separated by comas
- # shouldnt have a ? after the method name
+ # guidance for org
#
- # @return [Hash{String=> String}]
- def question_themes?
- themes_label = {}
- i = 1
- themes_quest = self.themes
-
- themes_quest.each do |tt|
- themes_label = tt.title
-
- if themes_quest.count > i then
- themes_label += ','
- i +=1
- end
- end
-
- return themes_label
- end
-
- ##
- # guidance for question in the org admin
- #
- # @param question [Question] the question to find guidance for
- # @param org_admin [Organisation] the organisation to find guidance for
+ # @param org [Org] the org to find guidance for
# @return [Hash{String => String}]
- def guidance_for_question(question, org_admin)
- # pulls together guidance from various sources for question
- guidances = {}
- theme_ids = question.theme_ids
-
- GuidanceGroup.where("organisation_id = ?", org_admin.id).each do |group|
- group.guidances.each do |g|
- g.themes.where("id IN (?)", theme_ids).each do |gg|
- guidances["#{group.name} " + I18n.t('admin.guidance_lowercase_on') + " #{gg.title}"] = g
- end
- end
+ def guidance_for_org(org)
+ # pulls together guidance from various sources for question
+ guidances = {}
+ theme_ids = themes.collect{|t| t.id}
+ if theme_ids.present?
+ GuidanceGroup.where(org_id: org.id).each do |group|
+ group.guidances.each do |g|
+ g.themes.where("id IN (?)", theme_ids).each do |gg|
+ guidances["#{group.name} " + I18n.t('admin.guidance_lowercase_on') + " #{gg.title}"] = g
+ end
end
- # Guidance link to directly to a question
- question.guidances.each do |g_by_q|
- g_by_q.guidance_groups.each do |group|
- if group.organisation == org_admin
- guidances["#{group.name} " + I18n.t('admin.guidance_lowercase')] = g_by_q
- end
- end
- end
+ end
+ end
+
return guidances
end
@@ -121,7 +82,7 @@
# @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_organisation_id(org_id)
+ suggested_answer = suggested_answers.find_by(org_id: org_id)
return suggested_answer
end
diff --git a/app/models/question_format.rb b/app/models/question_format.rb
index 29ad3b8..7f1a900 100644
--- a/app/models/question_format.rb
+++ b/app/models/question_format.rb
@@ -3,11 +3,13 @@
##
# Associations
has_many :questions
-
+
+ validates :title, presence: true, uniqueness: true
+
##
# Possibly needed for active_admin
# -relies on protected_attributes gem as syntax depricated in rails 4.2
- attr_accessible :title, :description, :as => [:default, :admin]
+ attr_accessible :title, :description, :option_based, :questions, :as => [:default, :admin]
# EVALUATE CLASS AND INSTANCE METHODS BELOW
diff --git a/app/models/question_option.rb b/app/models/question_option.rb
index b16b0d9..1a079d0 100644
--- a/app/models/question_option.rb
+++ b/app/models/question_option.rb
@@ -7,5 +7,8 @@
##
# Possibly needed for active_admin
# -relies on protected_attributes gem as syntax depricated in rails 4.2
- attr_accessible :text, :question_id, :is_default, :number, :as => [:default, :admin]
+ attr_accessible :text, :question_id, :is_default, :number, :question,
+ :as => [:default, :admin]
+
+ validates :text, :question, :number, presence: true
end
diff --git a/app/models/region.rb b/app/models/region.rb
index 8147fed..2c57e79 100644
--- a/app/models/region.rb
+++ b/app/models/region.rb
@@ -1,3 +1,8 @@
class Region < ActiveRecord::Base
-
+ has_many :sub_regions, class_name: 'Region', foreign_key: 'super_region_id'
+
+ belongs_to :super_region, class_name: 'Region'
+
+ validates :name, presence: true, uniqueness: true
+ validates :abbreviation, uniqueness: true, allow_nil: true
end
\ No newline at end of file
diff --git a/app/models/region_group.rb b/app/models/region_group.rb
deleted file mode 100644
index 8f83a83..0000000
--- a/app/models/region_group.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-class RegionGroup < ActiveRecord::Base
-
-end
\ No newline at end of file
diff --git a/app/models/section.rb b/app/models/section.rb
index 35d4aef..60fd094 100644
--- a/app/models/section.rb
+++ b/app/models/section.rb
@@ -5,14 +5,15 @@
belongs_to :phase
belongs_to :organisation
has_many :questions, :dependent => :destroy
- has_many :plan_sections, :dependent => :destroy
#Link the data
accepts_nested_attributes_for :questions, :reject_if => lambda {|a| a[:text].blank? }, :allow_destroy => true
# accepts_nested_attributes_for :version
- attr_accessible :organisation_id, :description, :number, :title, :version_id , :published, :questions_attributes, :as => [:default, :admin]
-
+ attr_accessible :organisation_id, :description, :number, :title, :published,
+ :questions_attributes, :organisation, :phase, :modifiable,
+ :as => [:default, :admin]
+
##
# return the title of the section
#
@@ -21,8 +22,11 @@
"#{title}"
end
- amoeba do
- include_association :questions
- end
+# TODO: Commented this amoeba cloning gem definition out to see if its even used. The
+# amoeba documentations uses [object].amoeba_dup to clone the object, but that
+# command does not exist in the codebase
+# amoeba do
+# include_association :questions
+# end
end
diff --git a/app/models/settings/plan_list.rb b/app/models/settings/plan_list.rb
index 17e93a9..812e2c8 100644
--- a/app/models/settings/plan_list.rb
+++ b/app/models/settings/plan_list.rb
@@ -5,7 +5,7 @@
# 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',
+ ALL_COLUMNS = DEFAULT_COLUMNS + ['template_owner', 'identifier', 'grant_number', 'visibility',
'principal_investigator', 'data_contact', 'description']
validate do
diff --git a/app/models/settings/template.rb b/app/models/settings/template.rb
index 7bc1968..2956eac 100644
--- a/app/models/settings/template.rb
+++ b/app/models/settings/template.rb
@@ -12,7 +12,7 @@
VALID_MARGIN_RANGE = (5..25)
VALID_ADMIN_FIELDS = ['project_name', 'project_identifier', 'grant_title', 'principal_investigator',
- 'project_data_contact', 'project_description', 'funder', 'institution']
+ 'project_data_contact', 'project_description', 'funder', 'institution', 'orcid']
DEFAULT_SETTINGS = {
formatting: {
diff --git a/app/models/suggested_answer.rb b/app/models/suggested_answer.rb
index 3e62265..5b94c8d 100644
--- a/app/models/suggested_answer.rb
+++ b/app/models/suggested_answer.rb
@@ -8,7 +8,8 @@
##
# Possibly needed for active_admin
# -relies on protected_attributes gem as syntax depricated in rails 4.2
- attr_accessible :organisation_id, :question_id, :text, :is_example, :as => [:default, :admin]
+ attr_accessible :org_id, :question_id, :text, :is_example,
+ :org, :question, :as => [:default, :admin]
# EVALUATE CLASS AND INSTANCE METHODS BELOW
diff --git a/app/models/template.rb b/app/models/template.rb
index 1ddcb9d..63b48de 100644
--- a/app/models/template.rb
+++ b/app/models/template.rb
@@ -12,7 +12,9 @@
##
# Possibly needed for active_admin
# -relies on protected_attributes gem as syntax depricated in rails 4.2
- attr_accessible :id, :organisation_id, :description, :published, :title, :locale, :is_default, :guidance_group_ids, :as => [:default, :admin]
+ attr_accessible :id, :org_id, :description, :published, :title, :locale,
+ :is_default, :guidance_group_ids, :org, :plans, :phases,
+ :version, :visibility, :published, :as => [:default, :admin]
# defines the export setting for a template object
has_settings :export, class_name: 'Settings::Template' do |s|
diff --git a/app/models/token_permission_type.rb b/app/models/token_permission_type.rb
index 0d1f291..a7362d9 100644
--- a/app/models/token_permission_type.rb
+++ b/app/models/token_permission_type.rb
@@ -2,7 +2,7 @@
##
# Associations
#has_and_belongs_to_many :org_token_permissions, join_table: "org_token_permissions"
- has_and_belongs_to_many :organisations, join_table: 'org_token_permissions'
+ has_and_belongs_to_many :organisations, join_table: 'org_token_permissions', unique: true
##
# Possibly needed for active_admin
diff --git a/app/models/user.rb b/app/models/user.rb
index 85fcc65..52672c4 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1,5 +1,6 @@
class User < ActiveRecord::Base
include GlobalHelpers
+
##
# Devise
# Include default devise modules. Others available are:
@@ -15,6 +16,7 @@
belongs_to :org
has_many :answers
has_many :notes
+ has_many :exported_plans
has_many :roles, dependent: :destroy
has_many :plans, through: :roles do
def filter(query)
@@ -30,6 +32,9 @@
self.where(conditions)
end
end
+
+ has_many :user_identifiers
+ has_many :identifier_schemes, through: :user_identifiers
##
# Possibly needed for active_admin
@@ -39,7 +44,7 @@
: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
+ :organisation, :language, :language_id, :org, :perms, :confirmed_at
validates :email, email: true, allow_nil: true, uniqueness: true
@@ -77,6 +82,15 @@
end
##
+ # Returns the user's identifier for the specified scheme name
+ #
+ # @param the identifier scheme name (e.g. ORCID)
+ # @return [UserIdentifier] the user's identifier for that scheme
+ def identifier_for(scheme)
+ user_identifiers.where(identifier_scheme: scheme).first
+ end
+
+ ##
# sets a new organisation id for the user
# if the user has any perms such as org_admin or admin, those are removed
# if the user had an api_token, that is removed
@@ -128,7 +142,7 @@
#
# @return [Boolean] true if the user can add new organisations
def can_add_orgs?
- perms.include? Perm.find_by(name: constant("user_role_types.add_organisations"))
+ perms.include? Perm.find_by(name: constant("roles.add_organisations"))
end
##
@@ -136,7 +150,7 @@
#
# @return [Boolean] true if the user can change their organisation affiliations
def can_change_org?
- perms.include? Perm.find_by(name: constant("user_role_types.change_org_affiliation"))
+ perms.include? Perm.find_by(name: constant("roles.change_org_affiliation"))
end
##
@@ -144,7 +158,7 @@
#
# @return [Boolean] true if the user can grant their permissions to others
def can_grant_permissions?
- perms.include? Perm.find_by(name: constant("user_role_types.grant_permissions"))
+ perms.include? Perm.find_by(name: constant("roles.grant_permissions"))
end
##
@@ -152,7 +166,7 @@
#
# @return [Boolean] true if the user can modify organisation templates
def can_modify_templates?
- perms.include? Perm.find_by(name: constant("user_role_types.modify_templates"))
+ perms.include? Perm.find_by(name: constant("roles.modify_templates"))
end
##
@@ -160,7 +174,7 @@
#
# @return [Boolean] true if the user can modify organistion guidance
def can_modify_guidance?
- perms.include? Perm.find_by(name: constant("user_role_types.modify_guidance"))
+ perms.include? Perm.find_by(name: constant("roles.modify_guidance"))
end
##
@@ -168,7 +182,7 @@
#
# @return [Boolean] true if the user can use the api
def can_use_api?
- perms.include? Perm.find_by(name: constant("user_role_types.use_api"))
+ perms.include? Perm.find_by(name: constant("roles.use_api"))
end
##
@@ -176,7 +190,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("user_role_types.change_org_details"))
+ perms.include? Perm.find_by(name: constant("roles.change_org_details"))
end
##
@@ -184,7 +198,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('user_role_types.grant_api_to_orgs'))
+ perms.include? Perm.find_by(name: constant('roles.grant_api_to_orgs'))
end
@@ -193,7 +207,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('user_role_types.grant_api_to_orgs'))
+ perms.include? Perm.find_by(name: constant('roles.grant_api_to_orgs'))
end
##
@@ -201,7 +215,7 @@
#
# @return [String] the organisation type
def org_type
- org_type = organisation.organisation_type.name
+ org_type = org.organisation_type
return org_type
end
@@ -226,12 +240,25 @@
end
self.save!
# send an email to the user to notify them of their new api token
- UserMailer.api_token_granted_notification(self)
+ #UserMailer.api_token_granted_notification(self)
end
end
+ ##
+ # Load the user based on the scheme and id provided by the Omniauth call
+ # --------------------------------------------------------------
+ def self.from_omniauth(auth)
+ scheme = IdentifierScheme.find_by(name: auth.provider.downcase)
+
+ if scheme.nil?
+ throw Exception.new('Unknown OAuth provider: ' + auth.provider)
+ else
+ joins(:user_identifiers).where('user_identifiers.identifier': auth.uid,
+ 'user_identifiers.identifier_scheme_id': scheme.id).first
+ end
+ end
- # this generates a reset password link for a given user
+ # this generates a reset password link for a given user
# which can then be sent to them with the appropriate host
# prepended.
def reset_password_link
diff --git a/app/models/user_identifier.rb b/app/models/user_identifier.rb
new file mode 100644
index 0000000..6623765
--- /dev/null
+++ b/app/models/user_identifier.rb
@@ -0,0 +1,9 @@
+class UserIdentifier < ActiveRecord::Base
+ belongs_to :user
+ belongs_to :identifier_scheme
+
+ # Should only be able to have one identifier per scheme!
+ validates_uniqueness_of :identifier_scheme, scope: :user
+
+ validates :identifier, :user, :identifier_scheme, presence: true
+end
\ No newline at end of file
diff --git a/app/policies/guidance_policy.rb b/app/policies/guidance_policy.rb
index 4aa8245..ee7be10 100644
--- a/app/policies/guidance_policy.rb
+++ b/app/policies/guidance_policy.rb
@@ -53,7 +53,7 @@
class Scope < Scope
def resolve
- scope = Guidance.includes(:guidance_group, :question, :themes).by_organisation(user.org_id)
+ scope = Guidance.includes(:guidance_group, :question, :themes).by_org(user.org_id)
end
end
end
\ No newline at end of file
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 60c76fd..9ca5bcc 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -39,4 +39,5 @@
def possible_guidance?
true
end
+
end
\ No newline at end of file
diff --git a/app/policies/template_policy.rb b/app/policies/template_policy.rb
index 3524c40..1fd64f5 100644
--- a/app/policies/template_policy.rb
+++ b/app/policies/template_policy.rb
@@ -31,6 +31,10 @@
user.can_modify_templates? && (template.org_id == user.org_id)
end
+ def admin_template_history?
+ user.can_modify_templates? && (template.org_id == user.org_id)
+ end
+
def admin_phase?
user.can_modify_templates? && (template.org_id == user.org_id)
end
diff --git a/app/validators/answer_for_correct_template_validator.rb b/app/validators/answer_for_correct_template_validator.rb
new file mode 100644
index 0000000..8ec15ee
--- /dev/null
+++ b/app/validators/answer_for_correct_template_validator.rb
@@ -0,0 +1,10 @@
+class AnswerForCorrectTemplateValidator < ActiveModel::Validator
+ def validate(record)
+ # Make sure that the question and plan belong to the same template!
+ unless record.plan.nil? || record.question.nil?
+ unless record.plan.template == record.question.section.phase.template
+ record.errors[:question] << I18n.t('helpers.answer.question_must_belong_to_correct_template')
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/validators/email_validator.rb b/app/validators/email_validator.rb
index a3cc4ed..d47e7c1 100644
--- a/app/validators/email_validator.rb
+++ b/app/validators/email_validator.rb
@@ -1,7 +1,7 @@
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
- #record.errors[attribute] << (options[:message] || "is not a valid email address")
+ record.errors[attribute] << (options[:message] || "is not a valid email address")
end
end
end
\ No newline at end of file
diff --git a/app/validators/url_validator.rb b/app/validators/url_validator.rb
new file mode 100644
index 0000000..a967c32
--- /dev/null
+++ b/app/validators/url_validator.rb
@@ -0,0 +1,7 @@
+class UrlValidator < ActiveModel::EachValidator
+ def validate_each(record, attribute, value)
+ unless value =~ /https?:\/\/[-a-zA-Z0-9@:%_\+.~#?&\/=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&\/=]*)?/
+ record.errors[attribute] << (options[:message] || "is not a valid URL")
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/views/api/v0/dmptemplates/index.json.jbuilder b/app/views/api/v0/dmptemplates/index.json.jbuilder
deleted file mode 100644
index 8ea25b3..0000000
--- a/app/views/api/v0/dmptemplates/index.json.jbuilder
+++ /dev/null
@@ -1,14 +0,0 @@
-# builds a json response to api query for a list of all dmptemplates
-json.prettify!
-
-json.templates Org.all.each do |org|
- unless org.published_templates.blank?
- json.organisation_name org.name
- json.organisation_id org.id
- json.organisation_templates org.published_templates.each do |template|
- json.title template.title
- json.id template.id
- json.description template.description
- 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
new file mode 100644
index 0000000..ebb8c58
--- /dev/null
+++ b/app/views/api/v0/plans/create.json.jbuilder
@@ -0,0 +1,15 @@
+# builds a json response to a successful project createtion
+
+json.prettify!
+
+json.project do
+ json.title @project.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
diff --git a/app/views/api/v0/plans/show.json.jbuilder b/app/views/api/v0/plans/show.json.jbuilder
new file mode 100644
index 0000000..2cd84bf
--- /dev/null
+++ b/app/views/api/v0/plans/show.json.jbuilder
@@ -0,0 +1,13 @@
+# builds a json response to a successful project createtion
+
+json.prettify!
+
+json.project do
+ json.title @project.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
+ #json.template @project.dmptemplate
+ json.dmptemplate @project.dmptemplate.title
+end
diff --git a/app/views/api/v0/projects/create.json.jbuilder b/app/views/api/v0/projects/create.json.jbuilder
deleted file mode 100644
index ebb8c58..0000000
--- a/app/views/api/v0/projects/create.json.jbuilder
+++ /dev/null
@@ -1,15 +0,0 @@
-# builds a json response to a successful project createtion
-
-json.prettify!
-
-json.project do
- json.title @project.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
diff --git a/app/views/api/v0/projects/show.json.jbuilder b/app/views/api/v0/projects/show.json.jbuilder
deleted file mode 100644
index 2cd84bf..0000000
--- a/app/views/api/v0/projects/show.json.jbuilder
+++ /dev/null
@@ -1,13 +0,0 @@
-# builds a json response to a successful project createtion
-
-json.prettify!
-
-json.project do
- json.title @project.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
- #json.template @project.dmptemplate
- json.dmptemplate @project.dmptemplate.title
-end
diff --git a/app/views/api/v0/templates/index.json.jbuilder b/app/views/api/v0/templates/index.json.jbuilder
new file mode 100644
index 0000000..643d87d
--- /dev/null
+++ b/app/views/api/v0/templates/index.json.jbuilder
@@ -0,0 +1,12 @@
+# builds a json response to api query for a list of all dmptemplates
+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
+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 73562ec..57596a5 100644
--- a/app/views/contact_us/contacts/new.html.erb
+++ b/app/views/contact_us/contacts/new.html.erb
@@ -97,18 +97,26 @@
<% end %>
+
-
+ <%= f.select :question_format_id,
+ #options_from_collection_for_select(QuestionFormat.all.order("title"), :id, :title, QuestionFormat.find_by_title(t("helpers.text_area")).id),
+ # the above was the line but it doesn't work because in the DB
+ # the QuestionFormat title is in English (Text area)
+ # but the above uses the Fr translation and so gets a nil
+ options_from_collection_for_select(QuestionFormat.all.order("title"), :id, :title, QuestionFormat.find_by_title("Text area").id),
+ {}, :id => "new-select-format-#{section.id}"%>
+
+ <% end %>
+
+ <% if current_user.can_org_admin? && (dmptemplate.org_type != constant("organisation_types.funder")|| current_user.org_type == constant("organisation_types.funder")) then %>
+ <% if active == 'add_plan' then %>
+
<% end %>
- <% if current_user.can_org_admin? && (dmptemplate.org_type != constant("organisation_types.funder")|| current_user.org_type == constant("organisation_types.funder")) then %>
- <% if active == 'add_plan' then %>
-
+
+<% end %>
\ No newline at end of file
diff --git a/app/views/templates/_edit_question.html.erb b/app/views/templates/_edit_question.html.erb
index ab12c02..8ea1271 100644
--- a/app/views/templates/_edit_question.html.erb
+++ b/app/views/templates/_edit_question.html.erb
@@ -6,169 +6,169 @@
**Copyright: Digital Curation Centre and University of California Curation Center
-->
-<%= form_for(question, :url => admin_updatequestion_dmptemplate_path(question), :html => { :method => :put}) do |f| %>
+<%= form_for(question, url: admin_updatequestion_template_path(question), html: { method: :put}) do |f| %>
+
+
\ No newline at end of file
diff --git a/app/views/templates/_option_fields.html.erb b/app/views/templates/_option_fields.html.erb
index 21f3e80..5182510 100644
--- a/app/views/templates/_option_fields.html.erb
+++ b/app/views/templates/_option_fields.html.erb
@@ -1,7 +1,7 @@
+
+<%end%>
\ No newline at end of file
diff --git a/config/application.rb b/config/application.rb
index f13810f..f4e3351 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -98,6 +98,5 @@
# Load Branded terminology (e.g. organization name, application name, etc.)
config.branding = config_for(:branding).deep_symbolize_keys
-
end
end
diff --git a/config/branding.yml b/config/branding.yml
index 578347c..5649562 100644
--- a/config/branding.yml
+++ b/config/branding.yml
@@ -26,4 +26,4 @@
<<: *defaults
production:
- <<: *defaults
\ No newline at end of file
+ <<: *defaults
diff --git a/config/environment.rb b/config/environment.rb
index c82b616..3488440 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -5,5 +5,4 @@
Rails.logger = Logger.new(STDOUT)
# Initialize the Rails application.
-#DMPonline4::Application.initialize!
Rails.application.initialize!
\ No newline at end of file
diff --git a/config/initializers/devise.rb.example b/config/initializers/devise.rb.example
index 17b481e..cce856a 100644
--- a/config/initializers/devise.rb.example
+++ b/config/initializers/devise.rb.example
@@ -247,7 +247,11 @@
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
# config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo'
-
+
+ # Any entries here MUST match a corresponding entry in the identifier_schemes table as
+ # well as an identifier_schemes.schemes section in each locale file!
+ config.omniauth :orcid, 'client_id', 'client_secret', {'scope': '/authenticate'}
+
# ==> Warden configuration
# If you want to use other strategies, that are not supported by Devise, or
# change the failure app, you can configure them inside the config.warden block.
@@ -269,7 +273,7 @@
#
# When using omniauth, Devise cannot automatically set Omniauth path,
# so you need to do it manually. For the users scope, it would be:
- # config.omniauth_path_prefix = "/my_engine/users/auth"
+ config.omniauth_path_prefix = "/users/auth"
config.warden do |manager|
manager.failure_app = CustomFailure
diff --git a/config/initializers/wicked_pdf.rb.example b/config/initializers/wicked_pdf.rb.example
new file mode 100644
index 0000000..1473351
--- /dev/null
+++ b/config/initializers/wicked_pdf.rb.example
@@ -0,0 +1,7 @@
+module DMPRoadmap
+ class Application < Rails::Application
+ WickedPdf.config = {
+ :exe_path => '/usr/local/bin/wkhtmltopdf'
+ }
+ end
+end
\ No newline at end of file
diff --git a/config/initializers/wicked_pdf_example.rb b/config/initializers/wicked_pdf_example.rb
deleted file mode 100644
index 103b3e5..0000000
--- a/config/initializers/wicked_pdf_example.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-module DMPRoadmap
- class Application < Rails::Application
-
- WickedPdf.config = {
- :exe_path => '/usr/local/bin/wkhtmltopdf'
- }
-
- end
-end
\ No newline at end of file
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 9c10799..d010da5 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -289,6 +289,7 @@
news_label: "Aktuelles"
help_label: "Hilfe"
contact_label: "Kontakt"
+ public_plans_label: "Öffentliche DMPs"
jisc: "Das DCC wird untertützt von"
greeting: "Hallo"
@@ -338,8 +339,8 @@
error: "Fehler!"
comment: "Kommentar"
send: "Senden"
- yes: "Ja"
- no: "Nein"
+ 'yes': "Ja"
+ 'no': "Nein"
none: "Keines"
title: "Titel"
note: "Anmerkung"
@@ -407,6 +408,10 @@
add_comment_accordion_label: "Füge Kommentar hinzu"
comment_accordion_label: "Kommentare"
+ answer:
+ only_one_per_question: "Eine Frage kann nur eine Antwort haben."
+ question_must_belong_to_correct_template: "Die Frage muss zur richtigen vorlage gehören."
+
comments:
add_comment_label: "Füge Kommentar hinzu"
add_comment_text: "Bitte füge einen Kommentar hinzu"
@@ -511,6 +516,21 @@
project_identifier_help_text: "Eine Identifikationskürzel, wie es von Förderern oder Institutionen vergeben wird."
project_static_info: "Dieser Plan basiert auf:"
projects_title: "Meine Pläne"
+
+ visibility: "Sichtweite"
+ visibilities:
+ labels:
+ privately_visible: "Private"
+ organisationally_visible: "Organisatorische"
+ publicly_visible: "Öffentlichkeit"
+ is_test: "Test/Übung"
+ help_texts:
+ privately_visible: "Private (Besitzer, Miteigentümer und Admins) Siehe unsere Nutzungsbedingungen."
+ organisationally_visible: "Mit anderen innerhalb Ihrer Organisation"
+ publicly_visible: "Öffentlich im Internet. Ihr DMP erscheint auf der Public DMPs Seite dieser Seite."
+ is_test: "Test / Praxis (Ihr Plan ist für andere Benutzer nicht sichtbar) Siehe unsere Nutzungsbedingungen."
+ not_set: "Nicht angegeben (wird standardmäßig für andere in Ihrer Organisation sichtbar sein)"
+
project_settings_text: "Die hier ausgewählten Einträge werden in der Tabelle unten angezeigt. Sie können die Daten durch jeden ihrer Tabellenköpfe sortieren oder filtern, indem Sie eine Zeichenkette in der Suchbox eingeben."
project_text_when_no_project: "
Willkommen. Sie können nun ihren ersten DMP erstellen. Wählen Sie 'Plan erstellen' weiter unten aus, um zu beginnen.
"
project_text_when_project: "
Die folgende Tabelle listet alle von Ihnen erstellten und von anderen mit Ihnen geteilten Pläne. Diese können jederzeit bearbeitet, geteilt, exportiert und gelöscht werden.
"
@@ -577,6 +597,10 @@
data_contact: "Plandatenkontakt"
description: "Beschreibung"
unknown: " - "
+ visibility: "Sichtweite"
+ name: 'Name'
+ template: 'Vorlage'
+ organisation: 'Organisation'
filter:
placeholder: "Filter Pläne"
submit: "Filter"
@@ -597,6 +621,7 @@
project_description: "Beschreibung"
funder: "Geldgeber"
institution: "Institution"
+ orcid: "Ihre ORCID"
settings:
title: "Einstellungen"
@@ -608,6 +633,7 @@
no_name: "'Name' muss in der Liste von Spalten enthalten sein."
duplicate: "Doppelter Spaltenname. Bitte jede Spalte nur einmal einfügen."
unknown: "Unbekannter Spaltenname."
+ no_plan: "Der Plan ist unvollständig."
plans:
title: "Dateiname"
reset: "Zurücksetzen"
@@ -684,6 +710,23 @@
no_auth_for_endpoint: '{"Error":"You do not have authorisation to view this endpoint"}'
bad_resource: '{"Error":"You do not have authorisation to view this resource"}'
+ identifier_schemes:
+ connect_success: 'Ihr Konto wurde mit %{scheme}'
+ connect_failure: 'Wir konnten nicht auf Ihr Konto %{scheme} verbinden'
+ disconnect_success: 'Ihr Konto wurde von %{scheme} getrennt'
+ disconnect_failure: 'Wir waren nicht in der Lage, Ihr Konto zu trennen von %{scheme}'
+ new_login_success: 'Sie haben nicht Setup ein Konto bei uns. Bitte füllen Sie das folgende Informationen, um Ihre Registrierung abzuschließen.'
+ new_login_failure: 'Wir waren nicht in der Lage, Ihr Konto zu überprüfen. Bitte benutzen Sie das folgende Formular ein neues Konto zu erstellen. Sie können danach Ihr neues Konto zu verknüpfen.'
+
+ schemes:
+ orcid:
+ logo: 'http://orcid.org/sites/default/files/images/orcid_16x16.png'
+ user_landing_page: 'https://orcid.org/%{id}'
+ connect: 'Erstellen oder Verbinden Sie Ihren ORCID ID'
+ connect_tooltip: 'ORCID bietet eine persistente digitale Kennung, die Sie von anderen Forschern unterscheidet. Erfahren Sie mehr unter orcid.org'
+ disconnect_confirmation: 'Sind Sie sicher, dass Sie Ihre ORCID ID trennen möchten?'
+ disconnect_tooltip: 'Trennen Sie Ihr Konto von ORCID. Sie können jederzeit wieder an.'
+
magic_strings:
organisation_types:
funder: 'Funder'
@@ -694,6 +737,10 @@
template: 'Template'
managing_organisation: 'Digital Curation Centre'
user_role_types:
+ admin: 'admin'
+ org_admin: 'org_admin'
+ user: 'user'
+ roles:
super_admin: 'admin'
organisational_admin: 'org_admin'
user: 'user'
@@ -705,7 +752,7 @@
use_api: 'use_api'
change_org_details: 'change_org_details'
grant_api_to_orgs: 'grant_api_to_orgs'
- api_endpoint_types:
+ token_permission_types:
guidances: 'guidances'
plans: 'plans'
templates: 'templates'
diff --git a/config/locales/en-UK.yml b/config/locales/en-UK.yml
index de174bd..45caa75 100644
--- a/config/locales/en-UK.yml
+++ b/config/locales/en-UK.yml
@@ -232,6 +232,7 @@
updated_message: "Guidance group was successfully updated."
destroyed_message: "Guidance group was successfully deleted."
templates:
+ template_history: "Template History"
create_template: "Create a template"
new_label: "New template"
template_details: "Template details"
@@ -244,6 +245,7 @@
create_own_template_text_html: "
If you wish to add an institutional template for a Data Management Plan, use the 'create template' button. You can create more than one template if desired e.g. one for researchers and one for PhD students.
Your template will be presented to users within your institution when no funder templates apply. If you want to add questions to funder templates use the 'customise template' options below.
"
create_new_template_text_html: "
To create a new template, first enter a title and description. Once you have saved this you will be presented with options to add one or more phases.
"
+ template_history_text_html: "
Here you can view previously published versions of your template. These can no longer be modified.
"
desc_help_text_html: "Enter a description that helps you to differentiate between templates e.g. if you have ones for different audiences"
own_temp: "Own templates"
add_phase_label: "Add new phase +"
@@ -338,11 +340,17 @@
about_us_label: "About"
roadmap_label: "Future plans"
help_label: "Help"
+ public_plans_label: "Public DMPs"
+
contact_label: "Contact"
+ public_plans_label: "Public DMPs"
jisc: "The %{organisation_abbreviation} is funded by"
format: "format"
change_language: "Change language"
+ 'yes': 'Yes'
+ 'no': 'No'
+
sign_in: "Sign in"
sign_out: "Sign out"
sign_up: "Sign up"
@@ -423,6 +431,7 @@
note: "Note"
me: "Me"
view: "View"
+ history: "History"
desc: "Description"
save: "Save"
preview: "Preview"
@@ -501,6 +510,10 @@
add_comment_accordion_label: "Share note"
comment_accordion_label: "Notes"
+ answer:
+ only_one_per_question: "A question can only have one answer."
+ question_must_belong_to_correct_template: "The question must belong to the correct template."
+
comments:
add_comment_label: "Add note"
add_comment_text: "Share note with collaborators"
@@ -574,6 +587,21 @@
project_identifier_help_text: "A pertinent ID as determined by the funder and/or institution."
project_static_info: "This plan is based on:"
projects_title: "My plans"
+
+ visibility: "Visibility"
+ visibilities:
+ labels:
+ privately_visible: "Private"
+ organisationally_visible: "Organisational"
+ publicly_visible: "Public"
+ is_test: "Test/Practice"
+ help_texts:
+ privately_visible: "Private (owners, co-owners, and administrators only) See our Terms of Use."
+ organisationally_visible: "Organisational (visibile to others within your organisation)"
+ publicly_visible: "Public (Your DMP will appear on the Public DMPs page of this site)"
+ is_test: "Test/Practice (your plan is not visible to other users) See our Terms of Use."
+ not_set: "Not specified (will be visible to others within your organisation by default)"
+
project_settings_text: "The items you select here will be displayed in the table below. You can sort the data by each of these headings or filter by entering a text string in the search box."
project_text_when_no_project: "
Welcome. You are now ready to create your first DMP.Click the 'Create plan' button below to begin.
"
project_text_when_project: "
The table below lists the plans that you have created, and any that have been shared with you by others.These can be edited, shared, exported or deleted at anytime.
"
@@ -626,6 +654,11 @@
data_contact: "Plan data contact"
description: "Description"
unknown: " - "
+ visibility: "Visibility"
+ name: 'Name'
+ template: 'Template'
+ organisation: 'Organization'
+
filter:
placeholder: "Filter plans"
submit: "Filter"
@@ -657,6 +690,7 @@
project_description: "Plan Description"
funder: "Funder"
institution: "Institution"
+ orcid: "Your ORCID"
not_valid_format: '%{value}% is not a valid format'
settings:
@@ -668,6 +702,7 @@
no_name: "'name' must be included in column list."
duplicate: "Duplicate column name. Please only include each column once."
unknown: "Unknown column name."
+ no_plan: "The plan is incomplete."
plans:
title: "File Name"
reset: "Reset"
@@ -739,6 +774,23 @@
no_auth_for_endpoint: '{"Error":"You do not have authorisation to view this endpoint"}'
bad_resource: '{"Error":"You do not have authorisation to view this resource"}'
+ identifier_schemes:
+ connect_success: 'Your account has bee connected to %{scheme}'
+ connect_failure: 'We could not connect your account to %{scheme}'
+ disconnect_success: 'Your account has been disconnected from %{scheme}'
+ disconnect_failure: 'We were unable to disconnect your account from %{scheme}'
+ new_login_success: 'It does not look like you have setup an account with us yet. Please fill in the following information to complete your registration.'
+ new_login_failure: 'We were unable to verify your account. Please use the following form to create a new account. You will be able to link your new account afterward.'
+
+ schemes:
+ orcid:
+ logo: 'http://orcid.org/sites/default/files/images/orcid_16x16.png'
+ user_landing_page: 'https://orcid.org/%{id}'
+ connect: 'Create or Connect your ORCID ID'
+ connect_tooltip: 'ORCID provides a persistent digital identifier that distinguishes you from other researchers. Learn more at orcid.org'
+ disconnect_confirmation: 'Are you sure you want to disconnect your ORCID ID?'
+ disconnect_tooltip: 'Disconnect your account from ORCID. You can reconnect at any time.'
+
magic_strings:
organisation_types:
funder: 'Funder'
@@ -749,6 +801,10 @@
template: 'Template'
managing_organisation: 'Digital Curation Centre'
user_role_types:
+ admin: 'admin'
+ org_admin: 'org_admin'
+ user: 'user'
+ roles:
super_admin: 'admin'
organisational_admin: 'org_admin'
user: 'user'
@@ -760,7 +816,7 @@
use_api: 'use_api'
change_org_details: 'change_org_details'
grant_api_to_orgs: 'grant_api_to_orgs'
- api_endpoint_types:
+ token_permission_types:
guidances: 'guidances'
plans: 'plans'
templates: 'templates'
diff --git a/config/locales/en-US.yml b/config/locales/en-US.yml
index 16de5b7..2d9b60b 100644
--- a/config/locales/en-US.yml
+++ b/config/locales/en-US.yml
@@ -327,9 +327,13 @@
roadmap_label: "Future plans"
help_label: "Help"
contact_label: "Contact"
+ public_plans_label: "Public DMPs"
jisc: "The %{organisation_abbreviation} is funded by"
format: "format"
+ 'yes': 'Yes'
+ 'no': 'No'
+
sign_in: "Sign in"
sign_out: "Sign out"
sign_up: "Sign up"
@@ -487,6 +491,10 @@
add_comment_accordion_label: "Share note"
comment_accordion_label: "Notes"
+ answer:
+ only_one_per_question: "A question can only have one answer."
+ question_must_belong_to_correct_template: "The question must belong to the correct template."
+
comments:
add_comment_label: "Add note"
add_comment_text: "Share note with collaborators"
@@ -560,6 +568,21 @@
project_identifier_help_text: "A pertinent ID as determined by the funder and/or institution."
project_static_info: "This plan is based on:"
projects_title: "My plans"
+
+ visibility: "Visibility"
+ visibilities:
+ labels:
+ privately_visible: "Private"
+ organisationally_visible: "Organizational"
+ publicly_visible: "Public"
+ is_test: "Test/Practice"
+ help_texts:
+ privately_visible: "Private (owners, co-owners, and administrators only) See our Terms of Use."
+ organisationally_visible: "Organizational (visibile to others within your organization)"
+ publicly_visible: "Public (Your DMP will appear on the Public DMPs page of this site)"
+ is_test: "Test/Practice (your plan is not visible to other users) See our Terms of Use."
+ not_set: "Not specified (will be visible to others within your organization by default)"
+
project_settings_text: "The items you select here will be displayed in the table below. You can sort the data by each of these headings or filter by entering a text string in the search box."
project_text_when_no_project: "
Welcome. You are now ready to create your first DMP.Click the 'Create plan' button below to begin.
"
project_text_when_project: "
The table below lists the plans that you have created, and any that have been shared with you by others.These can be edited, shared, exported or deleted at anytime.
"
@@ -612,6 +635,10 @@
data_contact: "Plan data contact"
description: "Description"
unknown: " - "
+ visibility: "Visibility"
+ name: 'Name'
+ template: 'Template'
+ organisation: 'Organization'
filter:
placeholder: "Filter plans"
submit: "Filter"
@@ -643,6 +670,7 @@
project_description: "Description"
funder: "Funder"
institution: "Institution"
+ orcid: "Your ORCID"
not_valid_format: '%{value}% is not a valid format'
settings:
@@ -654,6 +682,7 @@
no_name: "'name' must be included in column list."
duplicate: "Duplicate column name. Please only include each column once."
unknown: "Unknown column name."
+ no_plan: "The plan is incomplete."
plans:
title: "File Name"
reset: "Reset"
@@ -725,6 +754,23 @@
no_auth_for_endpoint: '{"Error":"You do not have authorisation to view this endpoint"}'
bad_resource: '{"Error":"You do not have authorisation to view this resource"}'
+ identifier_schemes:
+ connect_success: 'Your account has bee connected to %{scheme}'
+ connect_failure: 'We could not connect your account to %{scheme}'
+ disconnect_success: 'Your account has been disconnected from %{scheme}'
+ disconnect_failure: 'We were unable to disconnect your account from %{scheme}'
+ new_login_success: 'It does not look like you have setup an account with us yet. Please fill in the following information to complete your registration.'
+ new_login_failure: 'We were unable to verify your account. Please use the following form to create a new account. You will be able to link your new account afterward.'
+
+ schemes:
+ orcid:
+ logo: 'http://orcid.org/sites/default/files/images/orcid_16x16.png'
+ user_landing_page: 'https://orcid.org/%{id}'
+ connect: 'Create or Connect your ORCID ID'
+ connect_tooltip: 'ORCID provides a persistent digital identifier that distinguishes you from other researchers. Learn more at orcid.org'
+ disconnect_confirmation: 'Are you sure you want to disconnect your ORCID ID?'
+ disconnect_tooltip: 'Disconnect your account from ORCID. You can reconnect at any time.'
+
magic_strings:
organisation_types:
funder: 'Funder'
@@ -735,6 +781,10 @@
template: 'Template'
managing_organisation: 'Digital Curation Centre'
user_role_types:
+ admin: 'admin'
+ org_admin: 'org_admin'
+ user: 'user'
+ roles:
super_admin: 'admin'
organisational_admin: 'org_admin'
user: 'user'
@@ -746,7 +796,7 @@
use_api: 'use_api'
change_org_details: 'change_org_details'
grant_api_to_orgs: 'grant_api_to_orgs'
- api_endpoint_types:
+ token_permission_types:
guidances: 'guidances'
plans: 'plans'
templates: 'templates'
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 9c288cd..a7e52e5 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -280,6 +280,7 @@
roadmap_label: "Hoja de ruta"
help_label: "Ayuda"
contact_label: "Contacto"
+ public_plans_label: "DMP Públicos"
jisc: "El DCC está financiado por"
sign_in: "Conectar"
@@ -322,8 +323,8 @@
error: "¡Error!"
comment: "Comentario"
send: "Enviar"
- yes: "Si"
- no: "No"
+ 'yes': "Si"
+ 'no': "No"
none: "Ninguno/a"
false_lowercase: "falso"
title: "Título"
@@ -387,6 +388,10 @@
add_comment_accordion_label: "Compartir nota"
comment_accordion_label: "Notas"
+ answer:
+ only_one_per_question: "Una pregunta sólo puede tener una respuesta."
+ question_must_belong_to_correct_template: "La pregunta debe pertenecer a la plantilla correcta."
+
comments:
add_comment_label: "Añadir nota"
add_comment_text: "Compartir nota con colaboradores"
@@ -453,6 +458,21 @@
project_identifier_help_text: "El ID tal como lo determinó la institución u organismo financiador."
project_static_info: "Este plan está basado en:"
projects_title: "Mis planes"
+
+ visibility: "Visibilidad"
+ visibilities:
+ labels:
+ privately_visible: "Privado"
+ organisationally_visible: "Organizativo"
+ publicly_visible: "Público"
+ is_test: "Prueba/Práctica"
+ help_texts:
+ privately_visible: "Privado (propietarios, copropietarios y administradores solamente) Consulte nuestras Condiciones de uso."
+ organisationally_visible: "Con otros miembros de su organización"
+ publicly_visible: "Publicamente en la web. Su DMP aparecerá en la página Public DMPs de este sitio."
+ is_test: "Prueba / Práctica (su plan no es visible para otros usuarios) Vea nuestras Condiciones de uso."
+ not_set: "No especificado (será visible para otros dentro de su organización de forma predeterminada)"
+
project_settings_text: "Los items que seleccione se mostarán en la siguiente tabla. Puede ordenar los datos según sus encabezados o filtrar tecleando textos en la caja de búsqueda."
project_text_when_no_project: "
Bienvenido. Ya está listo para crear su primer PGD.Haga clic en el botón 'Crear un plan' para comenzar.
"
project_text_when_project: "
La siguiente tabla lista los planes que usted ha creado, así como los que otros investigadores hayan compartido con usted.Se pueden editar, compartir, exportar o borrar en cualquier momento.
"
@@ -504,6 +524,10 @@
principal_investigator: "Principal Investigador / Científico"
data_contact: "Datos de contacto del plan"
description: "Descripción"
+ visibility: 'Visibilidad'
+ name: 'Nombre'
+ template: 'Plantilla'
+ organisation: 'Organización'
filter:
placeholder: "Filtro de planes"
submit: "Filtrar"
@@ -534,6 +558,7 @@
no_name: "'nombre' tiene que estar en la lista de columnas."
duplicate: "Nombre de columna duplicado. Por favor, indique cada columna sólo una vez."
unknown: "Nombre de columna desconocido."
+ no_plan: "El plan es incompleto."
plans:
title: Título del plan
reset: "Reiniciar"
@@ -789,3 +814,60 @@
El uso de la herramienta indica que usted entiende y está de acuerdo con estos términos y condiciones.
"
+
+ api:
+ bad_credentials: '{"Error":"Bad credentials"}'
+ org_dosent_exist: '{"Error":"Organization does not exist"}'
+ org_not_funder: '{"Error":"Organization specified is not a funder"}'
+ org_multiple_templates: '{"Error":"Organization has more than one template and template name unspecified or invalid"}'
+ no_auth_for_endpoint: '{"Error":"You do not have authorisation to view this endpoint"}'
+ bad_resource: '{"Error":"You do not have authorisation to view this resource"}'
+
+ identifier_schemes:
+ connect_success: 'Tu cuenta se ha conectado a %{scheme}'
+ connect_failure: 'No pudimos conectar tu cuenta a %{scheme}'
+ disconnect_success: 'Su cuenta se ha desconectado de %{scheme}'
+ disconnect_failure: 'No hemos podido desconectar tu cuenta de %{scheme}'
+ new_login_success: 'No ha configurado una cuenta. Por favor complete su registro.'
+ new_login_failure: 'No hemos podido verificar tu cuenta. Utilice el siguiente formulario para crear una cuenta nueva. Podrá vincular su nueva cuenta posteriormente.'
+
+ schemes:
+ orcid:
+ logo: 'http://orcid.org/sites/default/files/images/orcid_16x16.png'
+ user_landing_page: 'https://orcid.org/%{id}'
+ connect: 'Cree o conecte su ID de ORCID ID'
+ connect_tooltip: 'ORCID proporciona un identificador digital persistente que lo distingue de otros investigadores. Más información en orcid.org'
+ disconnect_confirmation: '¿Está seguro de que desea desconectar su ORCID ID?'
+ disconnect_tooltip: 'Desconecte su cuenta de ORCID. Puede volver a conectarse en cualquier momento.'
+
+ magic_strings:
+ organisation_types:
+ funder: 'Financiador'
+ organisation: 'Organización'
+ project: 'Proyecto'
+ institution: 'Institución'
+ research_institute: 'Instituto de Investigación'
+ template: 'Modelo'
+ managing_organisation: 'Centro de Cura Digital'
+ user_role_types:
+ admin: 'admin'
+ org_admin: 'org_admin'
+ user: 'user'
+ roles:
+ super_admin: 'admin'
+ organisational_admin: 'org_admin'
+ user: 'user'
+ add_organisations: 'add_organisations'
+ change_org_affiliation: 'change_org_affiliation'
+ grant_permissions: 'grant_permissions'
+ modify_templates: 'modify_templates'
+ modify_guidance: 'modify_guidance'
+ use_api: 'use_api'
+ change_org_details: 'change_org_details'
+ grant_api_to_orgs: 'grant_api_to_orgs'
+ token_permission_types:
+ guidances: 'guidances'
+ plans: 'plans'
+ templates: 'templates'
+ statistics: 'statistics'
+ languages:
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 5f4e0eb..d045462 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -19,7 +19,7 @@
day_names: [dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi]
abbr_day_names: [DIM, LUN, MAR, MER, JEU, VEN, SAM]
- # Don't forget the nil at the beginning; there's no such thing as a 0th month
+ # Dont forget the nil at the beginning; theres no such thing as a 0th month
month_names: [~, janvier, février, mars, avril, mai, juin, juillet, août, septembre, octobre, novembre, décembre]
abbr_month_names: [~, JAN, FEV, MAR, AVR, MAI, JUN, JUL, AOU, SEP, OCT, NOV, DEC]
# Used in date_select and datetime_select.
@@ -42,23 +42,23 @@
dmponline3_text: "Version précédente de DMPonline"
dcc_name: "Digital Curation Centre"
welcome_title: "Bienvenue !"
- welcome_text: "
DMPonline est un développement du Digital Curation Centre (Centre de curation numérique britannique - DCC) pour vous aider dans la rédaction de plans de gestion de données, ou DMP.
"
- screencast_text: "Vidéo en ligne sur l'utilisation de DMPonline"
- screencast_error_text: "La balise
"
questions_answered: "questions avec réponses"
not_saved_answers_text_alert: "Vous avez changé des réponses sans les sauvegarder:"
not_saved_answers_confirmation_alert: "Voulez-vous faire la sauvegarde maintenant?"
not_saved_answers_header: "réponses non sauvegardées"
project_data_contact: "Interlocuteur pour les données du Plan"
- project_data_contact_help_text: "Nom (s'il diffère du précédent), coordonnées courriel et téléphone"
+ project_data_contact_help_text: "Nom (sil diffère du précédent), coordonnées courriel et téléphone"
project_name_help_text: "En cas de demande de financement, indiquer le nom exactement comme dans la demande de subvention."
- project_desc_help_text_html: "
Questions auxquelles réfléchir :
- Quelle est la nature de votre projet de recherche ?
- Quelles ont les problématiques de recherche que vous traitez ?
- Dans quel but est effectuée la collecte ou la création des données ?
Conseils :
Résumez brièvement le type d'étude(s) pour permettre à d'autres de comprendre dans quel but les données sont collectées ou créées.
"
+ project_desc_help_text_html: "
Questions auxquelles réfléchir :
- Quelle est la nature de votre projet de recherche ?
- Quelles ont les problématiques de recherche que vous traitez ?
- Dans quel but est effectuée la collecte ou la création des données ?
Conseils :
Résumez brièvement le type détude(s) pour permettre à dautres de comprendre dans quel but les données sont collectées ou créées.
"
project_identifier: "Identifiant"
- project_identifier_help_text: "Un identifiant approprié conforme aux prescriptions de l'organisme financeur ou de l'établissement."
- project_static_info: "Ce plan s'inspire de :"
+ project_identifier_help_text: "Un identifiant approprié conforme aux prescriptions de lorganisme financeur ou de létablissement."
+ project_static_info: "Ce plan sinspire de :"
projects_title: "Mes plans"
+
+ visibility: "Visibilité"
+ visibilities:
+ labels:
+ privately_visible: "Privé"
+ organisationally_visible: "Organisationnel"
+ publicly_visible: "Public"
+ is_test: "Test/Pratique"
+ help_texts:
+ privately_visible: "Privé (propriétaires, copropriétaires et administrateurs uniquement) Consultez nos Conditions d'utilisation."
+ organisationally_visible: "Avec d'autres membres de votre organisation"
+ publicly_visible: "Publiquement sur le web. Votre DMP apparaîtra sur la page Public DMPs de ce site."
+ is_test: "Test / Practice (votre plan n'est pas visible aux autres utilisateurs) Voir nos Conditions d'utilisation."
+ not_set: "Non spécifié (sera visible par d'autres personnes au sein de votre organisation par défaut)"
+
project_settings_text: "Les éléments que vous sélectionnez ici s'afficherontt dans le tableaiu ci-après. Vous pouvez trier les données à partir de chacune de ces en-tête ou les filtrer en tapant une chaîne de caractères dans la zone de recherche."
project_text_when_no_project: "
Bienvenue. Vous voilà prêt à créer votre premier DMP.Cliquez sur le bouton 'Créer un plan' ci-dessous pour commencer.
"
project_text_when_project: "
Dans le tableau ci-dessous figurent les plans que vous avez créés, ainsi que ceux que vous partagez avec d'autres.Vous pouvez à tout moment les modifier, les partager, les exporter, les effacer...
"
project_details_text_html: "Cette page vous donne un aperçu de votre plan. Elle indique de quoi il s'inspire et donne une idée générale des questions auxquelles vous devrez répondre."
project_details_editing_text_html: "Veuillez renseigner les premiers détails ci-après et cliquez sur 'Mettre à jour' pour enregistrer"
confirm_delete_text: "Voulez-vous vraiment effacer ce plan ? S'il est partagé avec d'autres utilisateurs, le fait de l'effacer de votre liste, l'effacera aussi de leur liste de plans."
+
confirmation_text: "Confirmer les détails du plan"
- confirmation_text_desc: "Si votre agence de financement ou votre établissement n'émet pas de prescriptions (ou si vous n'avez pas rempli ces options), la checklist du DCC s'affichera. Celle-ci propose un ensemble de questions générales et de conseils pour un DMP. Pour en savoir plus : DMP checklist 2013."
+ confirmation_text_desc: "Si votre agence de financement ou votre établissement német pas de prescriptions (ou si vous navez pas rempli ces options), la checklist du DCC saffichera. Celle-ci propose un ensemble de questions générales et de conseils pour un DMP. Pour en savoir plus : DMP checklist 2013."
confirmation_button_text: "Oui, créer un plan"
- default_confirmation_text_desc: "Vous avez choisi le DMP par défaut, qui repose sur la checklist du DCC. Celle-ci propose un ensemble de questions générales et de conseils pour un DMP. Pour en savoir plus : DMP checklist 2013."
+ default_confirmation_text_desc: "Vous avez choisi le DMP par défaut, qui repose sur la checklist du DCC. Celle-ci propose un ensemble de questions générales et de conseils pour un DMP. Pour en savoir plus : DMP checklist 2013."
default_confirmation_button_text: "Create plan"
- alert_default_template_text_html: "Attention : Votre organisme (%{org_name}) fournit un modèle de DMP. Si vous voulez l'utiliser, sélectionnez 'Annuler', sinon cliquez sur 'Créer un plan'"
+ alert_default_template_text_html: "Attention : Votre organisme (%{org_name}) fournit un modèle de DMP. Si vous voulez lutiliser, sélectionnez Annuler, sinon cliquez sur Créer un plan"
share:
tab_share: "Partager"
shared_label: "Partagé ?"
- share_text_html: "
À ce niveau, vous pouvez donner accès à votre plan à d'autres personnes. Trois niveaux d'autorisation sont possibles.
Les utilisateurs avec un droit en \"lecture seule\" ne pourront que consulter le plan.
Les utilisateurs avec un droit de mofification pourront y contribuer.
Les copropriétaires le peuvent aussi, mais peuvent aussi en modifier les détails et en contrôler l'accès.
Ajoutez chacun des collaborateurs en saisissant leurs courriels l'un après l'autre, en choisissant un niveau d'autorisation et en cliquant sur \"Ajouter le collaborateur\".
Ceux qui sont invités recevront un avis par courriel leur indiquant qu'ils ont accès à ce plan, invitant ceux qui n'ont pas de compte dans DMPonline à s'enregistrer. L'utilisateur reçoit aussi un avis quand ces droits sont changés.
"
+ share_text_html: "
À ce niveau, vous pouvez donner accès à votre plan à dautres personnes. Trois niveaux dautorisation sont possibles.
Les utilisateurs avec un droit en \"lecture seule\" ne pourront que consulter le plan.
Les utilisateurs avec un droit de mofification pourront y contribuer.
Les copropriétaires le peuvent aussi, mais peuvent aussi en modifier les détails et en contrôler laccès.
Ajoutez chacun des collaborateurs en saisissant leurs courriels lun après lautre, en choisissant un niveau dautorisation et en cliquant sur \"Ajouter le collaborateur\".
Ceux qui sont invités recevront un avis par courriel leur indiquant quils ont accès à ce plan, invitant ceux qui nont pas de compte dans DMPonline à senregistrer. Lutilisateur reçoit aussi un avis quand ces droits sont changés.
"
collaborators: "Collaborateurs"
add_collaborator: "Ajouter le collaborateur"
add: "Ajouter"
permissions: "Permissions"
- permissions_desc: "Les collaborateurs avec des droits de modification peuvent contribuer aux plans. Les copropriétaires ont en plus le droit de modifier les détails du plan et en contrôler l'accès. "
- remove: "Retirer l'accès utilisateur"
+ permissions_desc: "Les collaborateurs avec des droits de modification peuvent contribuer aux plans. Les copropriétaires ont en plus le droit de modifier les détails du plan et en contrôler laccès. "
+ remove: "Retirer laccès utilisateur"
confirmation_question: "Êtes-vous sûr ?"
owner: "Propriétaire"
co_owner: "Copropriétaire"
@@ -489,11 +510,11 @@
create_page:
title: "Créer un nouveau plan"
desc_html: "
Veuillez sélectionner des éléments dans les menus déroulants ci-après pour pouvoir identifier les questions et conseils à afficher dans votre plan.
-
Si votre soumission doit répondre à des prescriptions propres à un organisme financeur ou un établissement, sélectionnez ici la rédaction d'un DMP à partir des thèmes les plus courants.
"
+
Si votre soumission doit répondre à des prescriptions propres à un organisme financeur ou un établissement, sélectionnez ici la rédaction dun DMP à partir des thèmes les plus courants.
"
default_template: "DMP par défaut"
- funders_question: "Si vous soumettez une demande de subvention, sélectionnez l'organisme financeur."
+ funders_question: "Si vous soumettez une demande de subvention, sélectionnez lorganisme financeur."
funders_question_description: "Sinon laissez ce champ vide."
- other_funder_name_label: "Nom de l'organisme financeur, le cas échéant."
+ other_funder_name_label: "Nom de lorganisme financeur, le cas échéant."
institution_question: "Sélectionnez votre organisme pour voir les questions et conseils de votre établissement."
institution_question_description: "Ce champ peut rester vide, ou vous pouvez sélectionner un autre organisme que le vôtre."
other_guidance_question: "Cochez une ou plusieurs des sources de conseils que vous voulez voir."
@@ -509,36 +530,49 @@
principal_investigator: "Directeur de recherche / chercheur"
data_contact: "Interlocuteur pour les données du plan"
description: "Description"
+ visibility: "Visibilité"
+ name: 'Prénom'
+ template: 'Modèle'
+ organisation: 'Organisation'
filter:
placeholder: "Filtrer les plans"
submit: "Filtrer"
cancel: "Annuler"
- no_matches: "Pas de plans pour '%{filter}'"
+ no_matches: "Pas de plans pour %{filter}"
plan:
export:
pdf:
question_not_answered: Question sans réponse.
generated_by: Ce document a été créé par DMPonline (http://dmponline.dcc.ac.uk)
- space_used: "env. %{space_used}% d'espace disponible utilisé (%{num_pages} pages maxi)"
+ space_used: "env. %{space_used}% despace disponible utilisé (%{num_pages} pages maxi)"
+ space_used_without_max: "env. %{space_used}% despace disponible utilisé"
project_name: "Nom du projet"
project_identifier: "Identifiant du projet"
grant_title: "Titre de la subvention"
principal_investigator: "Directeur de recherche / chercheur"
project_data_contact: "Interlocuteur pour les données du plan"
project_description: "Description"
- funder: "Financeur"
- institution: "Etablissement"
+ funder: "Bailleur de fonds"
+ institution: "Établissement"
+ orcid: "Votre ORCID"
+ section: "Section"
+ question: "Question"
+ answer: "Réponse"
+ selected_options: "Option(s) choisie(s)"
+ answered_by: "Réponse faite par"
+ answered_at: "Réponse faite à"
settings:
title: "Réglages"
projects:
title: "Réglages - Mes plans"
- desc: "Le tableau suivant donne la liste des colonnes que l'on peut faire apparaître dans la liste 'Mes Plans'. Choisissez celles que vous voulez voir."
+ desc: "Le tableau suivant donne la liste des colonnes que lon peut faire apparaître dans la liste Mes Plans. Choisissez celles que vous voulez voir."
errors:
- no_name: "'name' doit figurer dans la liste des colonnes."
- duplicate: "Nom de colonne en doublon. Merci de n'ajouter qu'une seule colonne."
+ no_name: "name doit figurer dans la liste des colonnes."
+ duplicate: "Nom de colonne en doublon. Merci de najouter quune seule colonne."
unknown: "Nom de colonne inconnu."
+ no_plan: "Le plan est incomplet."
plans:
title: Titre du plan
reset: "Réinitialiser"
@@ -557,7 +591,7 @@
right: "Droite"
max_pages: "Nombre de pages maxi"
errors:
- missing_key: "Vous n'avez pas précisé un réglage obligatoire"
+ missing_key: "Vous navez pas précisé un réglage obligatoire"
invalid_margin: "Valeur de marge non valide"
negative_margin: "Une marge ne peut être négative"
unknown_margin: "Marge inconnue. Seules marges possibles : Haut, Bas, Gauche et Droite"
@@ -572,126 +606,127 @@
tab_2: "Dernières nouvelles"
body_text_tab_1_html: "
De plus en plus, les agences de financement exigent que leurs bénéficiaires proposent des DMP (des plans de gestion de données), tant pendant la préparation de leur soumission qu’après l’attribution de la subvention. Le Digital Curation Centre (Centre de curation numérique britannique - DCC) a élaboré DMPonline pour satisfaire cette exigence, ainsi que leur établissement ou tout autre acteur.
-
Le DCC DCC a coopéré étroitement avec des agences de financement de la recherche et des universités pour réaliser au profit des chercheurs un outil les assistant dans l’élaboration d'un DMP (un plan de gestion de données) efficace qui couvre le cycle de vie complet d’un projet de recherche, de l’étape de préparation de sa soumission jusqu’à son achèvement.
+
Le DCC DCC a coopéré étroitement avec des agences de financement de la recherche et des universités pour réaliser au profit des chercheurs un outil les assistant dans l’élaboration dun DMP (un plan de gestion de données) efficace qui couvre le cycle de vie complet d’un projet de recherche, de l’étape de préparation de sa soumission jusqu’à son achèvement.
-
Fonctionnement de l'outil
-
L'outil comprend un certain nombre de modèles qui sont représentatifs des prescriptions de différents organismes financeurs et établissements. Au départ, les utilisateurs doivent répondre à trois questions pour que nous puissions déterminer le modèle qu'il convient d'afficher(par ex. : le modèle ESRC pour une soumission dans le cadre d'un appel à projet de l'ESRC). Des conseils vous sont fournis pour vous permettre d'interpréter les questions posées et y répondre. Ces conseils sont fournis selon les agences de financement, universités et disciplines.
+
Fonctionnement de loutil
+
Loutil comprend un certain nombre de modèles qui sont représentatifs des prescriptions de différents organismes financeurs et établissements. Au départ, les utilisateurs doivent répondre à trois questions pour que nous puissions déterminer le modèle quil convient dafficher(par ex. : le modèle ESRC pour une soumission dans le cadre dun appel à projet de lESRC). Des conseils vous sont fournis pour vous permettre dinterpréter les questions posées et y répondre. Ces conseils sont fournis selon les agences de financement, universités et disciplines.
-
Pour commencer.../h3>
+
Pour commencer...
Si vous possédez un compte, veuillez vous connecter, puis commencez à créer ou modifier votre DMP.
-
En l'absence de compte DMPonline , cliquez sur 'S'enregistrer' en page d'accueil.
NOus améliorons constamment l'interface utilisateur de DMPonline et ses fonctionnalités.
- Si vous souhaitez apporter une contribution par un retour ou des suggestions, veuillez nous contacter par courriel : dmponline@dcc.ac.uk. Vous pouvez aussi signaler des dysfonctionnements ou demander d'autres fonctionnalités directement sur GitHub
-
Si vous voulez consulter des DMP issus d'une version antérieure de cette outil, visitez DMPonline v3.
"
+
NOus améliorons constamment linterface utilisateur de DMPonline et ses fonctionnalités.
+ Si vous souhaitez apporter une contribution par un retour ou des suggestions, veuillez nous contacter par courriel : dmponline@dcc.ac.uk. Vous pouvez aussi signaler des dysfonctionnements ou demander dautres fonctionnalités directement sur GitHub
+
Si vous voulez consulter des DMP issus dune version antérieure de cette outil, visitez DMPonline v3.
"
body_text_tab_2_html: "
Témoignages sur DMPonline depuis le site web du DCC
"
help_page:
title: "Aide"
tab_1: "À propos de DMPonline"
- tab_2: "À propos de la réalisation d'un plan de gestion de données (DMP)"
+ tab_2: "À propos de la réalisation dun plan de gestion de données (DMP)"
body_text_tab_2_html: "
- Checklist du DCC pour les DMP [PDF, 3 pages]
- Une liste de 13 questions et de conseils associés, qui représentent les principales problématiques qui se présentent dans la gestion et le partage de DMP. Cette liste sert de modèle générique pour DMPOnline, cette liste est proposée quand aucune prescription financière ou organisationnelle ne s'impose à l'utilisateur.
+ Checklist du DCC pour les DMP [PDF, 3 pages]
+ Une liste de 13 questions et de conseils associés, qui représentent les principales problématiques qui se présentent dans la gestion et le partage de DMP. Cette liste sert de modèle générique pour DMPOnline, cette liste est proposée quand aucune prescription financière ou organisationnelle ne simpose à lutilisateur.
- Comment élaborer un plan de gestion et de partage de données [PDF, 8 pages] Un Guide du DCC (Digital Curation Centre) qui brosse un tableau général des prescriptions des organismes financeurs pour les DMP et le type de réflexions à entreprendre quand l'on projette de présenter un projetTechnical plan submitted to the AHRC [PDF, 7 pages]
- Un DMP présenté par un chercheur de l'Université de Bristol, avec les commentaires des auditeurs.
+ Comment élaborer un plan de gestion et de partage de données [PDF, 8 pages] Un Guide du DCC (Digital Curation Centre) qui brosse un tableau général des prescriptions des organismes financeurs pour les DMP et le type de réflexions à entreprendre quand lon projette de présenter un projetTechnical plan submitted to the AHRC [PDF, 7 pages]
+ Un DMP présenté par un chercheur de lUniversité de Bristol, avec les commentaires des auditeurs.
- Deux DMP en Sciences sociales [PDF, 7 pages]
- Exemples de plans réalisés par des chercheurs de l'Université de Leeds, partagés dans le cadre des supports de formation Leeds RoaDMaP
+ Deux DMP en Sciences sociales [PDF, 7 pages]
+ Exemples de plans réalisés par des chercheurs de lUniversité de Leeds, partagés dans le cadre des supports de formation Leeds RoaDMaP
- Psychology DMP [PDF, 11 pages]
+ Psychology DMP [PDF, 11 pages]
Un DMP fictif très détaillé en psychologie élaboré par le projet pédagogique DMTpsych RDM, à partir de travaux expérimentaux précurseurs
- Exemples de DMP de l'Université de San Diego [webpage]
- Un vingtaine d'exemple de DMP proposé à la National Science Foundation (NSF) aux États-Unis par des enseignants chercheurs de l'Université de Californie à San Diego
+ Exemples de DMP de lUniversité de San Diego [webpage]
+ Un vingtaine dexemple de DMP proposé à la National Science Foundation (NSF) aux États-Unis par des enseignants chercheurs de lUniversité de Californie à San Diego
- DMP de la NSF [webpage]
+ DMP de la NSF [webpage]
5 DMP soumis à la NSF, partagés par la DataOne initiative
- DMP en biologie et en chimie [webpage]
- Trois exemples de DMP américains partagés par NECDMC, un outil pédagogique pour la formation à la gestion de données de recherche d'étudiants de niveaux L, M et en recherche en sciences, technologies et médecine.
+ DMP en biologie et en chimie [webpage]
+ Trois exemples de DMP américains partagés par NECDMC, un outil pédagogique pour la formation à la gestion de données de recherche détudiants de niveaux L, M et en recherche en sciences, technologies et médecine.
Guides utiles sur la gestion des données de la recherche en général
-
+
- Managing and Sharing Data: best practice for researchers [PDF, 36 pages]
- Un guide édité par le UK Data Service abordant une série de sujets, dont les formats et description de données, les questions d'éthique, de droit d'auteur et de partage des données.
+ Managing and Sharing Data: best practice for researchers [PDF, 36 pages]
+ Un guide édité par le UK Data Service abordant une série de sujets, dont les formats et description de données, les questions déthique, de droit dauteur et de partage des données.
- How to Cite Datasets and Link to Publications [PDF, 12 pages]
+ How to Cite Datasets and Link to Publications [PDF, 12 pages]
Un guide édité par le Digital Curation Centre (Centre de curation numérique britannique - DCC) contenant des recommandations pratiques sur la manière de citer des données et signalant les différents outils et infrastructures de référencement de données.
- How to License Research Data [PDF, 16 pages]
+ How to License Research Data [PDF, 16 pages]
Un guide édité par le Digital Curation Centre (Centre de curation numérique britannique - DCC) qui rend compte des différents types de licences, des points positifs et négatifs de chacune et comment les mettre en place.
- How to Appraise and Select Research Data for Curation [PDF, 8 pages]
- Un guide diffusé par l'ANDS et le DCC sur les méthodes de sélection des données à retenir pour leur conservation à long terme, leur partageet leur réutilisation. Plusieurs critères sont proposés pour faciliter la prise de décision.
+ How to Appraise and Select Research Data for Curation [PDF, 8 pages]
+ Un guide diffusé par lANDS et le DCC sur les méthodes de sélection des données à retenir pour leur conservation à long terme, leur partageet leur réutilisation. Plusieurs critères sont proposés pour faciliter la prise de décision.
- Research Data MANTRA [online resource]
- Un cours en ligne destiné aux chercheurs ou d'autres acteurs désireux de gérer des données dans le cadre de leurs opérations de recherche. Ce cours comporte un certain nombre de considérations d'ordre pratique dans le domaine logiciel, sur l'utilisation de SPSS, R, ArcGIS et NVivo.
+ Research Data MANTRA [online resource]
+ Un cours en ligne destiné aux chercheurs ou dautres acteurs désireux de gérer des données dans le cadre de leurs opérations de recherche. Ce cours comporte un certain nombre de considérations dordre pratique dans le domaine logiciel, sur lutilisation de SPSS, R, ArcGIS et NVivo.
"
- body_text_tab_1_html: "
Quand vous vous connectez à DMPonline, vous êtes redirigé vers la page intitulées 'Mes plans'. À partir de là, vous pouvez éditer, partager, exporter ou supprimer l'un de vos plans. Vous verrez à cet endroit aussi les plans que d'autres ont partagé avec vous.
+
+ body_text_tab_1_html: "
Quand vous vous connectez à DMPonline, vous êtes redirigé vers la page intitulées Mes plans. À partir de là, vous pouvez éditer, partager, exporter ou supprimer lun de vos plans. Vous verrez à cet endroit aussi les plans que dautres ont partagé avec vous.
Créer un plan
-
Pour créer un plan, cliquez sur le bouton 'Créer un plan' depuis votre page 'Mes plans' ou depuis le menu du haut. Sélectionnez les options des menus déroulants et parmi les cases à cocher pour définir les questions et les conseils qui devront vous être proposés. Confirmez vos choix en cliquant sur 'Oui, créer un plan'.
+
Pour créer un plan, cliquez sur le bouton Créer un plan depuis votre page Mes plans ou depuis le menu du haut. Sélectionnez les options des menus déroulants et parmi les cases à cocher pour définir les questions et les conseils qui devront vous être proposés. Confirmez vos choix en cliquant sur Oui, créer un plan.
Rédigez votre plan
-
L'interface sous forme d'onglets vous permet de naviguer d'une fonction à l'autre quand vous écrivez et mettez à jour votre plan.
+
Linterface sous forme donglets vous permet de naviguer dune fonction à lautre quand vous écrivez et mettez à jour votre plan.
-
- L'onglet 'Détails du plan' donne quelques informations administratives élémentaires, indique sur quel ensemble de questions et de conseils il s'appuie et des indications générales sur les questions qui vous seront posées.
-
- Le ou les onglets suivants affiche les questions auxquelles il faudra répondre. Cet écran peut afficher plusieurs onglets si votre agence de financement ou votre université vous demande plusieurs séries de questions selon différentes étapes, par ex. :au moment d'une demande de subvention ou après son attribution.
-
- L'onglet 'Partager' vous sert à inviter d'autres personnes à lire ou contribuer à votre plan.
-
- L'onglet 'Exporter' vous permet de décharger votre plan sous différents formats. Cela peut vous être utile pour présenter votre plan dans le cadre d'une demande de subvention.
+
- Longlet Détails du plan donne quelques informations administratives élémentaires, indique sur quel ensemble de questions et de conseils il sappuie et des indications générales sur les questions qui vous seront posées.
+
- Le ou les onglets suivants affiche les questions auxquelles il faudra répondre. Cet écran peut afficher plusieurs onglets si votre agence de financement ou votre université vous demande plusieurs séries de questions selon différentes étapes, par ex. :au moment dune demande de subvention ou après son attribution.
+
- Longlet Partager vous sert à inviter dautres personnes à lire ou contribuer à votre plan.
+
- Longlet Exporter vous permet de décharger votre plan sous différents formats. Cela peut vous être utile pour présenter votre plan dans le cadre dune demande de subvention.
-
Quand les différents onglets s'affichent, ils montrent les différentes parties de votre plan à l'écran. Cliquez pour répondre aux différentes questions. Vous pouvez mettre en forme vos réponses en utilisant les boutons de mise à jour.
-
Des conseils peuvent s'afficher dans le panneau de droite. Cliquez sur le symbole '+' pour qu'ils apparaissent.
-
Pensez à 'enregistrer' vos réponses avant de poursuivre.
+
Quand les différents onglets saffichent, ils montrent les différentes parties de votre plan à lécran. Cliquez pour répondre aux différentes questions. Vous pouvez mettre en forme vos réponses en utilisant les boutons de mise à jour.
+
Des conseils peuvent safficher dans le panneau de droite. Cliquez sur le symbole + pour quils apparaissent.
+
Pensez à enregistrer vos réponses avant de poursuivre.
Partager des plans
-
Insérez les courriels des collaborateurs que vous souhaitez inviter à lire ou modifier votre plan. Utilisez les options du menu déroulant pour leur attribuer les droits souhaités et cliquez sur 'Ajouter le collaborateur'
+
Insérez les courriels des collaborateurs que vous souhaitez inviter à lire ou modifier votre plan. Utilisez les options du menu déroulant pour leur attribuer les droits souhaités et cliquez sur Ajouter le collaborateur
Exporter des plans
-
À cet endroit vous pouvez décharger votre plans dans différents formats. Cela peut vous servir pour présenter votre plan dans le cadre d'une demande de subvention. Choisissez le format de visualisation ou de déchargement souhaité puis cliquer pour lancer l'export. Quand vous vous connecterez à DMPonline, celui-ci vous dirigera vers votre page 'Mes plans'. Vous pourrez modifier, partager, exporter ou supprimer l'un ou l'autre de vos plans. Vous verrez aussi les plans que d'autres ont partagé avec vous.
-
Données d'héritage
-
S'il vous faut accéder à des plans provenant de la version antérieure de cet outil, veuillez aller sur DMPonline v3.
"
+
À cet endroit vous pouvez décharger votre plans dans différents formats. Cela peut vous servir pour présenter votre plan dans le cadre dune demande de subvention. Choisissez le format de visualisation ou de déchargement souhaité puis cliquer pour lancer lexport. Quand vous vous connecterez à DMPonline, celui-ci vous dirigera vers votre page Mes plans. Vous pourrez modifier, partager, exporter ou supprimer lun ou lautre de vos plans. Vous verrez aussi les plans que dautres ont partagé avec vous.
+
Données dhéritage
+
Sil vous faut accéder à des plans provenant de la version antérieure de cet outil, veuillez aller sur DMPonline v3.
DMPonline est fourni par le Digital Curation Centre (Centre de curation numérique britannique - DCC). Pour plus de renseignements, consultez notre site web. Pour nous contacter, veuillez remplir le formulaire ci-après ou envoyez un courriel à dmponline@dcc.ac.uk.
"
- github_text_html: "
Si un fonctionnalité vous paraît souhaitable, ou si vous pensez constater une erreur, veuillez consulter la liste des questions à traiter sur GitHub. Si votre question n'est pas répertoriée, merci de l'ajouter. Si elle y figure, merci d'ajouter un commentaire si vous disposez d'informations supplémentaires ou souhaitez nous informer de l'importance qu'elle revêt pour vous. Ceci nous permettra de prioriser de futurs développements.
"
+ intro_text_html: "
DMPonline est fourni par le Digital Curation Centre (Centre de curation numérique britannique - DCC). Pour plus de renseignements, consultez notre site web. Pour nous contacter, veuillez remplir le formulaire ci-après ou envoyez un courriel à dmponline@dcc.ac.uk.
"
+ github_text_html: "
Si un fonctionnalité vous paraît souhaitable, ou si vous pensez constater une erreur, veuillez consulter la liste des questions à traiter sur GitHub. Si votre question nest pas répertoriée, merci de lajouter. Si elle y figure, merci dajouter un commentaire si vous disposez dinformations supplémentaires ou souhaitez nous informer de limportance quelle revêt pour vous. Ceci nous permettra de prioriser de futurs développements.
La communauté des utilisateurs de DMPonline est active et s'agrandit, et nous remercions ses membres qui nous proposent des idées pour améliorer ses fonctionnalités ou en créer de nouvelles. Nous faisons des bilans réguliers et décidons comment développer le service en répondant à ces besoins en évolution. Pour que tout le monde puisse rester dans la boucle, nous publions nos futurs projets dans la Feuille de route de DMPonline.
-
Notre feuille de route pour 2015 est organisée en cycles de 2 mois, et détaille un éventail de nouvelles fonctionnalités et d'améliorations à des fonctionnalités existantes.
-
-
Pour nous assurer d'aller dans le bon sens, nous nous efforçons d'élaborer notre feuille de route en concertation avec notre groupe d'utilisateurs de DMPonline.
+ body_text_tab_1_html: "
La communauté des utilisateurs de DMPonline est active et sagrandit, et nous remercions ses membres qui nous proposent des idées pour améliorer ses fonctionnalités ou en créer de nouvelles. Nous faisons des bilans réguliers et décidons comment développer le service en répondant à ces besoins en évolution. Pour que tout le monde puisse rester dans la boucle, nous publions nos futurs projets dans la Feuille de route de DMPonline.
+
Notre feuille de route pour 2015 est organisée en cycles de 2 mois, et détaille un éventail de nouvelles fonctionnalités et daméliorations à des fonctionnalités existantes.
+
+
Pour nous assurer daller dans le bon sens, nous nous efforçons délaborer notre feuille de route en concertation avec notre groupe dutilisateurs de DMPonline.
Version actuelle
-
À ce jour, DMPonline en est à sa version 4.1, publiée en mai 2015. Elle comporte une fonctionnalité de commentaires, des conseils plus précis sur comment s'enregistrer avec des authentifiants d'établissement, des conseils pour le déploiement, ainsi que des propositions méthodologiques pour l'internationalisation. La note de version et les documents détaillent plus complètement ces évolutions.
+
À ce jour, DMPonline en est à sa version 4.1, publiée en mai 2015. Elle comporte une fonctionnalité de commentaires, des conseils plus précis sur comment senregistrer avec des authentifiants détablissement, des conseils pour le déploiement, ainsi que des propositions méthodologiques pour linternationalisation. La note de version et les documents détaillent plus complètement ces évolutions.
Plusieurs fonctionnalités nouvelles sont programmées pour la version suivante :
- Identification institutionnelle
-
- Fonctionnalité d'examen de DMP
-
- Alerte de notifications de demande d'assistance aux établissements
+
- Fonctionnalité dexamen de DMP
+
- Alerte de notifications de demande dassistance aux établissements
- Statistiques et analyses pour administrateurs
-
- Mise en place d'une gestion de cycle de vie (par ex. :état \"projet\", \"terminé\", \"publié\")
-
- Développement d'API
+
- Mise en place dune gestion de cycle de vie (par ex. :état \"projet\", \"terminé\", \"publié\")
+
- Développement dAPI
- Assistance localisée
-
Si vous souhaitez contribuer à l'élaboration de nos projets de développements, vous pouvez vous joindre à notre groupe d'utilisateurs. Rendez-vous sur l'onglet \"Impliquez-vous\" pour plus d'informations sur la façon de vous joindre à nous.
"
+
Si vous souhaitez contribuer à lélaboration de nos projets de développements, vous pouvez vous joindre à notre groupe dutilisateurs. Rendez-vous sur longlet \"Impliquez-vous\" pour plus dinformations sur la façon de vous joindre à nous.
"
body_text_tab_2_html: "
Le développement et la maintenance de DMPonline sont assurés par le Digital Curation Centre (Centre de curation numérique britannique - DCC). Nous formons une petite équipe et nous nous sommes volontiers ouverts à des collaborations. Plusieurs possibilités vous sont offertes dans ce but :
-
Rejoindre le groupe d'utilisateurs
-
Nous souhaitons nouer des liens plus actifs avec nos utilisateurs, et nous vous invitons donc à faire partie de notre groupe d'utilisateurs. Nous avons mis en place une liste de diffusion pour ce groupe à laquelle vous pouvez vous abonner. Nous organisons aussi des réunions de consultation sur nos projets.
-
Nos réunions du groupe d'utilisateurs sont en général organisées sur un sujet précis (par ex. :étoffer une API par des cas d'utilisations). Aussi nos invitations sont lancées en fonction de vos domaines de compétence. Il est aussi utile pour nous de savoir à quelle catégorie d'utilisateur vous appartenez : chercheur, administrateur d'un établissement, bibliothécaire ou documentaliste, développeur informatique, personnel financier, etc.
-
Merci de nous indiquer vos centres d'intérêts et de faire partager vos suggestions de développements souhaités via la liste de diffusion pour que toute la communauté faire part de ses réactions.
+
Rejoindre le groupe dutilisateurs
+
Nous souhaitons nouer des liens plus actifs avec nos utilisateurs, et nous vous invitons donc à faire partie de notre groupe dutilisateurs. Nous avons mis en place une liste de diffusion pour ce groupe à laquelle vous pouvez vous abonner. Nous organisons aussi des réunions de consultation sur nos projets.
+
Nos réunions du groupe dutilisateurs sont en général organisées sur un sujet précis (par ex. :étoffer une API par des cas dutilisations). Aussi nos invitations sont lancées en fonction de vos domaines de compétence. Il est aussi utile pour nous de savoir à quelle catégorie dutilisateur vous appartenez : chercheur, administrateur dun établissement, bibliothécaire ou documentaliste, développeur informatique, personnel financier, etc.
+
Merci de nous indiquer vos centres dintérêts et de faire partager vos suggestions de développements souhaités via la liste de diffusion pour que toute la communauté faire part de ses réactions.
Personnaliser DMPonline
-
DMPonline peut être personnalisé en fonctions des institutions et des disciplines. Vous pouvez y ajouter des modèles destinés aux utilisateurs de votre établissement et ajouter des conseils qui expliquent comment trouver localement de l'assistance et des services. Des réponses types peuvent être ajoutées pour aider les utilisateurs à comprendre les informations qu'ils doivent rédiger dans un plan de gestion de données (DMP). Pour cela, vous devrez demander des droits d'accès administrateur, merci de nous envoyer un courriel à dmponline@dcc.ac.uk.
DMPonline peut être personnalisé en fonctions des institutions et des disciplines. Vous pouvez y ajouter des modèles destinés aux utilisateurs de votre établissement et ajouter des conseils qui expliquent comment trouver localement de lassistance et des services. Des réponses types peuvent être ajoutées pour aider les utilisateurs à comprendre les informations quils doivent rédiger dans un plan de gestion de données (DMP). Pour cela, vous devrez demander des droits daccès administrateur, merci de nous envoyer un courriel à dmponline@dcc.ac.uk.
DMPonline est une application Ruby on Rails. Le code source est disponible sous licence GNU AGPL (Affero General Public License). Elle autorise tout un chacun à réutiliser le code librement, mais vous oblige à partager le code source de toute extensions de la même manière. Veuillez-nous informer si vous installez une instance de DMPonline et offrez à votre tour vos contributions à la communauté.
-
Si vous installez une instance de DMPonline, nous vous demandons de créditer DMPonline au DCC comme étant à l'origine de cet outil. Nous recommandons que la mention de crédit se fasse sous la forme du logo de DMPonline renvoyant par un lien vers la version hébergée par le DCC.
+
Si vous installez une instance de DMPonline, nous vous demandons de créditer DMPonline au DCC comme étant à lorigine de cet outil. Nous recommandons que la mention de crédit se fasse sous la forme du logo de DMPonline renvoyant par un lien vers la version hébergée par le DCC.
Nous sommes désireux de travailler avec des développeurs extérieurs pour ajouter de nouvelles fonctionnalité à cet outil.Nous sommes également ouverts à fournir de nouvelles fonctionnalités à titre onéreux. Si vous souhaitez que priorité soit donnée à certaines extensions ou si vous disposez de moyens pour soutenir des travaux de développement supplémentaires, veuillez nous contacter sur dmponline@dcc.ac.uk pour en négocier les conditions.
Soutenir nos travaux
-
Nous sommes impressionné par la montée en l'utilisation de DMPonline au Royaume-Uni comme à m'international et nous souhaitons vivement savoir comment vous utilisez cet outil, comment vous promouvez son utilisation dans votre environnement. Nous savons que d'autres que nous ont mis en place des programmes de formation, créé des supports d'assistance et de conseils et militent pour son utilisation. Veuillez nous le faire savoir, car cela nous permet d'en montrer l'impact.
+
Nous sommes impressionné par la montée en lutilisation de DMPonline au Royaume-Uni comme à minternational et nous souhaitons vivement savoir comment vous utilisez cet outil, comment vous promouvez son utilisation dans votre environnement. Nous savons que dautres que nous ont mis en place des programmes de formation, créé des supports dassistance et de conseils et militent pour son utilisation. Veuillez nous le faire savoir, car cela nous permet den montrer limpact.
Nous réfléchissons actuellement sur des solutions pour créer des moyens de financement. Cela nous permettra de répondre plus efficacement à une demande montante et de garantir la pérennité de DMPonline. Des projets seront bientôt rendus publics en consultation, mais nous accueillons volontiers vos suggestions pour soutenir au mieux nos travaux.
Le Digital Curation Centre (Centre de curation numérique britannique - DCC) est un consortium porté par le Jisc et installé dans les université d'Édimbourg, de Glasgow et de Bath. Nos missions concernent au premier chef la communauté de recherche britannique, en particulier le secteur de l'enseignement supérieur et de la formation tout au long de la vie.
Le Digital Curation Centre (Centre de curation numérique britannique - DCC) est un consortium porté par le Jisc et installé dans les université dÉdimbourg, de Glasgow et de Bath. Nos missions concernent au premier chef la communauté de recherche britannique, en particulier le secteur de lenseignement supérieur et de la formation tout au long de la vie.
DMPonline
-
-
DMPonline ('l'outil', 'le système') est une ressource partagée pour la communauté de recherche développée par le DCC. Elle est hébergée par l'université d'Édimbourg.
+
+
DMPonline (loutil, le système) est une ressource partagée pour la communauté de recherche développée par le DCC. Elle est hébergée par luniversité dÉdimbourg.
Vos informations personnelles
-
-
Pour pouvoir identifier et administrer votre compte dans DMPonline, nous avons besoin d'enregistrer votre adresse de courriel. Il se peut que nous l'utilisions aussi pour recueillir votre avis sur l'utilisation de cet outil, ou de vous informer des dernières évolutions ou versions. Ces informations pourront être échangées entre institutions partenaires du DCC mais uniquement à des fins légitimes pour le DCC. Nous ne vendrons, ni ne louerons ni n'échangerons les informations personnelles que vous nous fournirez.
+
+
Pour pouvoir identifier et administrer votre compte dans DMPonline, nous avons besoin denregistrer votre adresse de courriel. Il se peut que nous lutilisions aussi pour recueillir votre avis sur lutilisation de cet outil, ou de vous informer des dernières évolutions ou versions. Ces informations pourront être échangées entre institutions partenaires du DCC mais uniquement à des fins légitimes pour le DCC. Nous ne vendrons, ni ne louerons ni néchangerons les informations personnelles que vous nous fournirez.
Protections des données à caractère personnel
-
-
Les informations que vous enregistrez dans le système ne peuvent être visualisées que par vous-même, par les personnes avec lesquelles vous avez décidé d'en partager l'accès, et - uniquement pour la maintenance du service - pour les administrateurs du système de l'université d'Édimbourg. Nous extrayons des informations anonymisées, automatiquement et sous forme agrégée à partir des DMP, mais nous n'accédons pas à votre contenu directement, ni ne l'utilisons ni le partageons avec des tiers sans autorisation de votre part. Des agents habilités de votre établissement d'affiliation pourront avoir accès à vos DMP dans des conditions précises, par ex. :pour vérifier le respect des prescriptions de l'établissement ou d'agences de financement ou pour calculer les besoins de stockage.
+
+
Les informations que vous enregistrez dans le système ne peuvent être visualisées que par vous-même, par les personnes avec lesquelles vous avez décidé den partager laccès, et - uniquement pour la maintenance du service - pour les administrateurs du système de luniversité dÉdimbourg. Nous extrayons des informations anonymisées, automatiquement et sous forme agrégée à partir des DMP, mais nous naccédons pas à votre contenu directement, ni ne lutilisons ni le partageons avec des tiers sans autorisation de votre part. Des agents habilités de votre établissement daffiliation pourront avoir accès à vos DMP dans des conditions précises, par ex. :pour vérifier le respect des prescriptions de létablissement ou dagences de financement ou pour calculer les besoins de stockage.
-
Liberté d'information
-
-
L'université d'Édimbourg assure le stockage de vos DMP pour votre compte, mais ceux-ci restent votre propriété et sous votre responsabilité. Toute demande au titre de la législation sur la liberté d'information se verra redirigée vers votre établissement d'affiliation.
+
Liberté dinformation
+
+
Luniversité dÉdimbourg assure le stockage de vos DMP pour votre compte, mais ceux-ci restent votre propriété et sous votre responsabilité. Toute demande au titre de la législation sur la liberté dinformation se verra redirigée vers votre établissement daffiliation.
Mots de passe
-
-
Votre mot de passe est enregistré sous forme chiffrée et ne peut être récupéré. En cas d'oubli, celui-ci devra être réinitialisé.
+
+
Votre mot de passe est enregistré sous forme chiffrée et ne peut être récupéré. En cas doubli, celui-ci devra être réinitialisé.
Cookies
-
-
Veuillez noter que DMPonline utilise des cookies. Vous pourrez en savoir plus sur les cookies et la manière dont nous les utilisons sur le site web principal du DCC.
+
+
Veuillez noter que DMPonline utilise des cookies. Vous pourrez en savoir plus sur les cookies et la manière dont nous les utilisons sur le site web principal du DCC.
-
-
En utilisant l'outil, vous reconnaissez avoir pris connaissance et accepté les présentes conditions d'utilisation.
"
+
+
En utilisant loutil, vous reconnaissez avoir pris connaissance et accepté les présentes conditions dutilisation.
"
+
+ identifier_schemes:
+ connect_success: 'Votre compte a été connecté à %{scheme}'
+ connect_failure: 'Nous ne pouvions pas connecter votre compte %{scheme}'
+ disconnect_success: 'Votre compte a été déconnecté de %{scheme}'
+ disconnect_failure: 'Nous avons été incapables de déconnecter votre compte %{scheme}'
+ new_login_success: "Vous ne l'avez pas configurer un compte avec nous. S'il vous plaît remplir les informations ci-dessous pour terminer votre inscription."
+ new_login_failure: "Nous avons été en mesure de vérifier votre compte. S'il vous plaît utiliser le formulaire ci-dessous pour créer un nouveau compte. Vous serez en mesure de lier votre nouveau compte par la suite."
+
+ schemes:
+ orcid:
+ logo: 'http://orcid.org/sites/default/files/images/orcid_16x16.png'
+ user_landing_page: 'https://orcid.org/%{id}'
+ connect: 'Créer ou Connectez votre ID ORCID'
+ connect_tooltip: 'ORCID fournit un identifiant numérique persistant qui vous distingue des autres chercheurs. En savoir plus sur orcid.org'
+ disconnect_confirmation: 'Êtes-vous certain que vous voulez déconnecter votre ID orcid?'
+ disconnect_tooltip: 'Déconnectez votre compte à partir de ORCID. Vous pouvez vous reconnecter à tout moment.'
+
+ magic_strings:
+ organisation_types:
+ funder: 'Funder'
+ organisation: 'Organisation'
+ project: 'Project'
+ institution: 'Institution'
+ research_institute: 'Research Institute'
+ template: 'Template'
+ managing_organisation: 'Digital Curation Centre'
+ user_role_types:
+ admin: 'admin'
+ org_admin: 'org_admin'
+ user: 'user'
+ roles:
+ super_admin: 'admin'
+ organisational_admin: 'org_admin'
+ user: 'user'
+ add_organisations: 'add_organisations'
+ change_org_affiliation: 'change_org_affiliation'
+ grant_permissions: 'grant_permissions'
+ modify_templates: 'modify_templates'
+ modify_guidance: 'modify_guidance'
+ use_api: 'use_api'
+ change_org_details: 'change_org_details'
+ grant_api_to_orgs: 'grant_api_to_orgs'
+ token_permission_types:
+ guidances: 'guidances'
+ plans: 'plans'
+ templates: 'templates'
+ statistics: 'statistics'
+ languages:
diff --git a/config/locales/static_pages/de.static.yml.example b/config/locales/static_pages/de.static.yml.example
index a7b92c5..bc6987b 100644
--- a/config/locales/static_pages/de.static.yml.example
+++ b/config/locales/static_pages/de.static.yml.example
@@ -147,6 +147,16 @@
title: "Kontakt"
intro_text_html: "
DMP Builder is provided by the University of Alberta Libraries. You can find out more about us on our Research Data Management page. If you would like to contact us about DMP Builder, please insert your query into the webform below or email data@ualberta.ca.
Bei Benutzung dieser Anwendung stimmen Sie den Nutzungsbedingungen zu.
-
"
\ No newline at end of file
+
"
+
+ public_plans_page:
+ title: "Öffentliche DMPs"
+ no_plans_body_text_html: "Es wurden noch keine DMPs veröffentlicht."
+ body_text_html: "Öffentliche DMPs sind Pläne, die mit dem DMPTool erstellt und öffentlich von ihren Eigentümern veröffentlicht werden. Sie werden nicht auf Qualität, Vollständigkeit oder die Einhaltung der funder Richtlinien überprüft."
\ No newline at end of file
diff --git a/config/locales/static_pages/en-UK.static.yml.example b/config/locales/static_pages/en-UK.static.yml.example
index db791d8..8a7d774 100644
--- a/config/locales/static_pages/en-UK.static.yml.example
+++ b/config/locales/static_pages/en-UK.static.yml.example
@@ -126,15 +126,15 @@
intro_text_html: "
%{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 enter your query in the form below or email dmponline@dcc.ac.uk.
"
github_text_html: "
If you have a feature request or think you have found a bug, please check out the list of issues on GitHub. If your issue isn't listed there, please add it; if it is, please add a comment if you have more information or just to let us know how important it is to you. This will help us to prioritise future developments.
Use of the tool indicates that you understand and agree to these terms and conditions.
"
\ No newline at end of file
+
Use of the tool indicates that you understand and agree to these terms and conditions.
"
+
+ public_plans_page:
+ title: "Public DMPs"
+ body_text_html: "Public DMPs are plans created using the DMPTool and shared publicly by their owners. They are not vetted for quality, completeness, or adherence to funder guidelines."
+ no_plans_body_text_html: "There are no public DMPs."
\ No newline at end of file
diff --git a/config/locales/static_pages/en-US.static.yml.example b/config/locales/static_pages/en-US.static.yml.example
index ed79687..3f9f003 100644
--- a/config/locales/static_pages/en-US.static.yml.example
+++ b/config/locales/static_pages/en-US.static.yml.example
@@ -126,15 +126,15 @@
intro_text_html: "
%{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 enter your query in the form below or email dmponline@dcc.ac.uk.
"
github_text_html: "
If you have a feature request or think you have found a bug, please check out the list of issues on GitHub. If your issue isn't listed there, please add it; if it is, please add a comment if you have more information or just to let us know how important it is to you. This will help us to prioritise future developments.
Use of the tool indicates that you understand and agree to these terms and conditions.
"
+
+ public_plans_page:
+ title: "Public DMPs"
+ body_text_html: "Public DMPs are plans created using the DMPTool and shared publicly by their owners. They are not vetted for quality, completeness, or adherence to funder guidelines."
+ no_plans_body_text_html: "There are no public DMPs."
\ No newline at end of file
diff --git a/config/locales/static_pages/fr.static.yml.example b/config/locales/static_pages/fr.static.yml.example
index 3bf7021..b48a7c2 100644
--- a/config/locales/static_pages/fr.static.yml.example
+++ b/config/locales/static_pages/fr.static.yml.example
@@ -114,7 +114,17 @@
title: "Communiquez avec nous"
intro_text_html: "
L'Assistant PGD est rendu disponible par les Bibliothèques de l'Université d'Alberta. Pour en savoir plus sur les services offerts par ces bibliothèques, consulter la page suivante : Research Data Management page. Si vous désirez communiquer avec nous concernant l'Assistant PGD, merci de saisir votre message dans le formulaire Web ci-dessous ou nous écrire à portage@carl-abrc.ca.
"
+
terms_page:
title: "Exploitation sous licence et conditions d'utilisation"
body_text_html: "
@@ -145,4 +155,9 @@
-
En utilisant l'outil, vous comprenez et acceptez ces conditions.
"
\ No newline at end of file
+
En utilisant l'outil, vous comprenez et acceptez ces conditions.
"
+
+ public_plans_page:
+ title: "DMP publics"
+ no_plans_body_text_html: "Aucun DMP n'a été rendu public."
+ body_text_html: "Les DMP publics sont des plans créés à l'aide de DMPTool et partagés publiquement par leurs propriétaires. Ils ne sont pas vérifiés pour la qualité, l'exhaustivité ou l'adhésion aux lignes directrices des bailleurs de fonds."
diff --git a/config/routes.rb b/config/routes.rb
index f1da471..a86ed2e 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,18 +1,28 @@
Rails.application.routes.draw do
- devise_for :users, :controllers => {:registrations => "registrations", :confirmations => 'confirmations', :passwords => 'passwords', :sessions => 'sessions', :omniauth_callbacks => 'users/omniauth_callbacks'} do
+ devise_for :users, controllers: {
+ registrations: "registrations",
+ confirmations: 'confirmations',
+ passwords: 'passwords',
+ sessions: 'sessions',
+ omniauth_callbacks: 'users/omniauth_callbacks'} do
+
get "/users/sign_out", :to => "devise/sessions#destroy"
end
-
+
# WAYFless access point - use query param idp
get 'auth/shibboleth' => 'users/omniauth_shibboleth_request#redirect', :as => 'user_omniauth_shibboleth'
get 'auth/shibboleth/assoc' => 'users/omniauth_shibboleth_request#associate', :as => 'user_shibboleth_assoc'
+ #post '/auth/:provider/callback' => 'sessions#oauth_create'
+
# fix for activeadmin signout bug
devise_scope :user do
get '/users/sign_out' => 'devise/sessions#destroy'
end
+ delete '/users/identifiers/:id', to: 'user_identifiers#destroy', as: 'destroy_user_identifier'
+
#ActiveAdmin.routes(self)
#organisation admin area
@@ -36,6 +46,9 @@
get "help" => 'static_pages#help'
get "roadmap" => 'static_pages#roadmap'
get "terms" => 'static_pages#termsuse'
+ get "public_plans" => 'static_pages#public_plans'
+ get "public_export/:id" => 'static_pages#public_export', as: 'public_export'
+
get "existing_users" => 'existing_users#index'
#post 'contact_form' => 'contacts', as: 'localized_contact_creation'
@@ -88,6 +101,7 @@
get 'admin_phase'
get 'admin_previewphase'
get 'admin_cloneversion'
+ get 'admin_template_history'
delete 'admin_destroy'
delete 'admin_destroyversion'
delete 'admin_destroyphase'
@@ -188,8 +202,8 @@
namespace :api, defaults: {format: :json} do
namespace :v0 do
resources :guidance_groups, only: [:index, :show]
- resources :plans, only: :create, controller: "projects", path: "plans"
- resources :templates, only: :index, controller: "dmptemplates", path: "templates"
+ resources :plans, only: :create
+ resources :templates, only: :index
resource :statistics, only: [], controller: "statistics", path: "statistics" do
member do
get :users_joined
diff --git a/db/migrate/20130708092900_devise_create_admin_users.rb b/db/migrate/20130708092900_devise_create_admin_users.rb
index ac03c44..b386cea 100644
--- a/db/migrate/20130708092900_devise_create_admin_users.rb
+++ b/db/migrate/20130708092900_devise_create_admin_users.rb
@@ -44,8 +44,8 @@
t.timestamps
end
- add_index :admin_users, :email, :unique => true
- add_index :admin_users, :reset_password_token, :unique => true
+ # +add_index+ :admin_users, :email, :unique => true
+ # add_index :admin_users, :reset_password_token, :unique => true
# add_index :admin_users, :confirmation_token, :unique => true
# add_index :admin_users, :unlock_token, :unique => true
# add_index :admin_users, :authentication_token, :unique => true
diff --git a/db/migrate/20131118094629_change_versions_published.rb b/db/migrate/20131118094629_change_versions_published.rb
index dc8deb4..6f05c55 100644
--- a/db/migrate/20131118094629_change_versions_published.rb
+++ b/db/migrate/20131118094629_change_versions_published.rb
@@ -1,5 +1,18 @@
class ChangeVersionsPublished < ActiveRecord::Migration
def change
- change_column :versions, :published, :boolean
+ add_column :versions, :published_tmp, :boolean
+
+ # Since we ultimately drop the Version model we must check for it before
+ # attempting to manipulate data
+ if table_exists?('versions')
+ Version.reset_column_information # make the new column available to model methods
+ Version.all.each do |v|
+ v.published_tmp = v.published == 't' ? true : false
+ v.save
+ end
+ end
+
+ remove_column :versions, :published
+ rename_column :versions, :published_tmp, :published
end
end
diff --git a/db/migrate/20150809210811_add_field_to_questions.rb b/db/migrate/20150809210811_add_field_to_questions.rb
index a4cc424..95ad8c6 100644
--- a/db/migrate/20150809210811_add_field_to_questions.rb
+++ b/db/migrate/20150809210811_add_field_to_questions.rb
@@ -1,9 +1,12 @@
class AddFieldToQuestions < ActiveRecord::Migration
def change
add_column :questions, :option_comment_display, :boolean, :default => true
- Question.find_each do |question|
- question.option_comment_display = true
- question.save!
+
+ if table_exists?('questions')
+ Question.find_each do |question|
+ question.option_comment_display = true
+ question.save!
+ end
end
end
end
diff --git a/db/migrate/20151208142029_add_field_to_guidances.rb b/db/migrate/20151208142029_add_field_to_guidances.rb
index e2c792f..a6dbe1c 100644
--- a/db/migrate/20151208142029_add_field_to_guidances.rb
+++ b/db/migrate/20151208142029_add_field_to_guidances.rb
@@ -1,9 +1,12 @@
class AddFieldToGuidances < ActiveRecord::Migration
def change
add_column :guidances, :published, :boolean
- Guidance.find_each do |guidance|
- guidance.published = true
- guidance.save!
+
+ if table_exists?('guidances')
+ Guidance.find_each do |guidance|
+ guidance.published = true
+ guidance.save!
+ end
end
end
end
diff --git a/db/migrate/20151208142836_update_field_in_guidance_groups.rb b/db/migrate/20151208142836_update_field_in_guidance_groups.rb
index f77f8ed..2062073 100644
--- a/db/migrate/20151208142836_update_field_in_guidance_groups.rb
+++ b/db/migrate/20151208142836_update_field_in_guidance_groups.rb
@@ -1,8 +1,10 @@
class UpdateFieldInGuidanceGroups < ActiveRecord::Migration
def change
+ if table_exists?('guidance_groups')
GuidanceGroup.find_each do |guidance_group|
guidance_group.published = true
guidance_group.save!
end
+ end
end
end
diff --git a/db/migrate/20161021100420_single_organisation_for_users.rb b/db/migrate/20161021100420_single_organisation_for_users.rb
index c7aa3ac..20cceec 100644
--- a/db/migrate/20161021100420_single_organisation_for_users.rb
+++ b/db/migrate/20161021100420_single_organisation_for_users.rb
@@ -2,16 +2,18 @@
def up
unless Rails.env.test?
- User.class_eval do
- belongs_to :organisation,
- :class_name => "Organisation",
- :foreign_key => "organisation_id"
- end
+ if table_exists?('users')
+ User.class_eval do
+ belongs_to :organisation,
+ :class_name => "Organisation",
+ :foreign_key => "organisation_id"
+ end
- User.includes(:user_org_roles, :roles).all.each do | user |
- # NOTE: we'll grab the first organisation (if present), so if there are more, these will be lost!
- user.organisation_id = user.user_org_roles.first.organisation_id unless user.user_org_roles.empty?
- user.save!
+ User.includes(:user_org_roles, :roles).all.each do | user |
+ # NOTE: we'll grab the first organisation (if present), so if there are more, these will be lost!
+ user.organisation_id = user.user_org_roles.first.organisation_id unless user.user_org_roles.empty?
+ user.save!
+ end
end
end
diff --git a/db/migrate/20161024163546_create_user_identifier_scheme.rb b/db/migrate/20161024163546_create_user_identifier_scheme.rb
new file mode 100644
index 0000000..657d0e5
--- /dev/null
+++ b/db/migrate/20161024163546_create_user_identifier_scheme.rb
@@ -0,0 +1,10 @@
+class CreateUserIdentifierScheme < ActiveRecord::Migration
+ def change
+ create_table :identifier_schemes do |t|
+ t.string :name
+ t.string :description
+ t.boolean :active
+ t.timestamps
+ end
+ end
+end
\ No newline at end of file
diff --git a/db/migrate/20161024163920_create_user_identifiers.rb b/db/migrate/20161024163920_create_user_identifiers.rb
new file mode 100644
index 0000000..9a86e89
--- /dev/null
+++ b/db/migrate/20161024163920_create_user_identifiers.rb
@@ -0,0 +1,11 @@
+class CreateUserIdentifiers < ActiveRecord::Migration
+ def change
+ create_table :user_identifiers do |t|
+ t.string :identifier
+ t.timestamps
+ end
+
+ add_reference :user_identifiers, :user, foreign_key: true
+ add_reference :user_identifiers, :identifier_scheme, foreign_key: true
+ end
+end
diff --git a/db/migrate/20161122152339_new_plan_template_structure.rb b/db/migrate/20161122152339_new_plan_template_structure.rb
index 5f27f6a..2432dea 100644
--- a/db/migrate/20161122152339_new_plan_template_structure.rb
+++ b/db/migrate/20161122152339_new_plan_template_structure.rb
@@ -138,138 +138,144 @@
# Then migrate all customised plans
# migrate most current template into templates (org facing)
proj_number = 0
- # migrating uncustomised plans
- Template.transaction do
- Project.includes( { dmptemplate: [ { phases: [ { versions: [:sections] } ] } ] }, {plans: [:version ]}, :organisation).find_each(batch_size: 20) do |project|
- puts ""
- puts "beginning number #{proj_number}"
- proj_number +=1
- if project.dmptemplate.nil? # one of the templates dosent exist
- next
- end
- new_plan = initNewPlan(project) # copy data from project to NewPlan object
- plans = project.plans # select plans for project
- version_ids = []
- versions = []
- plans.each do |plan| # select version ids from plans list
- version_ids << plan.version.id
- versions << plan.version
- end
- dmptemplate = project.dmptemplate # select template for project
- phases = dmptemplate.phases # select phases for project
- temp_match = false # flag for if we found a matching template
+
+ if table_exists?('projects') && table_exists?('templates') && table_exists?('answers') &&
+ table_exists?('comments') && table_exists?('sections')
+ # migrating uncustomised plans
+ Template.transaction do
+ Project.includes( { dmptemplate: [ { phases: [ { versions: [:sections] } ] } ] }, {plans: [:version ]}, :organisation).find_each(batch_size: 20) do |project|
+ puts ""
+ puts "beginning number #{proj_number}"
+ proj_number +=1
+ if project.dmptemplate.nil? # one of the templates dosent exist
+ next
+ end
+ new_plan = initNewPlan(project) # copy data from project to NewPlan object
+ plans = project.plans # select plans for project
+ version_ids = []
+ versions = []
+ plans.each do |plan| # select version ids from plans list
+ version_ids << plan.version.id
+ versions << plan.version
+ end
+ dmptemplate = project.dmptemplate # select template for project
+ phases = dmptemplate.phases # select phases for project
+ temp_match = false # flag for if we found a matching template
- puts "checking for matching templates for #{dmptemplate.title} customised by #{project.organisation.name}" unless project.organisation.nil?
- puts "checking for matching templates for #{dmptemplate.title} uncustomised" unless project.organisation.present?
- possible_templates = project.organisation.nil? ?
- Template.includes(:new_phases).where(dmptemplate_id: dmptemplate.id, organisation_id: dmptemplate.organisation_id) :
- Template.includes(:new_phases).where(dmptemplate_id: dmptemplate.id, organisation_id: project.organisation_id)
- possible_templates.find_each do |t| # for templates with same id
- # early cut for un-even number of phases
- new_phase_versions = t.new_phases.pluck(:vid)
- if new_phase_versions.sort == version_ids.sort
- temp_match = true # flag that we found match
- # we can point the new_plan to this template and init all data
- new_plan.template_id = t.id
+ puts "checking for matching templates for #{dmptemplate.title} customised by #{project.organisation.name}" unless project.organisation.nil?
+ puts "checking for matching templates for #{dmptemplate.title} uncustomised" unless project.organisation.present?
+ possible_templates = project.organisation.nil? ?
+ Template.includes(:new_phases).where(dmptemplate_id: dmptemplate.id, organisation_id: dmptemplate.organisation_id) :
+ Template.includes(:new_phases).where(dmptemplate_id: dmptemplate.id, organisation_id: project.organisation_id)
+ possible_templates.find_each do |t| # for templates with same id
+ # early cut for un-even number of phases
+ new_phase_versions = t.new_phases.pluck(:vid)
+ if new_phase_versions.sort == version_ids.sort
+ temp_match = true # flag that we found match
+ # we can point the new_plan to this template and init all data
+ new_plan.template_id = t.id
+ new_plan.save!
+ puts "found a match: #{t.title} version #{t.version}"
+ break
+ end
+ end
+
+
+ # this section handles for customisations
+ unless temp_match # no matches found, init template & phase & sections & questions & themes & options
+ puts "creating new template for #{dmptemplate.title}" unless project.organisation.present?
+ puts "creating new template for #{dmptemplate.title} customised by #{project.organisation.name}" unless project.organisation.nil?
+ modifiable = project.organisation.nil? || project.organisation_id == dmptemplate.organisation_id
+ template = initTemplate(dmptemplate, modifiable, project.organisation_id) # needs to select next version of temp based on old_temp_id
+ # some differences between a customised and un-customised template
+ # customised templates need a different organisation_id
+ template.organisation_id = project.organisation_id unless project.organisation_id.nil? # updated to not overwrite with nil
+ # customised templates follow different version rules
+ template.save!
+ # since template was not a match, need to gen/copy all data below the template level
+ versions.each do |version|
+ new_phase = initNewPhase(version.phase, version, template, modifiable)
+ new_phase.save!
+ sections = []
+ sections += version.sections.where("organisation_id = ? ", dmptemplate.organisation_id).pluck(:id)
+ unless project.organisation_id.nil?
+ sections += Section.where(organisation_id: project.organisation_id, version_id: version.id).pluck(:id)
+ end
+ Section.includes(questions: [:themes, :options, :suggested_answers]).where(id: sections).each do |section|
+ new_section = initNewSection(section, new_phase, modifiable)
+ new_section.save!
+ section.questions.each do |question|
+ new_question = initNewQuestion(question, new_section, modifiable)
+ new_question.save!
+ question.themes.each do |theme|
+ new_question.themes << theme
+ end
+ question.options.each do |option|
+ question_option = initQuestionOption(option, new_question)
+ question_option.save!
+ end
+ question.suggested_answers.each do |suggested_answer|
+ new_suggested_answer = initNewSuggestedAnswers(suggested_answer, new_question)
+ new_suggested_answer.save!
+ end
+ end
+ end
+ end
+ new_plan.template_id = template.id
new_plan.save!
- puts "found a match: #{t.title} version #{t.version}"
- break
end
- end
-
- # this section handles for customisations
- unless temp_match # no matches found, init template & phase & sections & questions & themes & options
- puts "creating new template for #{dmptemplate.title}" unless project.organisation.present?
- puts "creating new template for #{dmptemplate.title} customised by #{project.organisation.name}" unless project.organisation.nil?
- template = initTemplate(dmptemplate) # needs to select next version of temp based on old_temp_id
- # some differences between a customised and un-customised template
- # customised templates need a different organisation_id
- template.organisation_id = project.organisation_id
- # customised templates follow different version rules
- template.save!
- # since template was not a match, need to gen/copy all data below the template level
- versions.each do |version|
- new_phase = initNewPhase(version.phase, version, template, true)
- new_phase.save!
- sections = []
- sections += version.sections.where("organisation_id = ? ", dmptemplate.organisation_id).pluck(:id)
- unless project.organisation_id.nil?
- sections += Section.where(organisation_id: project.organisation_id, version_id: version.id).pluck(:id)
+ # up to this point, we have either found a matching template and pointed the
+ # new_plan obj at it, or we have generated a new:
+ # template/phases/sections/questions/question_options/question_themes
+ # now need to init answers, notes, answers_options
+ #new_plan.template.new_phases.each do |new_phase|
+ puts "transfering plan data"
+ project.project_groups.each do |group|
+ role = initRole(group, new_plan)
+ role.save!
+ end
+ template = Template.includes(new_phases: {new_sections: :new_questions}).find(new_plan.template_id)
+ template.new_phases.each do |new_phase|
+ old_plan = project.plans.where(version_id: new_phase.vid).first
+ puts "old plan id: #{old_plan.id}"
+ puts "plan ids :#{plans.pluck(:id)}"
+ if old_plan.id == 46
+ puts "IT'S NOT WORKING RITE HERE!!!!!!!!!!!!!!!!!!!!!!! IT'S NOT WORKING RITE HERE!!!!!!!!!!!!!!!!!!!!!!! IT'S NOT WORKING RITE HERE!!!!!!!!!!!!!!!!!!!!!!!"
end
- Section.includes(questions: [:themes, :options, :suggested_answers]).where(id: sections).each do |section|
- new_section = initNewSection(section, new_phase, true)
- new_section.save!
- section.questions.each do |question|
- new_question = initNewQuestion(question, new_section, true)
- new_question.save!
- question.themes.each do |theme|
- new_question.themes << theme
+ new_phase.new_sections.each do |new_section|
+ new_section.new_questions.each do |new_question|
+ # init new answer
+ old_ans = Answer.where(question_id: new_question.question_id, plan_id: old_plan.id).order("created_at DESC").first
+ # init comments on answer
+ new_ans = nil
+ comments = Comment.where(question_id: new_question.question_id, plan_id: old_plan.id)
+ # unless there is no old answer, and no comments, create an answer
+ unless old_ans.nil? && comments.length < 1
+ new_ans = initNewAnswer(old_ans, new_plan, new_question)
+ new_ans.save!
end
- question.options.each do |option|
- question_option = initQuestionOption(option, new_question)
- question_option.save!
+ comments.find_each do |comment|
+ note = initNote(comment, new_ans)
+ note.save!
end
- question.suggested_answers.each do |suggested_answer|
- new_suggested_answer = initNewSuggestedAnswers(suggested_answer, new_question)
- new_suggested_answer.save!
+ if new_ans.present? && new_ans.text.present? && new_ans.text.include?("test2")
+ puts "!!!!!!!!!!!!!!!!DEBUG MODE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+ puts "old answer: #{old_ans.text}"
+ puts "old answer: #{old_ans.id}"
+ puts "new answer: #{new_ans.text}"
+ puts "old plans: #{project.plans.pluck(:id)}"
+ puts "old_plan: #{old_plan.id}"
+ puts "old project: #{project.id}"
+ puts "question: #{new_question.question_id}"
+ puts "old user: #{old_ans.user.email}"
end
end
end
end
- new_plan.template_id = template.id
- new_plan.save!
- end
-
- # up to this point, we have either found a matching template and pointed the
- # new_plan obj at it, or we have generated a new:
- # template/phases/sections/questions/question_options/question_themes
- # now need to init answers, notes, answers_options
- #new_plan.template.new_phases.each do |new_phase|
- puts "transfering plan data"
- project.project_groups.each do |group|
- role = initRole(group, new_plan)
- role.save!
- end
- template = Template.includes(new_phases: {new_sections: :new_questions}).find(new_plan.template_id)
- template.new_phases.each do |new_phase|
- old_plan = project.plans.where(version_id: new_phase.vid).first
- puts "old plan id: #{old_plan.id}"
- puts "plan ids :#{plans.pluck(:id)}"
- if old_plan.id == 46
- puts "IT'S NOT WORKING RITE HERE!!!!!!!!!!!!!!!!!!!!!!! IT'S NOT WORKING RITE HERE!!!!!!!!!!!!!!!!!!!!!!! IT'S NOT WORKING RITE HERE!!!!!!!!!!!!!!!!!!!!!!!"
- end
- new_phase.new_sections.each do |new_section|
- new_section.new_questions.each do |new_question|
- # init new answer
- old_ans = Answer.where(question_id: new_question.question_id, plan_id: old_plan.id).order("created_at DESC").first
- # init comments on answer
- new_ans = nil
- comments = Comment.where(question_id: new_question.question_id, plan_id: old_plan.id)
- # unless there is no old answer, and no comments, create an answer
- unless old_ans.nil? && comments.length < 1
- new_ans = initNewAnswer(old_ans, new_plan, new_question)
- new_ans.save!
- end
- comments.find_each do |comment|
- note = initNote(comment, new_ans)
- note.save!
- end
- if new_ans.present? && new_ans.text.present? && new_ans.text.include?("test2")
- puts "!!!!!!!!!!!!!!!!DEBUG MODE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
- puts "old answer: #{old_ans.text}"
- puts "old answer: #{old_ans.id}"
- puts "new answer: #{new_ans.text}"
- puts "old plans: #{project.plans.pluck(:id)}"
- puts "old_plan: #{old_plan.id}"
- puts "old project: #{project.id}"
- puts "question: #{new_question.question_id}"
- puts "old user: #{old_ans.user.email}"
- end
- end
- end
end
end
+
end
# indexes on join tables at the end
@@ -303,23 +309,32 @@
-def initTemplate(dmptemp)
- template = Template.new
- template.title = dmptemp.title
- template.description = dmptemp.description
- template.published = dmptemp.published
- template.organisation_id = dmptemp.organisation_id
- template.locale = dmptemp.locale
- template.is_default = dmptemp.is_default
- template.created_at = dmptemp.created_at
- template.updated_at = dmptemp.updated_at
- template.visibility = 0 # dummy value for private
- template.customization_of = nil
- template.version = Template.where(dmptemplate_id: dmptemp.id).blank? ?
- 0 : Template.where(dmptemplate_id: dmptemp.id).pluck(:version).max + 1
- puts "NEW TEMPLATE: \n title: #{template.title} \n version: #{template.version} \n others_present? #{Template.where(dmptemplate_id: dmptemp.id).count}"
- template.dmptemplate_id = dmptemp.id
- return template
+def initTemplate(dmptemp, modifiable, organisation_id)
+ if table_exists?('templates')
+ template = Template.new
+ template.title = dmptemp.title
+ template.description = dmptemp.description
+ template.published = dmptemp.published
+ template.organisation_id = organisation_id.present? ? organisation_id : dmptemp.organisation_id
+ template.locale = dmptemp.locale
+ template.is_default = dmptemp.is_default
+ template.created_at = dmptemp.created_at
+ template.updated_at = dmptemp.updated_at
+ template.visibility = 0 # dummy value for private
+ template.customization_of = modifiable ? nil : dmptemp.id
+ template.dmptemplate_id = dmptemp.id
+ # if no templates with the same dmptemplate_id and organisation_id exist
+ # 0
+ # otherwise
+ # take the maximum version from templates with the same dmptemplate_id and organisation_id and add 1
+ template.version = Template.where(dmptemplate_id: dmptemp.id, organisation_id: template.organisation_id).blank? ?
+ 0 : Template.where(dmptemplate_id: dmptemp.id, organisation_id: template.organisation_id).pluck(:version).max + 1
+ puts "NEW TEMPLATE: \n title: #{template.title} \n version: #{template.version} \n others_present? #{Template.where(dmptemplate_id: dmptemp.id).count}"
+ return template
+
+ else
+ return nil
+ end
end
def initNewPhase(phase, version, temp, modifiable)
@@ -354,8 +369,10 @@
new_question.text = question.text
new_question.default_value = question.default_value
new_question.guidance = question.guidance.nil? ? "" : question.guidance
- Guidance.where(question_id: question.id).each do |guidance|
- new_question.guidance += guidance.text
+ if table_exists?('guidances')
+ Guidance.where(question_id: question.id).each do |guidance|
+ new_question.guidance += guidance.text
+ end
end
new_question.number = question.number
new_question.new_section_id = new_section.id
@@ -378,35 +395,45 @@
new_answer.created_at = answer.created_at
new_answer.updated_at = answer.updated_at
# not sure if these get saved properly as new_answer has no id yet
- answer.options.each do |option|
- new_answer.question_options << QuestionOption.find_by(option_id: option.id)
+ if table_exists?('question_options')
+ answer.options.each do |option|
+ new_answer.question_options << QuestionOption.find_by(option_id: option.id)
+ end
end
end
return new_answer
end
def initQuestionOption(option, new_question)
- question_option = QuestionOption.new
- question_option.new_question_id = new_question.id
- question_option.option_id = option.id
- question_option.text = option.text
- question_option.number = option.number
- question_option.is_default = option.is_default
- question_option.created_at = option.created_at
- question_option.updated_at = option.updated_at
- return question_option
+ if table_exists?('question_options')
+ question_option = QuestionOption.new
+ question_option.new_question_id = new_question.id
+ question_option.option_id = option.id
+ question_option.text = option.text
+ question_option.number = option.number
+ question_option.is_default = option.is_default
+ question_option.created_at = option.created_at
+ question_option.updated_at = option.updated_at
+ return question_option
+ else
+ return nil
+ end
end
def initNote(comment, new_answer)
- note = Note.new
- note.user_id = comment.user_id
- note.text = comment.text
- note.archived = comment.archived
- note.archived_by = comment.archived_by
- note.new_answer_id = new_answer.id
- note.created_at = comment.created_at
- note.updated_at = comment.updated_at
- return note
+ if table_exists?('notes')
+ note = Note.new
+ note.user_id = comment.user_id
+ note.text = comment.text
+ note.archived = comment.archived
+ note.archived_by = comment.archived_by
+ note.new_answer_id = new_answer.id
+ note.created_at = comment.created_at
+ note.updated_at = comment.updated_at
+ return note
+ else
+ return nil
+ end
end
def initNewPlan(project)
@@ -438,13 +465,17 @@
end
def initRole(project_group, new_plan)
- role = Role.new
- role.creator = project_group.project_creator
- role.administrator = project_group.project_administrator
- role.editor = project_group.project_editor
- role.created_at = project_group.created_at
- role.updated_at = project_group.updated_at
- role.user_id = project_group.user_id
- role.new_plan_id = new_plan.id
- return role
-end
\ No newline at end of file
+ if table_exists?('roles')
+ role = Role.new
+ role.creator = project_group.project_creator
+ role.administrator = project_group.project_administrator
+ role.editor = project_group.project_editor
+ role.created_at = project_group.created_at
+ role.updated_at = project_group.updated_at
+ role.user_id = project_group.user_id
+ role.new_plan_id = new_plan.id
+ return role
+ else
+ return nil
+ end
+end
diff --git a/db/migrate/20161205095624_replacing_organisation_types_with_bitflags.rb b/db/migrate/20161205095624_replacing_organisation_types_with_bitflags.rb
index 16be879..0ebed56 100644
--- a/db/migrate/20161205095624_replacing_organisation_types_with_bitflags.rb
+++ b/db/migrate/20161205095624_replacing_organisation_types_with_bitflags.rb
@@ -12,26 +12,30 @@
# t.boolean :School
# t.boolean :Project
end
- # migrate old org_type data to bitfield
- Org.includes(:organisation_type).all.each do |org|
- unless org.organisation_type.nil?
- case org.organisation_type.name
- when "Organisation"
- org.organisation = true
- when "Funder"
- org.funder = true
- when "Project"
- org.project = true
- when "School"
- org.school = true
- when "Institution"
- org.institution = true
- when "Research Institute"
- org.research_institute = true
+
+ if table_exists?('orgs')
+ # migrate old org_type data to bitfield
+ Org.includes(:organisation_type).all.each do |org|
+ unless org.organisation_type.nil?
+ case org.organisation_type.name
+ when "Organisation"
+ org.organisation = true
+ when "Funder"
+ org.funder = true
+ when "Project"
+ org.project = true
+ when "School"
+ org.school = true
+ when "Institution"
+ org.institution = true
+ when "Research Institute"
+ org.research_institute = true
+ end
+ org.save!
end
- org.save!
end
end
+
# remove organisation_type_id field from orgs
remove_column :orgs, :organisation_type_id
# remove organisation_type table
diff --git a/db/migrate/20161205095625_replacing_plan_roles_with_bitflags.rb b/db/migrate/20161205095625_replacing_plan_roles_with_bitflags.rb
index fa9d143..859586c 100644
--- a/db/migrate/20161205095625_replacing_plan_roles_with_bitflags.rb
+++ b/db/migrate/20161205095625_replacing_plan_roles_with_bitflags.rb
@@ -6,19 +6,23 @@
rename_column :roles, :creator, :create
rename_column :roles, :editor, :edit
rename_column :roles, :administrator, :admin
+
# transfer the data from the other fields to the bitfield
- Role.find_each do |role|
- if role.admin
- role.administrator = true
+ if table_exists?('roles')
+ Role.find_each do |role|
+ if role.admin
+ role.administrator = true
+ end
+ if role.edit
+ role.editor = true
+ end
+ if role.create
+ role.creator = true
+ end
+ role.save!
end
- if role.edit
- role.editor = true
- end
- if role.create
- role.creator = true
- end
- role.save!
end
+
# remove the other columns
remove_column :roles, :create
remove_column :roles, :edit
diff --git a/db/migrate/20161206122926_add_foreign_keys.rb b/db/migrate/20161206122926_add_foreign_keys.rb
index 2eba3c6..7574279 100644
--- a/db/migrate/20161206122926_add_foreign_keys.rb
+++ b/db/migrate/20161206122926_add_foreign_keys.rb
@@ -83,79 +83,91 @@
def scrub_references
# answers
i = 0
- Answer.includes(:user, :plan, :question).find_each do |ans|
- if ans.user.nil? && ans.user_id.present?
- ans.user_id = nil
- i += 1
+ if table_exists?('answers')
+ Answer.includes(:user, :plan, :question).find_each do |ans|
+ if ans.user.nil? && ans.user_id.present?
+ ans.user_id = nil
+ i += 1
+ end
+ if ans.plan.nil? && ans.plan_id.present?
+ ans.plan_id = nil
+ i += 1
+ end
+ if ans.question.nil? && ans.question_id.present?
+ ans.question_id = nil
+ i += 1
+ end
+ ans.save!
end
- if ans.plan.nil? && ans.plan_id.present?
- ans.plan_id = nil
- i += 1
- end
- if ans.question.nil? && ans.question_id.present?
- ans.question_id = nil
- i += 1
- end
- ans.save!
end
puts "#{i} answers scrubbed"
# notes
i = 0
- Note.includes(:answer, :user).find_each do |note|
- if note.answer.nil? && note.answer_id.present?
- note.answer_id = nil
- i += 1
+ if table_exists?('notes')
+ Note.includes(:answer, :user).find_each do |note|
+ if note.answer.nil? && note.answer_id.present?
+ note.answer_id = nil
+ i += 1
+ end
+ if note.user.nil? && note.user_id.present?
+ note.user_id = nil
+ i += 1
+ end
+ note.save!
end
- if note.user.nil? && note.user_id.present?
- note.user_id = nil
- i += 1
- end
- note.save!
end
puts "#{i} notes scrubbed"
# templates
i = 0
- Template.includes(:org).find_each do |temp|
- if temp.org.nil? && temp.org_id.present?
- temp.org_id = nil
- i += 1
+ if table_exists?('templates')
+ Template.includes(:org).find_each do |temp|
+ if temp.org.nil? && temp.org_id.present?
+ temp.org_id = nil
+ i += 1
+ end
+ temp.save!
end
- temp.save!
end
puts "#{i} templates scrubbed"
# guidance_groups
# i = 0
- # GuidanceGroup.includes(:org).find_each do |gg|
- # if gg.org.nil? && gg.org_id.present?
- # gg.org_id = nil
- # i += 1
+ # if table_exists?('guidance_groups')
+ # GuidanceGroup.includes(:org).find_each do |gg|
+ # if gg.org.nil? && gg.org_id.present?
+ # gg.org_id = nil
+ # i += 1
+ # end
+ # gg.save!
# end
- # gg.save!
# end
# puts "#{i} guidance groups scrubbed"
# # question_options
# i = 0
- # QuestionOption.includes(:question).find_each do |opt|
- # if opt.question.nil? && opt.question_id.present?
- # opt.question_id = nil
- # i += 1
+ # if table_exists?('question_options')
+ # QuestionOption.includes(:question).find_each do |opt|
+ # if opt.question.nil? && opt.question_id.present?
+ # opt.question_id = nil
+ # i += 1
+ # end
+ # opt.save!
# end
- # opt.save!
# end
# puts "#{i} question_options scrubbed"
# # orgs
# i = 0
- # Org.includes( :language).find_each do |org|
- # if org.language.nil? && org.language_id.present?
- # org.language_id = nil
- # i += 1
+ # if table_exists?('orgs')
+ # Org.includes( :language).find_each do |org|
+ # if org.language.nil? && org.language_id.present?
+ # org.language_id = nil
+ # i += 1
+ # end
+ # org.save!
# end
- # org.save!
# end
# puts "#{i} orgs scrubbed"
@@ -167,15 +179,17 @@
# roles
i = 0
- Role.includes(:user, :plan).find_each do |role|
- if role.user.nil? && role.user_id.present?
- Role.delete_all(user_id: role.user_id)
- i += 1
- next
- end
- if role.plan.nil? && role.plan_id.present?
- Role.delete_all(plan_id: role.plan_id)
- i += 1
+ if table_exists?('roles')
+ Role.includes(:user, :plan).find_each do |role|
+ if role.user.nil? && role.user_id.present?
+ Role.delete_all(user_id: role.user_id)
+ i += 1
+ next
+ end
+ if role.plan.nil? && role.plan_id.present?
+ Role.delete_all(plan_id: role.plan_id)
+ i += 1
+ end
end
end
puts "#{i} roles scrubbed"
@@ -186,17 +200,19 @@
# # suggested_answers
# i = 0
- # SuggestedAnswer.includes(:org, :question).find_each do |sa|
- # if sa.org.nil? && sa.org_id.present?
- # sa.org_id = nil
- # i += 1
+ # if table_exists?('suggested_answers')
+ # SuggestedAnswer.includes(:org, :question).find_each do |sa|
+ # if sa.org.nil? && sa.org_id.present?
+ # sa.org_id = nil
+ # i += 1
+ # end
+ # if sa.question.nil?
+ # sa.delete!
+ # i += 1
+ # next
+ # end
+ # sa.save!
# end
- # if sa.question.nil?
- # sa.delete!
- # i += 1
- # next
- # end
- # sa.save!
# end
# puts "#{i} suggested answers scrubbed"
@@ -204,23 +220,27 @@
# # users
# i = 0
- # User.includes(:org, :language).find_each do |u|
- # if u.org.nil? && u.org_id.present?
- # u.org_id = nil
- # i += 1
+ # if table_exists?('users')
+ # User.includes(:org, :language).find_each do |u|
+ # if u.org.nil? && u.org_id.present?
+ # u.org_id = nil
+ # i += 1
+ # end
+ # if u.language.nil? && u.language_id.present?
+ # u.language_id = nil
+ # i += 1
+ # end
+ # u.save!
# end
- # if u.language.nil? && u.language_id.present?
- # u.language_id = nil
- # i += 1
- # end
- # u.save!
# end
# puts "#{i} users scrubbed"
# users_perms
- UsersPerm.includes(:user).all.each do |u|
- if u.user.nil?
- UsersPerm.delete_all(user_id: u.user_id)
+ if table_exists?('users_perms')
+ UsersPerm.includes(:user).all.each do |u|
+ if u.user.nil?
+ UsersPerm.delete_all(user_id: u.user_id)
+ end
end
end
end
diff --git a/db/migrate/20161208122123_single_group_for_guidance.rb b/db/migrate/20161208122123_single_group_for_guidance.rb
index 4c02f86..562673c 100644
--- a/db/migrate/20161208122123_single_group_for_guidance.rb
+++ b/db/migrate/20161208122123_single_group_for_guidance.rb
@@ -1,16 +1,18 @@
class SingleGroupForGuidance < ActiveRecord::Migration
def change
unless Rails.env.test?
- Guidance.class_eval do
- belongs_to :guidance_group, class_name: "GuidanceGroup", foreign_key: "guidance_group_id"
- end
+ if table_exists?('guidances')
+ Guidance.class_eval do
+ belongs_to :guidance_group, class_name: "GuidanceGroup", foreign_key: "guidance_group_id"
+ end
- Guidance.includes( :guidance_groups).all.each do |guidance|
- guidance.guidance_group_id = guidance.guidance_groups.first.id unless guidance.guidance_groups.empty?
- if guidance.guidance_group_id.nil?
- guidance.destroy
- else
- guidance.save!
+ Guidance.includes( :guidance_groups).all.each do |guidance|
+ guidance.guidance_group_id = guidance.guidance_groups.first.id unless guidance.guidance_groups.empty?
+ if guidance.guidance_group_id.nil?
+ guidance.destroy
+ else
+ guidance.save!
+ end
end
end
end
diff --git a/db/migrate/20170124235829_add_visibility_to_plans.rb b/db/migrate/20170124235829_add_visibility_to_plans.rb
new file mode 100644
index 0000000..1ba4f54
--- /dev/null
+++ b/db/migrate/20170124235829_add_visibility_to_plans.rb
@@ -0,0 +1,5 @@
+class AddVisibilityToPlans < ActiveRecord::Migration
+ def change
+ add_column :plans, :visibility, :integer, null: false, default: 0
+ end
+end
diff --git a/db/migrate/20170130173049_add_option_based_to_question_formats.rb b/db/migrate/20170130173049_add_option_based_to_question_formats.rb
new file mode 100644
index 0000000..936fa3e
--- /dev/null
+++ b/db/migrate/20170130173049_add_option_based_to_question_formats.rb
@@ -0,0 +1,15 @@
+class AddOptionBasedToQuestionFormats < ActiveRecord::Migration
+ def change
+ add_column :question_formats, :option_based, :boolean, default: false
+
+ # Set the new field to true for the question formats that have options
+ if table_exists?('question_formats')
+ QuestionFormat.all.each do |qf|
+ unless ['text area', 'text field', 'date'].include?(qf.title.downcase)
+ qf.option_based = true
+ qf.save!
+ end
+ end
+ end
+ end
+end
diff --git a/db/migrate/20170130173612_move_orcid_id_from_users_to_user_identifiers.rb b/db/migrate/20170130173612_move_orcid_id_from_users_to_user_identifiers.rb
new file mode 100644
index 0000000..c20c37f
--- /dev/null
+++ b/db/migrate/20170130173612_move_orcid_id_from_users_to_user_identifiers.rb
@@ -0,0 +1,20 @@
+class MoveOrcidIdFromUsersToUserIdentifiers < ActiveRecord::Migration
+ def change
+
+ if table_exists?('users') && table_exists?('identifier_schemes')
+ scheme = IdentifierScheme.find_by(name: 'orcid')
+
+ unless scheme.nil?
+ User.all.each do |u|
+ unless u.orcid_id.nil?
+ u.user_identifiers << UserIdentifier.new(identifier_scheme: scheme, identifier: u.orcid_id)
+ u.save!
+ end
+ end
+
+ remove_column :users, :orcid_id
+ end
+ end
+
+ end
+end
diff --git a/db/migrate/20170201194502_remove_region_group_and_add_super_region_id_to_regions.rb b/db/migrate/20170201194502_remove_region_group_and_add_super_region_id_to_regions.rb
new file mode 100644
index 0000000..07a1e1d
--- /dev/null
+++ b/db/migrate/20170201194502_remove_region_group_and_add_super_region_id_to_regions.rb
@@ -0,0 +1,7 @@
+class RemoveRegionGroupAndAddSuperRegionIdToRegions < ActiveRecord::Migration
+ def change
+ drop_table :region_groups if table_exists?(:region_groups)
+
+ add_column :regions, :super_region_id, :integer unless column_exists?(:regions, :super_region_id)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index fc8d37b..90ab057 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,60 +11,61 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20161213101804) do
-
- # These are extensions that must be enabled in order to support this database
- enable_extension "plpgsql"
+ActiveRecord::Schema.define(version: 20170201194502) do
create_table "answers", force: :cascade do |t|
- t.text "text"
- t.integer "plan_id"
- t.integer "user_id"
- t.integer "question_id"
+ t.text "text", limit: 65535
+ t.integer "plan_id", limit: 4
+ t.integer "user_id", limit: 4
+ t.integer "question_id", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
end
+ add_index "answers", ["plan_id"], name: "fk_rails_84a6005a3e", using: :btree
+ add_index "answers", ["question_id"], name: "fk_rails_3d5ed4418f", using: :btree
+ add_index "answers", ["user_id"], name: "fk_rails_584be190c2", using: :btree
+
create_table "answers_question_options", id: false, force: :cascade do |t|
- t.integer "answer_id", null: false
- t.integer "question_option_id", null: false
+ t.integer "answer_id", limit: 4, null: false
+ t.integer "question_option_id", limit: 4, null: false
end
add_index "answers_question_options", ["answer_id", "question_option_id"], name: "answer_question_option_index", using: :btree
add_index "answers_question_options", ["question_option_id", "answer_id"], name: "question_option_answer_index", using: :btree
create_table "exported_plans", force: :cascade do |t|
- t.integer "plan_id"
- t.integer "user_id"
- t.string "format"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.integer "plan_id", limit: 4
+ t.integer "user_id", limit: 4
+ t.string "format", limit: 255
+ t.datetime "created_at"
+ t.datetime "updated_at"
end
create_table "file_types", force: :cascade do |t|
- t.string "name"
- t.string "icon_name"
- t.integer "icon_size"
- t.string "icon_location"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.string "name", limit: 255
+ t.string "icon_name", limit: 255
+ t.integer "icon_size", limit: 4
+ t.string "icon_location", limit: 255
+ t.datetime "created_at"
+ t.datetime "updated_at"
end
create_table "file_uploads", force: :cascade do |t|
- t.string "name"
- t.string "title"
- t.text "description"
- t.integer "size"
+ t.string "name", limit: 255
+ t.string "title", limit: 255
+ t.text "description", limit: 65535
+ t.integer "size", limit: 4
t.boolean "published"
- t.string "location"
- t.integer "file_type_id"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.string "location", limit: 255
+ t.integer "file_type_id", limit: 4
+ t.datetime "created_at"
+ t.datetime "updated_at"
end
create_table "friendly_id_slugs", force: :cascade do |t|
- t.string "slug", null: false
- t.integer "sluggable_id", null: false
+ t.string "slug", limit: 255, null: false
+ t.integer "sluggable_id", limit: 4, null: false
t.string "sluggable_type", limit: 40
t.datetime "created_at"
end
@@ -74,282 +75,329 @@
add_index "friendly_id_slugs", ["sluggable_type"], name: "index_friendly_id_slugs_on_sluggable_type", using: :btree
create_table "guidance_groups", force: :cascade do |t|
- t.string "name"
- t.integer "org_id"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.string "name", limit: 255
+ t.integer "org_id", limit: 4
+ t.datetime "created_at"
+ t.datetime "updated_at"
t.boolean "optional_subset"
t.boolean "published"
end
+ add_index "guidance_groups", ["org_id"], name: "fk_rails_819c1dbbc7", using: :btree
+
create_table "guidances", force: :cascade do |t|
- t.text "text"
- t.integer "guidance_group_id"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.integer "question_id"
+ t.text "text", limit: 65535
+ t.integer "guidance_group_id", limit: 4
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "question_id", limit: 4
t.boolean "published"
end
+ add_index "guidances", ["guidance_group_id"], name: "fk_rails_20d29da787", using: :btree
+
+ create_table "identifier_schemes", force: :cascade do |t|
+ t.string "name", limit: 255
+ t.string "description", limit: 255
+ t.boolean "active"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
create_table "languages", force: :cascade do |t|
- t.string "abbreviation"
- t.string "description"
- t.string "name"
+ t.string "abbreviation", limit: 255
+ t.string "description", limit: 255
+ t.string "name", limit: 255
t.boolean "default_language"
end
create_table "notes", force: :cascade do |t|
- t.integer "user_id"
- t.text "text"
+ t.integer "user_id", limit: 4
+ t.text "text", limit: 65535
t.boolean "archived"
- t.integer "answer_id"
- t.integer "archived_by"
+ t.integer "answer_id", limit: 4
+ t.integer "archived_by", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
end
+ add_index "notes", ["answer_id"], name: "fk_rails_907f8d48bf", using: :btree
+ add_index "notes", ["user_id"], name: "fk_rails_7f2323ad43", using: :btree
+
create_table "org_token_permissions", force: :cascade do |t|
- t.integer "org_id"
- t.integer "token_permission_type_id"
+ t.integer "org_id", limit: 4
+ t.integer "token_permission_type_id", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
end
+ add_index "org_token_permissions", ["org_id"], name: "fk_rails_e1db1b22c5", using: :btree
+ add_index "org_token_permissions", ["token_permission_type_id"], name: "fk_rails_2aa265f538", using: :btree
+
create_table "orgs", force: :cascade do |t|
- t.string "name"
- t.string "abbreviation"
- t.string "target_url"
- t.string "wayfless_entity"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.integer "parent_id"
+ t.string "name", limit: 255
+ t.string "abbreviation", limit: 255
+ t.string "target_url", limit: 255
+ t.string "wayfless_entity", limit: 255
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "parent_id", limit: 4
t.boolean "is_other"
- t.string "sort_name"
- t.text "banner_text"
- t.string "logo_file_name"
- t.integer "region_id"
- t.integer "language_id"
- t.string "logo_uid"
- t.string "logo_name"
- t.string "contact_email"
- t.integer "org_type", default: 0, null: false
+ t.string "sort_name", limit: 255
+ t.text "banner_text", limit: 65535
+ t.string "logo_file_name", limit: 255
+ t.integer "region_id", limit: 4
+ t.integer "language_id", limit: 4
+ t.string "logo_uid", limit: 255
+ t.string "logo_name", limit: 255
+ t.string "contact_email", limit: 255
+ t.integer "org_type", limit: 4, default: 0, null: false
end
+ add_index "orgs", ["language_id"], name: "fk_rails_5640112cab", using: :btree
+ add_index "orgs", ["region_id"], name: "fk_rails_5a6adf6bab", using: :btree
+
create_table "perms", force: :cascade do |t|
- t.string "name"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.string "name", limit: 255
+ t.datetime "created_at"
+ t.datetime "updated_at"
end
add_index "perms", ["name"], name: "index_perms_on_name", using: :btree
add_index "perms", ["name"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree
create_table "phases", force: :cascade do |t|
- t.string "title"
- t.text "description"
- t.integer "number"
- t.integer "template_id"
+ t.string "title", limit: 255
+ t.text "description", limit: 65535
+ t.integer "number", limit: 4
+ t.integer "template_id", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
- t.string "slug"
+ t.string "slug", limit: 255
t.boolean "modifiable"
end
+ add_index "phases", ["template_id"], name: "fk_rails_0f8036cb2e", using: :btree
+
create_table "plans", force: :cascade do |t|
- t.integer "project_id"
- t.string "title"
- t.integer "template_id"
+ t.integer "project_id", limit: 4
+ t.string "title", limit: 255
+ t.integer "template_id", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
- t.string "slug"
- t.string "grant_number"
- t.string "identifier"
- t.text "description"
- t.string "principal_investigator"
- t.string "principal_investigator_identifier"
- t.string "data_contact"
- t.string "funder_name"
+ t.string "slug", limit: 255
+ t.string "grant_number", limit: 255
+ t.string "identifier", limit: 255
+ t.text "description", limit: 65535
+ t.string "principal_investigator", limit: 255
+ t.string "principal_investigator_identifier", limit: 255
+ t.string "data_contact", limit: 255
+ t.string "funder_name", limit: 255
+ t.integer "visibility", limit: 4, default: 0, null: false
end
- create_table "project_guidance", id: false, force: :cascade do |t|
- t.integer "project_id", null: false
- t.integer "guidance_group_id", null: false
- end
-
- add_index "project_guidance", ["project_id", "guidance_group_id"], name: "index_project_guidance_on_project_id_and_guidance_group_id", using: :btree
+ add_index "plans", ["template_id"], name: "fk_rails_3424ca281f", using: :btree
create_table "question_formats", force: :cascade do |t|
- t.string "title"
- t.text "description"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.string "title", limit: 255
+ t.text "description", limit: 65535
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.boolean "option_based", default: false
end
create_table "question_options", force: :cascade do |t|
- t.integer "question_id"
- t.string "text"
- t.integer "number"
+ t.integer "question_id", limit: 4
+ t.string "text", limit: 255
+ t.integer "number", limit: 4
t.boolean "is_default"
t.datetime "created_at"
t.datetime "updated_at"
end
+ add_index "question_options", ["question_id"], name: "fk_rails_b9c5f61cf9", using: :btree
+
create_table "questions", force: :cascade do |t|
- t.text "text"
- t.text "default_value"
- t.text "guidance"
- t.integer "number"
- t.integer "section_id"
+ t.text "text", limit: 65535
+ t.text "default_value", limit: 65535
+ t.text "guidance", limit: 65535
+ t.integer "number", limit: 4
+ t.integer "section_id", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
- t.integer "question_format_id"
- t.boolean "option_comment_display", default: true
+ t.integer "question_format_id", limit: 4
+ t.boolean "option_comment_display", default: true
t.boolean "modifiable"
end
+ add_index "questions", ["question_format_id"], name: "fk_rails_4fbc38c8c7", using: :btree
+ add_index "questions", ["section_id"], name: "fk_rails_c50eadc3e3", using: :btree
+
create_table "questions_themes", id: false, force: :cascade do |t|
- t.integer "question_id", null: false
- t.integer "theme_id", null: false
+ t.integer "question_id", limit: 4, null: false
+ t.integer "theme_id", limit: 4, null: false
end
add_index "questions_themes", ["question_id", "theme_id"], name: "question_theme_index", using: :btree
add_index "questions_themes", ["theme_id", "question_id"], name: "theme_question_index", using: :btree
- create_table "region_groups", force: :cascade do |t|
- t.integer "super_region_id"
- t.integer "region_id"
- end
-
create_table "regions", force: :cascade do |t|
- t.string "abbreviation"
- t.string "description"
- t.string "name"
+ t.string "abbreviation", limit: 255
+ t.string "description", limit: 255
+ t.string "name", limit: 255
+ t.integer "super_region_id", limit: 4
end
create_table "roles", force: :cascade do |t|
- t.integer "user_id"
- t.integer "plan_id"
+ t.integer "user_id", limit: 4
+ t.integer "plan_id", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
- t.integer "access", default: 0, null: false
+ t.integer "access", limit: 4, default: 0, null: false
end
+ add_index "roles", ["plan_id"], name: "fk_rails_a1ce6c2772", using: :btree
+ add_index "roles", ["user_id"], name: "fk_rails_ab35d699f0", using: :btree
+
create_table "sections", force: :cascade do |t|
- t.string "title"
- t.text "description"
- t.integer "number"
+ t.string "title", limit: 255
+ t.text "description", limit: 65535
+ t.integer "number", limit: 4
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "published"
- t.integer "phase_id"
+ t.integer "phase_id", limit: 4
t.boolean "modifiable"
end
+ add_index "sections", ["phase_id"], name: "fk_rails_1853581585", using: :btree
+
create_table "settings", force: :cascade do |t|
- t.string "var", null: false
- t.text "value"
- t.integer "target_id", null: false
- t.string "target_type", null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.string "var", limit: 255, null: false
+ t.text "value", limit: 65535
+ t.integer "target_id", limit: 4, null: false
+ t.string "target_type", limit: 255, null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
end
add_index "settings", ["target_type", "target_id", "var"], name: "index_settings_on_target_type_and_target_id_and_var", unique: true, using: :btree
create_table "splash_logs", force: :cascade do |t|
- t.string "destination"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.string "destination", limit: 255
+ t.datetime "created_at"
+ t.datetime "updated_at"
end
create_table "suggested_answers", force: :cascade do |t|
- t.integer "question_id"
- t.integer "org_id"
- t.text "text"
+ t.integer "question_id", limit: 4
+ t.integer "org_id", limit: 4
+ t.text "text", limit: 65535
t.boolean "is_example"
t.datetime "created_at"
t.datetime "updated_at"
end
+ add_index "suggested_answers", ["org_id"], name: "fk_rails_473de65779", using: :btree
+ add_index "suggested_answers", ["question_id"], name: "fk_rails_daa60b5b70", using: :btree
+
create_table "templates", force: :cascade do |t|
- t.string "title"
- t.text "description"
+ t.string "title", limit: 255
+ t.text "description", limit: 65535
t.boolean "published"
- t.integer "org_id"
- t.string "locale"
+ t.integer "org_id", limit: 4
+ t.string "locale", limit: 255
t.boolean "is_default"
t.datetime "created_at"
t.datetime "updated_at"
- t.integer "version"
- t.integer "visibility"
- t.integer "customization_of"
- t.integer "dmptemplate_id"
+ t.integer "version", limit: 4
+ t.integer "visibility", limit: 4
+ t.integer "customization_of", limit: 4
+ t.integer "dmptemplate_id", limit: 4
end
+ add_index "templates", ["org_id"], name: "fk_rails_481431e1bd", using: :btree
+
create_table "themes", force: :cascade do |t|
- t.string "title"
- t.text "description"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "locale"
+ t.string "title", limit: 255
+ t.text "description", limit: 65535
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "locale", limit: 255
end
create_table "themes_in_guidance", id: false, force: :cascade do |t|
- t.integer "theme_id"
- t.integer "guidance_id"
+ t.integer "theme_id", limit: 4
+ t.integer "guidance_id", limit: 4
end
+ add_index "themes_in_guidance", ["guidance_id"], name: "fk_rails_a5ab9402df", using: :btree
+ add_index "themes_in_guidance", ["theme_id"], name: "fk_rails_7d708f6f1e", using: :btree
+
create_table "token_permission_types", force: :cascade do |t|
- t.string "token_type"
- t.text "text_description"
+ t.string "token_type", limit: 255
+ t.text "text_description", limit: 65535
t.datetime "created_at"
t.datetime "updated_at"
end
- create_table "users", force: :cascade do |t|
- t.string "firstname"
- t.string "surname"
- t.string "email", default: "", null: false
- t.string "orcid_id"
- t.string "shibboleth_id"
+ create_table "user_identifiers", force: :cascade do |t|
+ t.string "identifier", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
- t.string "encrypted_password", default: ""
- t.string "reset_password_token"
+ t.integer "user_id", limit: 4
+ t.integer "identifier_scheme_id", limit: 4
+ end
+
+ add_index "user_identifiers", ["identifier_scheme_id"], name: "fk_rails_fe95df7db0", using: :btree
+ add_index "user_identifiers", ["user_id"], name: "fk_rails_65c9a98cdb", using: :btree
+
+ create_table "users", force: :cascade do |t|
+ t.string "firstname", limit: 255
+ t.string "surname", limit: 255
+ t.string "email", limit: 255, default: "", null: false
+ t.string "shibboleth_id", limit: 255
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "encrypted_password", limit: 255, default: ""
+ t.string "reset_password_token", limit: 255
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
- t.integer "sign_in_count", default: 0
+ t.integer "sign_in_count", limit: 4, default: 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
- t.string "current_sign_in_ip"
- t.string "last_sign_in_ip"
- t.string "confirmation_token"
+ t.string "current_sign_in_ip", limit: 255
+ t.string "last_sign_in_ip", limit: 255
+ t.string "confirmation_token", limit: 255
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
- t.string "invitation_token"
+ t.string "invitation_token", limit: 255
t.datetime "invitation_created_at"
t.datetime "invitation_sent_at"
t.datetime "invitation_accepted_at"
- t.string "other_organisation"
+ t.string "other_organisation", limit: 255
t.boolean "dmponline3"
t.boolean "accept_terms"
- t.integer "org_id"
- t.string "api_token"
- t.integer "invited_by_id"
- t.string "invited_by_type"
- t.integer "language_id"
+ t.integer "org_id", limit: 4
+ t.string "api_token", limit: 255
+ t.integer "invited_by_id", limit: 4
+ t.string "invited_by_type", limit: 255
+ t.integer "language_id", limit: 4
end
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true, using: :btree
+ add_index "users", ["language_id"], name: "fk_rails_45f4f12508", using: :btree
+ add_index "users", ["org_id"], name: "fk_rails_e73753bccb", using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
create_table "users_perms", id: false, force: :cascade do |t|
- t.integer "user_id"
- t.integer "perm_id"
+ t.integer "user_id", limit: 4
+ t.integer "perm_id", limit: 4
end
+ add_index "users_perms", ["perm_id"], name: "fk_rails_457217c31c", using: :btree
add_index "users_perms", ["user_id", "perm_id"], name: "index_users_perms_on_user_id_and_perm_id", using: :btree
add_foreign_key "answers", "plans"
@@ -380,6 +428,8 @@
add_foreign_key "templates", "orgs"
add_foreign_key "themes_in_guidance", "guidances"
add_foreign_key "themes_in_guidance", "themes"
+ add_foreign_key "user_identifiers", "identifier_schemes"
+ add_foreign_key "user_identifiers", "users"
add_foreign_key "users", "languages"
add_foreign_key "users", "orgs"
add_foreign_key "users_perms", "perms"
diff --git a/db/seeds.rb b/db/seeds.rb
index 70912b7..216bfda 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -2,762 +2,795 @@
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
-# Dmptemplate default formatting settings based on https://je-s.rcuk.ac.uk/Handbook/pages/GuidanceonCompletingaStandardG/CaseforSupportandAttachments/CaseforSupportandAttachments.htm
+# Identifier Schemes
+# -------------------------------------------------------
+identifier_schemes = [
+ {name: 'orcid', description: 'ORCID researcher identifiers', active: true},
+ {name: 'shibboleth', description: 'Shibboleth', active: false},
+ {name: 'facebook', description: 'Facebook OAuth', active: false}
+]
+identifier_schemes.map{ |is| IdentifierScheme.create!(is) if IdentifierScheme.find_by(name: is[:name]).nil? }
-d1 = DateTime.new(2015, 6, 22)
+# Question Formats
+# -------------------------------------------------------
+question_formats = [
+ {title: "Text area", option_based: false},
+ {title: "Text field", option_based: false},
+ {title: "Radio buttons", option_based: true},
+ {title: "Check box", option_based: true},
+ {title: "Dropdown", option_based: true},
+ {title: "Multi select box", option_based: true},
+ {title: "Date", option_based: false}
+]
+question_formats.map{ |qf| QuestionFormat.create!(qf) if QuestionFormat.find_by(title: qf[:title]).nil? }
-languages = {
- 'English(UK)' => {
- abbreviation: 'en-UK',
- description: 'UK English language used as default',
- name: 'English(UK)',
- default_language: true
- },
- 'FR' => {
- abbreviation: 'fr',
- description: '',
- name: 'fr',
+# Languages (check config/locales for any ones not defined here)
+# -------------------------------------------------------
+languages = [
+ {abbreviation: 'en-UK',
+ description: 'UK English',
+ name: 'English (UK)',
+ default_language: true},
+ {abbreviation: 'en-US',
+ description: 'US English',
+ name: 'English (US)',
+ default_language: false},
+ {abbreviation: 'fr',
+ description: 'French',
+ name: 'French',
+ default_language: false},
+ {abbreviation: 'de',
+ description: 'German',
+ name: 'German',
+ default_language: false},
+ {abbreviation: 'es',
+ description: 'Spanish',
+ name: 'Spanish',
+ default_language: false}
+]
+languages.map{ |l| Language.create!(l) if Language.find_by(abbreviation: l[:abbreviation]).nil? }
+
+# Scan through the locale files and add an entry if a file is present but
+# not defined in this seed file
+Dir.entries("#{Rails.root.join("config", "locales").to_s}").each do |f|
+ if f[-4..-1] == '.yml'
+ lang = f.gsub('.yml', '')
+
+ if Language.where(abbreviation: lang).empty?
+ Language.create!({
+ abbreviation: lang,
+ description: lang,
+ name: lang,
default_language: false
- },
- 'DE' => {
- abbreviation: 'de',
- description: '',
- name: 'de',
- default_language: false
- },
- 'ES' => {
- abbreviation: 'es',
- description: '',
- name: 'es',
- default_language: false
- }
-}
-
-languages.each do |l, details|
- if Language.where(name: details[:name]).empty?
- language = Language.new
- language.abbreviation = details[:abbreviation]
- language.description = details[:description]
- language.name = details[:name]
- language.default_language = details[:default_language]
- language.save!
- end
-end
-
-regions = {
- 'UK' => {
- abbreviation: 'uk',
- description: 'default region',
- name: 'UK',
- },
- 'DE' => {
- abbreviation: 'de',
- description: '',
- name: 'DE',
- },
- 'Horizon2020' => {
- abbreviation: 'horizon',
- description: 'European super region',
- name: 'Horizon2020',
- }
-}
-
-regions.each do |l, details|
- if Region.where(name: details[:name]).empty?
- region = Region.new
- region.abbreviation = details[:abbreviation]
- region.description = details[:description]
- region.name = details[:name]
- region.save!
- end
-end
-
-region_groups = {
- 'UK' => {
- super_region_name: 'Horizon2020',
- region_name: 'UK',
- },
- 'DE' => {
- super_region_name: 'Horizon2020',
- region_name: 'DE',
- }
-}
-
-region_groups.each do |l, details|
- if RegionGroup.find_by(region_id: details[:region_name]).blank?
- region_group = RegionGroup.new
- region_group.super_region_id = Region.find_by_name(details[:super_region_name]).id
- region_group.region_id = Region.find_by_name(details[:region_name]).id
- region_group.save!
- end
-end
-
-organisation_types = {
- 'Organisation' => {
- name: "Organisation"
- },
- 'Funder' => {
- name: "Funder"
- },
- 'Project' => {
- name: "Project"
- },
- 'Institution' => {
- name: "Institution"
- },
- 'Research Institute' => {
- name: "Research Institute"
- }
- }
-
- organisation_types.each do |org_type, details|
- if OrganisationType.where(name: details[:name]).empty?
- organisation_type = OrganisationType.new
- organisation_type.name = details[:name]
- organisation_type.save!
- end
- end
-
- organisations = {
- 'Your Organization' => {
- name: "My Regional Curation Centre",
- abbreviation: "RCC",
- sort_name: "MyRegionalCurationCenter",
- organisation_type: "Organisation",
- description: "An example: Regional Curation Center concerned with research data management (typically the organization hosting this website)",
- banner_text: "Example: Your Regional Curation Center",
- region: 'UK',
- language: 'English(UK)'
- },
- 'Global Funding Organization' => {
- name: "Global Research Center",
- abbreviation: "EGRC",
- sort_name: "GlobalResearchCenter",
- organisation_type: "Funder",
- description: "An example: Research funding agency",
- banner_text: "Example: Global Research Center",
- region: 'UK',
- language: 'English(UK)'
- },
- 'Regional Funding Organization' => {
- name: "Regional Science Federation",
- abbreviation: "RegSciFed",
- sort_name: "RegionalScienceFederation",
- organisation_type: "Funder",
- description: "An example: Regional funding agency for scientific research",
- banner_text: "Example: Regional Science Federation",
- region: 'UK',
- language: 'English(UK)'
- },
- 'Example Institution'=> {
- name: "Capital City College",
- abbreviation: "CapColl",
- sort_name: "CapitalCityCollege",
- organisation_type: "Institution",
- description: "An example: Academic institution",
- banner_text: "Example: Capital City College ... go mascots!!",
- region: 'UK',
- language: 'English(UK)'
- }
- }
-
- organisations.each do |org, details|
- if Org.where(abbreviation: details[:abbreviation]).empty?
- organisation = Org.new
- organisation.name = details[:name]
- organisation.abbreviation = details[:abbreviation]
- organisation.sort_name = details[:sort_name]
- organisation.organisation_type = OrganisationType.find_by_name(details[:organisation_type])
- organisation.region_id = Region.find_by_name(details[:region]).id
- organisation.language_id = Language.find_by_name(details[:language]).id
- organisation.save!
- end
- end
-
-roles = {
- 'admin' => {
- name: "admin" #depricated
- },
- 'org_admin' => {
- name: "org_admin" #depricated
- },
- 'user' => {
- name: "user" #depricated
- },
- 'add_organisations' => {
- name: 'add_organisations'
- },
- 'change_org_affiliation' => {
- name: 'change_org_affiliation'
- },
- 'grant_permissions' => {
- name: 'grant_permissions'
- },
- 'modify_templates' => {
- name: 'modify_templates'
- },
- 'modify_guidance' => {
- name: 'modify_guidance'
- },
- 'use_api' => {
- name: 'use_api'
- },
- 'change_org_details' => {
- name: 'change_org_details'
- },
- 'grant_api_to_orgs' => {
- name: 'grant_api_to_orgs'
- }
-}
-
-roles.each do |role, details|
- if Role.where(name: details[:name]).empty?
- role = Role.new
- role.name = details[:name]
- role.save!
- end
-end
-
-users = {
- 'Super admin' => {
- email: "super_admin@example.com",
- password: "password123",
- firstname: "RCC Super",
- surname: "Admin",
- password_confirmation: "password123",
- organisation: "RCC",
- language: 'English(UK)',
- roles: ['admin','org_admin','add_organisations','change_org_affiliation','grant_permissions','modify_templates','modify_guidance','use_api','change_org_details','grant_api_to_orgs'],
- accept_terms: true,
- confirmed_at: Time.zone.now
- },
- 'Funder admin' => {
- email: "funder_admin@example.com",
- password: "password123",
- password_confirmation: "password123",
- firstname: "Funder",
- surname: "Admin",
- organisation: "RegSciFed",
- language: 'English(UK)',
- roles: ['org_admin','grant_permissions','modify_templates','modify_guidance','change_org_details'],
- accept_terms: true,
- confirmed_at: Time.zone.now
- },
- 'Organizational admin' => {
- email: "org_admin@example.com",
- password: "password123",
- password_confirmation: "password123",
- firstname: "Organization",
- surname: "Admin",
- organisation: "CapColl",
- language: 'English(UK)',
- roles: ['org_admin','grant_permissions','modify_templates','modify_guidance','change_org_details'],
- accept_terms: true,
- confirmed_at: Time.zone.now
- },
- 'Organizational user' => {
- email: "org_user@example.com",
- password: "password123",
- password_confirmation: "password123",
- firstname: "Jane",
- surname: "Researcher",
- organisation: "CapColl",
- language: 'English(UK)',
- roles: ['user'],
- accept_terms: true,
- confirmed_at: Time.zone.now
- },
- 'Organizational user' => {
- email: "org_user@example.com",
- password: "password123",
- password_confirmation: "password123",
- firstname: "Jane",
- surname: "Researcher",
- organisation: "CapColl",
- language: 'English(UK)',
- roles: ['user'],
- accept_terms: true,
- confirmed_at: Time.zone.now
- }
- }
-
-users.each do |user, details|
- if User.where(email: details[:email]).empty?
- usr = User.new
- else
- usr = User.where(email: details[:email])
- end
- usr.email = details[:email]
- usr.password = details[:password]
- usr.password_confirmation = details[:password_confirmation]
- usr.confirmed_at = details[:confirmed_at]
- usr.organisation_id = Org.find_by_abbreviation(details[:organisation]).id
- usr.language_id = Language.find_by_name(details[:language]).id
- details[:roles].each do |role|
- usr.roles << Role.find_by_name(role)
+ })
end
- usr.accept_terms = details[:accept_terms]
- usr.save!
-end
-
- themes = {
- "Theme 1" => {
- title: "Theme 1",
- locale: "en"
- },
- "Theme 2" => {
- title: "Theme 2",
- locale: "en"
- },
- "Theme 3" => {
- title: "Theme 3",
- locale: "en",
- description: "Theme 3 description."
- },
- "Theme 4" => {
- title: "Theme 4",
- locale: "en",
- description: "Theme 4 description."
- }
- }
-
- themes.each do |t, details|
- if Theme.where(title: details[:title]).empty?
- theme = Theme.new
- theme.title = details[:title]
- theme.locale = details[:locale]
- theme.description = details[:description]
- theme.save!
- end
- end
-
- question_formats = {
- "Text area" => {
- title: "Text area"
- },
- "Text field" => {
- title: "Text field"
- },
- "Radio buttons" => {
- title: "Radio buttons"
- },
- "Check box" => {
- title: "Check box"
- },
- "Dropdown" => {
- title: "Dropdown"
- },
- "Multi select box" => {
- title: "Multi select box"
- },
- }
-
- question_formats.each do |qf, details|
- if QuestionFormat.where(title: details[:title]).empty?
- question_format = QuestionFormat.new
- question_format.title = details[:title]
- question_format.save!
- end
- end
-
- guidance_groups = {
- "RCC Guidance" => {
- name: "My organization guidance (optional generic guidance you provide for users)",
- organisation: "RCC",
- optional_subset: true
- },
- "Global Research Center Guidance" => {
- name: "Global Research Center (Funder specific guidance)",
- organisation: "EGRC",
- optional_subset: false
- },
- "Regional Science Federation Guidance" => {
- name: "Regional Science Federation (Funder specific guidance)",
- organisation: "RegSciFed",
- optional_subset: false
- },
- "Institutional Guidance" => {
- name: "CapColl - School of Math and Science (optional institutional guidance)",
- organisation: "CapColl",
- optional_subset: true
- }
- }
-
- guidance_groups.each do |gg, details|
- if GuidanceGroup.where(name: details[:name]).empty?
- guidance_group = GuidanceGroup.new
- guidance_group.name = details[:name]
- guidance_group.organisation = Org.find_by_abbreviation(details[:organisation])
- guidance_group.optional_subset = details[:optional_subset]
- guidance_group.save!
- end
- end
-
- guidances = {
- "Guidance 1" => {
- text: "Guidance text",
- guidance_group: "My organization guidance (optional generic guidance you provide for users)",
- themes: ["Theme 4"]
- },
- "Guidance 2" => {
- text: "Guidance text",
- guidance_group: "Global Research Center (Funder specific guidance)",
- themes: ["Theme 2"]
- },
- "Guidance 3" => {
- text: "Guidance text",
- guidance_group: "Global Research Center (Funder specific guidance)",
- themes: ["Theme 3"]
- },
- "Guidance 4" => {
- text: "Guidance text",
- guidance_group: "Regional Science Federation (Funder specific guidance)",
- themes: ["Theme 1"]
- },
- "Guidance 4" => {
- text: "Guidance text",
- guidance_group: "CapColl - School of Math and Science (optional institutional guidance)",
- themes: ["Theme 1"]
- }
- }
-
- guidances.each do |g, details|
- if Guidance.where(text: details[:text]).empty?
- guidance = Guidance.new
- guidance.text = details[:text]
- guidance.guidance_groups << GuidanceGroup.find_by_name(details[:guidance_group])
- details[:themes].each do |theme|
- guidance.themes << Theme.find_by_title(theme)
- end
- guidance.save!
- end
- end
-
- templates = {
- "RCC" => {
- title: "Regional Curation Center Template",
- description: "The default RCC template",
- published: true,
- organisation: "RCC",
- locale: "en",
- is_default: true
- },
- "Global Research Center" => {
- title: "Global Research Center Award",
- description: "Funder template description",
- published: true,
- organisation: "EGRC",
- locale: "en",
- is_default: false
- },
- "Regional Science Federation" => {
- title: "Regional Science Federation Grant - Summary",
- description: "Funder template description for phase 1",
- published: true,
- organisation: "RegSciFed",
- locale: "en",
- is_default: false
- },
- "Regional Science Federation2" => {
- title: "Regional Science Federation Grant - Finalized",
- description: "Funder template description for phase 2",
- published: true,
- organisation: "RegSciFed",
- locale: "en",
- is_default: false
- }
- }
-
- templates.each do |t, details|
- org = Org.where(abbreviation: details[:organisation]).first
-
- if Dmptemplate.where(organisation: org).where(title: details[:title]).empty?
- template = Dmptemplate.new
- template.title = details[:title]
- template.description = details[:description]
- template.published = details[:published]
- template.locale = details[:locale]
- template.is_default = details[:is_default]
- template.organisation = org
- template.save!
- end
- end
-
- phases = {
- "RCC" => {
- title: "Regional CurationCenter Data Management Plan",
- number: 1,
- template: "Regional Curation Center Template"
- },
- "EGRC Template" => {
- title: "Global Research Center Annual Award",
- number: 1,
- template: "Global Research Center Award"
- },
- "RegSciFed Template" => {
- title: "Regional Science Federation - Preliminary",
- number: 1,
- template: "Regional Science Federation Grant - Summary"
- },
- "RegSciFed Template2" => {
- title: "Regional Science Federation - Final",
- number: 1,
- template: "Regional Science Federation Grant - Finalized"
- }
- }
-
- phases.each do |p, details|
- if Phase.where(title: details[:title]).empty?
- phase = Phase.new
- phase.title = details[:title]
- phase.number = details[:number]
- phase.dmptemplate = Dmptemplate.find_by_title(details[:template])
- phase.save!
- end
- end
-
- versions = {
- "RCC" => {
- title: "Default Template v1",
- number: 1,
- phase: "Regional CurationCenter Data Management Plan"
- },
- "EGRC" => {
- title: "Annual Award v1",
- number: 1,
- phase: "Global Research Center Annual Award"
- },
- "RegSciFed_1" => {
- title: "Grant Summary v1",
- number: 1,
- phase: "Regional Science Federation - Preliminary"
- },
- "RegSciFed_2" => {
- title: "Grant Finalized Award v1",
- number: 1,
- phase: "Regional Science Federation - Final"
- },
- "RegSciFed_2.1" => {
- title: "Grant Finalized v2",
- number: 1,
- phase: "Regional Science Federation - Final"
- },
- }
-
- versions.each do |v, details|
- if Version.where(title: details[:title]).empty?
- version = Version.new
- version.title = details[:title]
- version.number = details[:number]
- version.phase = Phase.find_by_title(details[:phase])
- version.save!
- end
- end
-
- sections = {
- "Section 1" => {
- title: "Data Collection",
- number: 1,
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
- version: "Default Template v1",
- organisation: "RCC"
- },
- "Section 2" => {
- title: "Documentation and Metadata",
- number: 2,
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
- version: "Default Template v1",
- organisation: "RCC"
- },
- "Section A" => {
- title: "Data Overview",
- number: 1,
- version: "Annual Award v1",
- organisation: "EGRC"
- },
- "Section B" => {
- title: "Ethics and Legal Compliance",
- number: 2,
- version: "Annual Award v1",
- organisation: "EGRC"
- },
- "Section C" => {
- title: "Storage and Backup",
- number: 3,
- version: "Annual Award v1",
- organisation: "EGRC"
- },
- "Section D" => {
- title: "Preservation, Sustainability and Use",
- number: 4,
- version: "Annual Award v1",
- organisation: "EGRC"
- },
- "regSciFed Summary" => {
- title: "Data Collection Guidelines",
- number: 1,
- description: "This is what we plan on collecting and how we're going to store it.",
- version: "Grant Summary v1",
- organisation: "RegSciFed"
- },
- "RegSciFed Final 1" => {
- title: "Data Collection and Storage",
- number: 1,
- version: "Grant Finalized Award v1",
- organisation: "RegSciFed"
- },
- "RegSciFed Final 1_2" => {
- title: "Data Preservation",
- number: 2,
- version: "Grant Finalized v2",
- organisation: "RegSciFed"
- },
- "RegSciFed Final 2_2" => {
- title: "Ongoing Access",
- number: 3,
- version: "Grant Finalized v2",
- organisation: "RegSciFed"
- }
- }
-
- sections.each do |s, details|
- if Section.where(title: details[:title]).empty?
- section = Section.new
- section.title = details[:title]
- section.number = details[:number]
- section.description = details[:description]
- section.version = Version.find_by_title(details[:version])
- section.organisation = Org.find_by_abbreviation(details[:organisation])
- section.save!
- end
- end
-
- questions = {
- "What data will you collect or create?" => {
- text: "What data will you collect or create?",
- section: "Data Collection",
- number: 1,
- guidance: "
Questions to consider:
What type, format and volume of data?
Do your chosen formats and software enable sharing and long-term access to the data?
Are there any existing data that you can reuse?
Guidance:
Give a brief description of the data, including any existing data or third-party sources that will be used, in each case noting its content, type and coverage. Outline and justify your choice of format and consider the implications of data format and data volumes in terms of storage, backup and access.
",
- themes: ["Theme 2"]
- },
- "How will the data be collected or created?" => {
- text: "How will the data be collected or created?",
- section: "Data Collection",
- number: 2,
- guidance: "
Questions to consider:
What standards or methodologies will you use?
How will you structure and name your folders and files?
How will you handle versioning?
What quality assurance processes will you adopt?
Guidance:
Outline how the data will be collected/created and which community data standards (if any) will be used. Consider how the data will be organised during the project, mentioning for example naming conventions, version control and folder structures. Explain how the consistency and quality of data collection will be controlled and documented. This may include processes such as calibration, repeat samples or measurements, standardised data capture or recording, data entry validation, peer review of data or representation with controlled vocabularies.
",
- themes: ["Theme 3"]
- },
- "What documentation and metadata will accompany the data?" => {
- text: "What documentation and metadata will accompany the data?",
- section: "Documentation and Metadata",
- number: 1,
- guidance: "
Questions to consider:
What information is needed for the data to be to be read and interpreted in the future?
How will you capture / create this documentation and metadata?
What metadata standards will you use and why?
Guidance:
Describe the types of documentation that will accompany the data to help secondary users to understand and reuse it. This should at least include basic details that will help people to find the data, including who created or contributed to the data, its title, date of creation and under what conditions it can be accessed.
Documentation may also include details on the methodology used, analytical and procedural information, definitions of variables, vocabularies, units of measurement, any assumptions made, and the format and file type of the data. Consider how you will capture this information and where it will be recorded. Wherever possible you should identify and use existing community standards.
Will you need special software/tools to access the data?
How do you plan to store your data?
",
- themes: ["Theme 4"]
- },
- "How will you manage any ethical issues?" => {
- text: "How will you manage any ethical issues?",
- section: "Ethics and Legal Compliance",
- number: 1,
- guidance: "
Questions to consider:
Have you gained consent for data preservation and sharing?
How will you protect the identity of participants if required? e.g. via anonymisation
How will sensitive data be handled to ensure it is stored and transferred securely?
Guidance:
Ethical issues affect how you store data, who can see/use it and how long it is kept. Managing ethical concerns may include: anonymisation of data; referral to departmental or institutional ethics committees; and formal consent agreements. You should show that you are aware of any issues and have planned accordingly. If you are carrying out research involving human participants, you must also ensure that consent is requested to allow data to be shared and reused.
",
- themes: ["Theme 4"]
- },
- "How will you manage copyright and Intellectual Property Rights (IPR) issues?" => {
- text: "How will you manage copyright and Intellectual Property Rights (IPR) issues?",
- section: "Ethics and Legal Compliance",
- number: 2,
- guidance: "
Questions to consider:
Who owns the data?
How will the data be licensed for reuse?
Are there any restrictions on the reuse of third-party data?
Will data sharing be postponed / restricted e.g. to publish or seek patents?
Guidance:
State who will own the copyright and IPR of any data that you will collect or create, along with the licence(s) for its use and reuse. For multi-partner projects, IPR ownership may be worth covering in a consortium agreement. Consider any relevant funder, institutional, departmental or group policies on copyright or IPR. Also consider permissions to reuse third-party data and any restrictions needed on data sharing.
",
- themes: ["Theme 1"]
- },
- "How will the data be stored and backed up during the research?" => {
- text: "How will the data be stored and backed up during the research?",
- section: "Storage and Backup",
- number: 1,
- guidance: "
Questions to consider:
Do you have sufficient storage or will you need to include charges for additional services?
How will the data be backed up?
Who will be responsible for backup and recovery?
How will the data be recovered in the event of an incident?
Guidance:
State how often the data will be backed up and to which locations. How many copies are being made? Storing data on laptops, computer hard drives or external storage devices alone is very risky. The use of robust, managed storage provided by university IT teams is preferable. Similarly, it is normally better to use automatic backup services provided by IT Services than rely on manual processes. If you choose to use a third-party service, you should ensure that this does not conflict with any funder, institutional, departmental or group policies, for example in terms of the legal jurisdiction in which data are held or the protection of sensitive data.
Preservation of digital outputs is necessary in order for them to endure changes in the technological environment and remain potentially re-usable in the future. In this section you must state what, if any, digital outputs of your project you intend to preserve beyond the period of funding.
The length and cost of preservation should be proportionate to the value and significance of the digital outputs. If you believe that none of these should be preserved this must be justified, and if the case is a good one the application will not be prejudiced.
You must consider preservation in four ways: what, where, how and for how long. You must also consider any institutional support needed in order to carry out these plans, whether from an individual, facility, organisation or service.
You should think about the possibilities for re-use of your data in other contexts and by other users, and connect this as appropriate with your plans for dissemination and Pathways to Impact.Where there is potential for re-usability, you should use standards and formats that facilitate this.
The Technical Reviewer will be looking for evidence that you understand the reasons for the choice of technical standards and formats described in Section 2.a Technical Methodology: Standards and Formats.
You should describe the types of documentation which will accompany the data. Documentation in this sense means technical documentation as well as user documentation. It includes, for instance, technical description, code commenting, project-build guidelines, the documentation of technical decisions and resource metadata which is additional to the standards which you have described in Section 2.a. Not all types of documentation will be relevant to a project and the quantity of documentation proposed should be proportionate to the envisaged value of the data.
",
- themes: ["Theme 2", "Theme 3", "Theme 4"]
- },
- "4b: Ensuring Continued Accessibility and Use of Your Digital Outputs" => {
- text: "4b: Ensuring Continued Accessibility and Use of Your Digital Outputs",
- section: "Preservation, Sustainability and Use",
- number: 2,
- guidance: "
In this section you must provide information about any plans for ensuring that digital outputs remain sustainable in the sense of immediately accessible and usable beyond the period of funding. There are costs to ensuring sustainability in this sense over and above the costs of preservation. The project's sustainability plan should therefore be proportionate to the envisaged longer-term value of the data for the research community and should be closely related to your plans for dissemination and Pathways to Impact.
If you believe that digital outputs should not be sustained beyond the period of funding then this should be justified. It is not mandatory to sustain all digital outputs. While you should consider the long-term value of the digital outputs to the research community, where they are purely ancillary to a project’s research outputs there may not be a case for sustaining them (though there would usually be a case for preservation).
You must consider the sustainability of your digital outputs in five ways: what, where, how, for how long, and how the cost will be covered. You must make appropriate provision for user consultation and user testing in this connection, and plan the development of suitable user documentation.
You should provide justification if you do not envisage open, public access. A case can be made for charging for or otherwise limiting access, but the default expectation is that access will be open. The Technical Reviewer will be looking for realistic commitments to sustaining public access in line with affordability and the longer-term value of the digital output.
You must consider any institutional support needed in order to carry out these plans, if not covered under Section 3, as well as the cost of keeping the digital output publicly available in the future, including issues relating to maintenance, infrastructure and upgrade (such as the need to modify aspects of a web interface or software application in order to account for changes in the technological environment). In order to minimise sustainability costs, it is generally useful that the expertise involved in the development of your project is supported by expertise in your own or a partner institution.
A sustainability plan does not necessarily mean a requirement to generate income or prevent resources from being freely available. Rather it is a requirement to consider the direct costs and expertise of maintaining digital outputs for continued access. Some applicants might be able to demonstrate that there will be no significant sustainability problems with their digital output; in some cases the university’s computing services or library might provide a firm commitment to sustaining the resource for a specified period; others might see the benefit of Open Source community development models. You should provide reassurances of sustainability which are proportionate to the envisaged longer-term value of the digital outputs for the research community.
When completing this section, you should consider the potential impact of the data on research in your field (if research in the discipline will be improved through the creation of the digital output, how will it be affected if the resource then disappears?), and make the necessary connections with your Impact Plan. You must factor in the effects of any IP, copyright and ethical issues during the period in which the digital output will be publicly accessible, connecting what you say with the relevant part of your Case for Support.
You must identify whether or not you envisage the academic content (as distinct from the technology) of the digital output being extended or updated beyond the period of funding, addressing the following issues: how this will be done, by who and at what cost. You will need to show how the cost of this will be sustained after the period of funding ends.
",
- themes: ["Theme 2"]
- }
- }
-
- questions.each do |q, details|
- if Question.where(text: details[:text]).empty?
- question = Question.new
- question.text = details[:text]
- question.number = details[:number]
- question.guidance = details[:guidance]
- question.section = Section.find_by_title(details[:section])
- details[:themes].each do |theme|
- question.themes << Theme.find_by_title(theme)
- end
- question.save!
- end
- end
-
-formatting = {
- 'Funder' => {
- font_face: "Arial, Helvetica, Sans-Serif",
- font_size: 11,
- margin: { top: 20, bottom: 20, left: 20, right: 20 }
- },
- 'DCC' => {
- font_face: "Arial, Helvetica, Sans-Serif",
- font_size: 12,
- margin: { top: 20, bottom: 20, left: 20, right: 20 }
- }
-}
-
-formatting.each do |org, settings|
- #template = Dmptemplate.find_by_title("#{org} Template") # this is bugged, there is no Funder Template nor DCC template
- #template.settings(:export).formatting = settings
- #template.save!
-end
-
-token_permission_types = {
- 'guidances' => {
- description: "allows a user access to the guidances api endpoint"
- },
- 'plans' => {
- description: "allows a user access to the plans api endpoint"
- },
- 'templates' => {
- description: "allows a user access to the templates api endpoint"
- },
- 'statistics' => {
- description: "allows a user access to the statistics api endpoint"
- }
-}
-
-token_permission_types.each do |title,settings|
- if TokenPermissionType.where(token_type: title).empty?
- token_permission_type = TokenPermissionType.new
- token_permission_type.token_type = title
- token_permission_type.text_description = settings[:description]
- token_permission_type.save!
end
end
+
+# Regions (create the super regions first and then create the rest)
+# -------------------------------------------------------
+regions = [
+ {abbreviation: 'horizon',
+ description: 'European super region',
+ name: 'Horizon2020',
+
+ sub_regions: [
+ {abbreviation: 'uk',
+ description: 'United Kingdom',
+ name: 'UK'},
+ {abbreviation: 'de',
+ description: 'Germany',
+ name: 'DE'},
+ {abbreviation: 'fr',
+ description: 'France',
+ name: 'FR'},
+ {abbreviation: 'es',
+ description: 'Spain',
+ name: 'ES'}
+ ]},
+ {abbreviation: 'us',
+ description: 'United States of America',
+ name: 'US'}
+]
+
+# Create the region. If it has subregions create them and then connect them
+regions.each do |r|
+ srs = r[:sub_regions]
+ r.delete(:sub_regions) unless r[:sub_regions].nil?
+
+ if Region.find_by(abbreviation: r[:abbreviation]).nil?
+ region = Region.create!(r)
+
+ unless srs.nil?
+ srs.each do |sr|
+ if Region.find_by(abbreviation: sr[:abbreviation]).nil?
+ sr[:super_region] = region
+ Region.create!((sr))
+ end
+ end
+ end
+
+ end
+end
+
+# Perms
+# -------------------------------------------------------
+perms = [
+ {name: 'add_organisations'},
+ {name: 'change_org_affiliation'},
+ {name: 'grant_permissions'},
+ {name: 'modify_templates'},
+ {name: 'modify_guidance'},
+ {name: 'use_api'},
+ {name: 'change_org_details'},
+ {name: 'grant_api_to_orgs'}
+]
+
+perms.map{ |p| Perm.create!(p) if Perm.find_by(name: p[:name]).nil? }
+
+# Guidance Themes
+# -------------------------------------------------------
+themes = [
+ {title: 'Data Description'},
+ {title: 'Data Format'},
+ {title: 'Data Volume'},
+ {title: 'Data Collection'},
+ {title: 'Metadata & Documentation'},
+ {title: 'Ethics & Privacy'},
+ {title: 'Intellectual Property Rights'},
+ {title: 'Storage & Security'},
+ {title: 'Data Sharing'},
+ {title: 'Data Repository'},
+ {title: 'Preservation'},
+ {title: 'Roles & Responsibilities'},
+ {title: 'Budget'},
+ {title: 'Related Policies'}
+]
+themes.map{ |t| Theme.create!(t) if Theme.find_by(title: t[:title]).nil? }
+
+# Token Permission Types
+# -------------------------------------------------------
+token_permission_types = [
+ {token_type: 'guidances', text_description: 'allows a user access to the guidances api endpoint'},
+ {token_type: 'plans', text_description: 'allows a user access to the plans api endpoint'}
+]
+token_permission_types.map{ |tpt| TokenPermissionType.create!(tpt) if TokenPermissionType.find_by(token_type: tpt[:token_type]).nil? }
+
+# Create our generic organisation, a funder and a University
+# -------------------------------------------------------
+orgs = [
+ {name: GlobalHelpers.constant("organisation_types.managing_organisation"),
+ abbreviation: 'CC',
+ banner_text: 'This is an example organisation',
+ org_type: 3,
+ language_id: Language.find_by(abbreviation: I18n.locale).id,
+ token_permission_types: TokenPermissionType.all},
+ {name: 'Government Agency',
+ abbreviation: 'GA',
+ org_type: 2,
+ language: Language.find_by(abbreviation: 'en-UK')},
+ {name: 'University of Exampleland',
+ abbreviation: 'UOS',
+ org_type: 1,
+ language: Language.find_by(abbreviation: 'en-UK')}
+]
+orgs.map{ |o| Org.create!(o) if Org.find_by(abbreviation: o[:abbreviation]).nil? }
+
+# Create a Super Admin associated with our generic organisation,
+# an Org Admin for our funder and an Org Admin and User for our University
+# -------------------------------------------------------
+users = [
+ {email: "super_admin@example.com",
+ firstname: "Super",
+ surname: "Admin",
+ password: "password123",
+ password_confirmation: "password123",
+ org: Org.find_by(abbreviation: 'CC'),
+ language: Language.find_by(abbreviation: I18n.locale),
+ perms: Perm.all,
+ accept_terms: true,
+ confirmed_at: Time.zone.now},
+ {email: "funder_admin@example.com",
+ firstname: "Funder",
+ surname: "Admin",
+ password: "password123",
+ password_confirmation: "password123",
+ org: Org.find_by(abbreviation: 'GA'),
+ language: Language.find_by(abbreviation: I18n.locale),
+ perms: Perm.where.not(name: ['admin', 'add_organisations', 'change_org_affiliation']),
+ accept_terms: true,
+ confirmed_at: Time.zone.now},
+ {email: "org_admin@example.com",
+ firstname: "Organisational",
+ surname: "Admin",
+ password: "password123",
+ password_confirmation: "password123",
+ org: Org.find_by(abbreviation: 'UOS'),
+ language: Language.find_by(abbreviation: I18n.locale),
+ perms: Perm.where.not(name: ['admin', 'add_organisations', 'change_org_affiliation']),
+ accept_terms: true,
+ confirmed_at: Time.zone.now},
+ {email: "org_user@example.com",
+ firstname: "Organisational",
+ surname: "User",
+ password: "password123",
+ password_confirmation: "password123",
+ org: Org.find_by(abbreviation: 'UOS'),
+ language: Language.find_by(abbreviation: I18n.locale),
+ accept_terms: true,
+ confirmed_at: Time.zone.now}
+]
+users.map{ |u| User.create!(u) if User.find_by(email: u[:email]).nil? }
+
+# Create a Guidance Group for our organisation and the funder
+# -------------------------------------------------------
+guidance_groups = [
+ {name: "Generic Guidance (provided by the example curation centre)",
+ org: Org.find_by(abbreviation: 'CC'),
+ optional_subset: true,
+ published: true},
+ {name: "Government Agency Advice (Funder specific guidance)",
+ org: Org.find_by(abbreviation: 'GA'),
+ optional_subset: false,
+ published: true}
+]
+guidance_groups.map{ |gg| GuidanceGroup.create!(gg) if GuidanceGroup.find_by(name: gg[:name]).nil? }
+
+# Initialize with the generic Roadmap guidance and a sample funder guidance
+# -------------------------------------------------------
+guidances = [
+ {text: "● Give a summary of the data you will collect or create, noting the content, coverage and data type, e.g., tabular data, survey data, experimental measurements, models, software, audiovisual data, physical samples, etc.
+● Consider how your data could complement and integrate with existing data, or whether there are any existing data or methods that you could reuse.
+● If purchasing or reusing existing data, explain how issues such as copyright and IPR have been addressed. You should aim to m
+inimise any restrictions on the reuse (and subsequent sharing) of third-party data.",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Data Description')]},
+ {text: "● Clearly note what format(s) your data will be in, e.g., plain text (.txt), comma-separated values (.csv), geo-referenced TIFF (.tif, .tfw).
+● Explain why you have chosen certain formats. Decisions may be based on staff expertise, a preference for open formats, the standards accepted by data centres or widespread usage within a given community.
+● Using standardised, interchangeable or open formats ensures the long-term usability of data; these are recommended for sharing and archiving.
+● See UK Data Service guidance on recommended formats or DataONE Best Practices for file formats",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Data Format')]},
+ {text: "● Note what volume of data you will create in MB/GB/TB
+● Consider the implications of data volumes in terms of storage, access and preservation. Do you need to include additional costs?
+● Consider whether the scale of the data will pose challenges when sharing or transferring data between sites; if so, how will you address these challenges?",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Data Volume')]},
+ {text: "● Outline how the data will be collected and processed. This should cover relevant standards or methods, quality assurance and data organisation.
+● Indicate how the data will be organised during the project, mentioning, e.g., naming conventions, version control and folder structures. Consistent, well-ordered research data will be easier to find, understand and reuse
+● Explain how the consistency and quality of data collection will be controlled and documented. This may include processes such as calibration, repeat samples or measurements, standardised data capture, data entry validation, peer review of data or representation with controlled vocabularies.
+● See the DataOne Best Practices for data quality",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Data Collection')]},
+ {text: "● What metadata will be provided to help others identify and discover the data?
+● Researchers are strongly encouraged to use community metadata standards where these are in place. The Research Data Alliance offers a Directory of Metadata Standards.
+● Consider what other documentation is needed to enable reuse. This may include information on the methodology used to collect the data, analytical and procedural information, definitions of variables, units of measurement, any assumptions made, the format and file type of the data and software used to collect and/or process the data.
+● Consider how you will capture this information and where it will be recorded, e.g., in a database with links to each item, in a ‘readme’ text file, in file headers, etc. ",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Metadata & Documentation')]},
+ {text: "● Investigators carrying out research involving human participants should request consent to preserve and share the data. Do not just ask for permission to use the data in your study or make unnecessary promises to delete it at the end.
+● Consider how you will protect the identity of participants, e.g., via anonymisation or using managed access procedures.
+● Ethical issues may affect how you store and transfer data, who can see/use it and how long it is kept. You should demonstrate that you are aware of this and have planned accordingly.
+● See UK Data Service guidance on consent for data sharing
+● See ICPSR approach to confidentiality and Health Insurance Portability and Accountability Act (HIPAA) regulations for health research",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Ethics & Privacy')]},
+ {text: "● State who will own the copyright and IPR of any new data that you will generate. For multi-partner projects, IPR ownership should be covered in the consortium agreement.
+● Outline any restrictions needed on data sharing, e.g., to protect proprietary or patentable data.
+● Explain how the data will be licensed for reuse. See the DCC guide on How to license research data and EUDAT’s data and software licensing wizard.",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Intellectual Property Rights')]},
+ {text: "● Describe where the data will be stored and backed up during the course of research activities. This may vary if you are doing fieldwork or working across multiple sites so explain each procedure.
+● Identify who will be responsible for backup and how often this will be performed. The use of robust, managed storage with automatic backup, for example, that provided by university IT teams, is preferable. Storing data on laptops, computer hard drives or external storage devices alone is very risky.
+● See UK Data Service Guidance on data storage or DataONE Best Practices for storage
+● Also consider data security, particularly if your data is sensitive e.g., detailed personal data, politically sensitive information or trade secrets. Note the main risks and how these will be managed.
+● Identify any formal standards that you will comply with, e.g., ISO 27001. See the DCC Briefing Paper on Information Security Management -ISO 27000 and UK Data Service guidance on data security",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Storage & Security')]},
+ {text: "● How will you share the data e.g. deposit in a data repository, use a secure data service, handle data requests directly or use another mechanism? The methods used will depend on a number of factors such as the type, size, complexity and sensitivity of the data.
+● When will you make the data available? Research funders expect timely release. They typically allow embargoes but not prolonged exclusive use.
+● Who will be able to use your data? If you need to restricted access to certain communities or apply data sharing agreements, explain why.
+● Consider strategies to minimise restrictions on sharing. These may include anonymising or aggregating data, gaining participant consent for data sharing, gaining copyright permissions, and agreeing a limited embargo period.
+● How might your data be reused in other contexts? Where there is potential for reuse, you should use standards and formats that facilitate this, and ensure that appropriate metadata is available online so your data can be discovered. Persistent identifiers should be applied so people can reliably and efficiently find your data. They also help you to track citations and reuse.",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Data Sharing')]},
+ {text: "● Where will the data be deposited? If you do not propose to use an established repository, the data management plan should demonstrate that the data can be curated effectively beyond the lifetime of the grant.
+● It helps to show that you have consulted with the repository to understand their policies and procedures, including any metadata standards.
+● An international list of data repositories is available via Re3data and some universities or publishers provide lists of recommendations e.g. PLOS ONE recommended repositories",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Data Repository')]},
+ {text: "● Indicate which data are of long-term value and should be shared and/or preserved.
+● Outline the plans for data sharing and preservation - how long will the data be retained and where will it be archived?
+● Will additional resources be needed to prepare data for deposit or meet any charges from data repositories? See the DCC guide: How to appraise and select research data for curation or DataONE Best Practices: Identifying data with long-term value",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Preservation')]},
+ {text: "● Outline the roles and responsibilities for all activities, e.g., data capture, metadata production, data quality, storage and backup, data archiving & data sharing. Individuals should be named where possible.
+● For collaborative projects you should explain the coordination of data management responsibilities across partners.
+● See UK Data Service guidance on data management roles and responsibilities or DataONE Best Practices: Define roles and assign responsibilities for data management",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Roles & Responsibilities')]},
+ {text: "● Carefully consider and justify any resources needed to deliver the plan. These may include storage costs, hardware, staff time, costs of preparing data for deposit and repository charges.
+● Outline any relevant technical expertise, support and training that is likely to be required and how it will be acquired.
+● If you are not depositing in a data repository, ensure you have appropriate resources and systems in place to share and preserve the data. See UK Data Service guidance on costing data management",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Budget')]},
+ {text: "● Consider whether there are any existing procedures that you can base your approach on. If your group/department has local guidelines that you work to, point to them here.
+● List any other relevant funder, institutional, departmental or group policies on data management, data sharing and data security. ",
+ guidance_group: GuidanceGroup.first,
+ published: true,
+ themes: [Theme.find_by(title: 'Related Policies')]},
+ {text: "Please tell us how much data you plan to collect and what format it will be in once its deposited.",
+ guidance_group: GuidanceGroup.last,
+ published: true,
+ themes: [Theme.find_by(title: 'Data Description')]}
+]
+guidances.map{ |g| Guidance.create!(g) if Guidance.find_by(text: g[:text]).nil? }
+
+# Create a default template for the curation centre and one for the example funder
+# -------------------------------------------------------
+templates = [
+ {title: "My Curation Center's Default Template",
+ description: "The default template",
+ published: true,
+ org: Org.find_by(abbreviation: 'CC'),
+ is_default: true,
+ version: 1},
+
+ {title: "OLD - Department of Testing Award",
+ published: false,
+ org: Org.find_by(abbreviation: 'GA'),
+ is_default: false,
+ version: 1},
+
+ {title: "Department of Testing Award",
+ published: true,
+ org: Org.find_by(abbreviation: 'GA'),
+ is_default: false,
+ version: 2}
+]
+templates.map{ |t| Template.create!(t) if Template.find_by(title: t[:title]).nil? }
+
+# Create 2 phases for the funder's template and one for our generic template
+# -------------------------------------------------------
+phases = [
+ {title: "Generic Data Management Planning Template",
+ number: 1,
+ modifiable: false,
+ template: Template.find_by(title: "My Curation Center's Default Template")},
+
+ {title: "Detailed Overview",
+ number: 1,
+ modifiable: false,
+ template: Template.find_by(title: "OLD - Department of Testing Award")},
+
+ {title: "Preliminary Statement of Work",
+ number: 1,
+ modifiable: true,
+ template: Template.find_by(title: "Department of Testing Award")},
+ {title: "Detailed Overview",
+ number: 2,
+ modifiable: false,
+ template: Template.find_by(title: "Department of Testing Award")}
+]
+phases.map{ |p| Phase.create!(p) if Phase.find_by(title: p[:title]).nil? }
+
+generic_template_phase_1 = Phase.find_by(title: "Generic Data Management Planning Template")
+funder_template_phase_1 = Phase.find_by(title: "Preliminary Statement of Work")
+funder_template_phase_2 = Phase.find_by(title: "Detailed Overview")
+
+# Create sections for the 2 templates and their phases
+# -------------------------------------------------------
+sections = [
+ # Sections for the Generic Template
+ {title: "Data Collection",
+ number: 1,
+ published: true,
+ modifiable: false,
+ phase: generic_template_phase_1},
+ {title: "Documentation and Metadata",
+ number: 2,
+ published: true,
+ modifiable: false,
+ phase: generic_template_phase_1},
+ {title: "Ethics and Legal Compliance",
+ number: 3,
+ published: true,
+ modifiable: false,
+ phase: generic_template_phase_1},
+ {title: "Storage and Backup",
+ number: 4,
+ published: true,
+ modifiable: false,
+ phase: generic_template_phase_1},
+ {title: "Selection and Preservation",
+ number: 5,
+ published: true,
+ modifiable: false,
+ phase: generic_template_phase_1},
+ {title: "Data Sharing",
+ number: 6,
+ published: true,
+ modifiable: false,
+ phase: generic_template_phase_1},
+ {title: "Responsibilities and Resources",
+ number: 7,
+ published: true,
+ modifiable: false,
+ phase: generic_template_phase_1},
+
+ # Section of old version of Funder Template
+ {title: "Data Collection and Preservation",
+ number: 1,
+ published: false,
+ modifiable: true,
+ phase: Phase.find_by(title: "Detailed Overview")},
+
+ # Sections for the Funder Template's Preliminary Phase
+ {title: "Data Overview",
+ number: 1,
+ published: false,
+ modifiable: true,
+ phase: funder_template_phase_1},
+ {title: "Data Description",
+ number: 1,
+ published: false,
+ modifiable: true,
+ phase: funder_template_phase_1},
+
+ # Sections for the Funder Template's Detailed Phase
+ {title: "Preservation Policy",
+ number: 1,
+ published: true,
+ modifiable: false,
+ phase: funder_template_phase_2},
+ {title: "Data Format and Storage",
+ number: 1,
+ published: true,
+ modifiable: false,
+ phase: funder_template_phase_2},
+ {title: "Collection Process",
+ number: 1,
+ published: true,
+ modifiable: false,
+ phase: funder_template_phase_2},
+ {title: "Ethical Standards",
+ number: 1,
+ published: true,
+ modifiable: false,
+ phase: funder_template_phase_2},
+ {title: "Preservation and Reuse Policies",
+ number: 1,
+ published: true,
+ modifiable: false,
+ phase: funder_template_phase_2}
+]
+sections.map{ |s| Section.create!(s) if Section.find_by(title: s[:title]).nil? }
+
+text_area = QuestionFormat.find_by(title: "Text area")
+
+# Create questions for the 2 templates and their phases
+# -------------------------------------------------------
+questions = [
+ # Questions for the Generic Template
+ {text: "What data will you collect or create?",
+ number: 1,
+ section: Section.find_by(title: "Data Collection"),
+ question_format: text_area,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Data Description")]},
+ {text: "How will the data be collected or created?",
+ number: 2,
+ section: Section.find_by(title: "Data Collection"),
+ question_format: text_area,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Data Collection")]},
+ {text: "What documentation and metadata will accompany the data?",
+ number: 1,
+ section: Section.find_by(title: "Documentation and Metadata"),
+ question_format: text_area,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Metadata & Documentation")]},
+ {text: "How will you manage any ethical issues?",
+ number: 1,
+ section: Section.find_by(title: "Ethics and Legal Compliance"),
+ question_format: text_area,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Ethics & Privacy")]},
+ {text: "How will you manage copyright and Intellectual Property Rights (IPR) issues?",
+ number: 2,
+ section: Section.find_by(title: "Ethics and Legal Compliance"),
+ question_format: text_area,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Intellectual Property Rights")]},
+ {text: "How will the data be stored and backed up during the research?",
+ number: 1,
+ section: Section.find_by(title: "Storage and Backup"),
+ question_format: text_area,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Storage & Security")]},
+ {text: "How will you manage access and security?",
+ number: 2,
+ section: Section.find_by(title: "Storage and Backup"),
+ question_format: text_area,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Storage & Security")]},
+ {text: "Which data are of long-term value and should be retained, shared, and/or preserved?",
+ number: 1,
+ section: Section.find_by(title: "Selection and Preservation"),
+ question_format: text_area,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Preservation")]},
+ {text: "What is the long-term preservation plan for the dataset?",
+ number: 2,
+ section: Section.find_by(title: "Selection and Preservation"),
+ question_format: text_area,
+ modifiable: false},
+ {text: "How will you share the data?",
+ number: 1,
+ section: Section.find_by(title: "Data Sharing"),
+ question_format: text_area,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Data Sharing")]},
+ {text: "Are any restrictions on data sharing required?",
+ number: 2,
+ section: Section.find_by(title: "Data Sharing"),
+ question_format: text_area,
+ modifiable: false},
+ {text: "Who will be responsible for data management?",
+ number: 1,
+ section: Section.find_by(title: "Responsibilities and Resources"),
+ question_format: text_area,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Roles & Responsibilities")]},
+ {text: "What resources will you require to deliver your plan?",
+ number: 2,
+ modifiable: false,
+ section: Section.find_by(title: "Responsibilities and Resources"),
+ question_format: text_area},
+
+ # Questions for old version of Funder Template
+ {text: "What data will you collect and how will it be obtained?",
+ number: 1,
+ modifiable: false,
+ section: Section.find_by(title: "Data Collection and Preservation"),
+ question_format: text_area},
+ {text: "How will you preserve your data during the project and long-term?",
+ number: 2,
+ modifiable: false,
+ section: Section.find_by(title: "Data Collection and Preservation"),
+ question_format: text_area},
+
+ # Questions for the Funder Template's Preliminary Phase
+ {text: "Provide an overview of the dataset.",
+ number: 1,
+ section: Section.find_by(title: "Data Overview"),
+ question_format: text_area,
+ modifiable: true,
+ themes: [Theme.find_by(title: "Data Description")]},
+ {text: "What types/formats of data will you collect?",
+ number: 1,
+ modifiable: true,
+ section: Section.find_by(title: "Data Description"),
+ question_format: text_area,
+ themes: [Theme.find_by(title: "Data Format")]},
+ {text: "How will you store the data and how will it be preserved?",
+ number: 2,
+ modifiable: true,
+ section: Section.find_by(title: "Data Description"),
+ question_format: text_area,
+ themes: [Theme.find_by(title: "Data Collection")]},
+
+ # Questions for the Funder Template's Detailed Phase
+ {text: "What is your policy for long term access to your dataset?",
+ number: 1,
+ section: Section.find_by(title: "Preservation Policy"),
+ question_format: text_area,
+ modifiable: false,
+ default_value: "Please enter your answer here ..." ,
+ themes: [Theme.find_by(title: "Preservation")]},
+ {text: "Where will your data be preserved?",
+ number: 2,
+ section: Section.find_by(title: "Preservation Policy"),
+ question_format: QuestionFormat.find_by(title: "Text field"),
+ modifiable: false,
+ default_value: "on a server at my institution",
+ guidance: "Consider where your data will be stored after your research is complete.",
+ themes: [Theme.find_by(title: "Preservation")]},
+ {text: "What types of data will you collect and how will it be stored?",
+ number: 1,
+ section: Section.find_by(title: "Data Format and Storage"),
+ question_format: text_area,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Storage & Security"), Theme.find_by(title: 'Data Format')]},
+ {text: "Please select the appropriate formats.",
+ number: 2,
+ section: Section.find_by(title: "Data Format and Storage"),
+ question_format: QuestionFormat.find_by(title: "Radio buttons"),
+ modifiable: false,
+ themes: [Theme.find_by(title: "Storage & Security"), Theme.find_by(title: 'Data Format')]},
+ {text: "Will software accompany your dataset?",
+ number: 1,
+ section: Section.find_by(title: "Collection Process"),
+ question_format: QuestionFormat.find_by(title: "Check box"),
+ modifiable: false,
+ themes: [Theme.find_by(title: "Data Collection")]},
+ {text: "Where will you store your data during the research period?",
+ number: 2,
+ section: Section.find_by(title: "Collection Process"),
+ question_format: QuestionFormat.find_by(title: "Dropdown"),
+ modifiable: false,
+ themes: [Theme.find_by(title: "Data Collection")]},
+ {text: "What type(s) of data will you collect?",
+ number: 3,
+ section: Section.find_by(title: "Collection Process"),
+ question_format: QuestionFormat.find_by(title: "Multi select box"),
+ option_comment_display: true,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Data Collection")]},
+ {text: "What are your institution's ethical policies?",
+ number: 1,
+ section: Section.find_by(title: "Ethical Standards"),
+ question_format: text_area,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Ethics & Privacy")]},
+ {text: "When will your data be available for public consumption?",
+ number: 2,
+ section: Section.find_by(title: "Ethical Standards"),
+ question_format: QuestionFormat.find_by(title: "Date"),
+ modifiable: false,
+ themes: [Theme.find_by(title: "Ethics & Privacy")]},
+ {text: "Tell us about your departmental and institutional policies on reuse and preservation.",
+ number: 1,
+ section: Section.find_by(title: "Preservation and Reuse Policies"),
+ question_format: text_area,
+ modifiable: false,
+ themes: [Theme.find_by(title: "Preservation"), Theme.find_by(title: "Data Sharing")]}
+]
+questions.map{ |q| Question.create!(q) if Question.find_by(text: q[:text]).nil? }
+
+drop_down_question = Question.find_by(text: "Where will you store your data during the research period?")
+multi_select_question = Question.find_by(text: "What type(s) of data will you collect?")
+radio_button_question = Question.find_by(text: "Please select the appropriate formats.")
+
+# Create suggested answers for a few questions
+# -------------------------------------------------------
+suggested_answers = [
+ {text: "We will preserve it in Dryad or a similar data repository service.",
+ is_example: true,
+ org: Org.find_by(abbreviation: 'GA'),
+ question: Question.find_by(text: "What is your policy for long term access to your dataset?")},
+ {text: "We recommend that you identify the type(s) of content as well as the type of file(s) involved",
+ is_example: false,
+ org: Org.find_by(abbreviation: 'GA'),
+ question: Question.find_by(text: "What types of data will you collect and how will it be stored?")},
+]
+suggested_answers.map{ |s| SuggestedAnswer.create!(s) if SuggestedAnswer.find_by(text: s[:text]).nil? }
+
+# Create options for the dropdown, multi-select and radio buttons
+# -------------------------------------------------------
+question_options = [
+ {text: "csv files",
+ number: 1,
+ question: radio_button_question,
+ is_default: false},
+ {text: "database (e.g. mysql, redis)",
+ number: 2,
+ question: radio_button_question,
+ is_default: false},
+ {text: "archive files (e.g. tar, zip)",
+ number: 3,
+ question: radio_button_question,
+ is_default: false},
+
+ {text: "local hard drive",
+ number: 1,
+ question: drop_down_question,
+ is_default: true},
+ {text: "personal cloud storage",
+ number: 2,
+ question: drop_down_question,
+ is_default: false},
+ {text: "institutional servers",
+ number: 3,
+ question: drop_down_question,
+ is_default: false},
+
+ {text: "statistical",
+ number: 1,
+ question: multi_select_question,
+ is_default: false},
+ {text: "image/video",
+ number: 2,
+ question: multi_select_question,
+ is_default: false},
+ {text: "geographical",
+ number: 3,
+ question: multi_select_question,
+ is_default: false},
+ {text: "other",
+ number: 4,
+ question: multi_select_question,
+ is_default: false}
+]
+question_options.map{ |q| QuestionOption.create!(q) if QuestionOption.find_by(text: q[:text]).nil? }
+
+# Create plans
+# -------------------------------------------------------
+=begin
+plans = [
+ {title: "Sample plan",
+ template: Template.find_by(title: "Department of Testing Award"),
+ grant_number: "FUNDER-GRANT-123",
+ identifier: "987654321",
+ description: "This is a sample plan based on a funder template",
+ principal_investigator: "John Doe",
+ principal_investigator_identifier: "ORCID: 12346-000-1234",
+ data_contact: "john.doe@example.com",
+ funder_name: "Example Government Agency",
+ visibility: 0}
+]
+plans.map{ |p| Plan.create!(p) if Plan.find_by(title: "Sample plan").nil? }
+
+plan = Plan.find_by(title: "Sample plan")
+user = User.find_by(email: "org_user@example.com")
+
+answers = [
+ {text: "We will collect data from various sources and create our own analysis.",
+ plan: plan,
+ user: user,
+ question: Question.find_by(text: "Provide an overview of the dataset.")},
+ {text: "We will primarily collect images and video from our telescope and other instruments",
+ plan: plan,
+ user: user,
+ question: Question.find_by(text: "What types/formats of data will you collect?")},
+ {text: "We will store the data on our departmental server and then move it to a commercial data repository afterward.",
+ plan: plan,
+ user: user,
+ question: Question.find_by(text: "How will you store the data and how will it be preserved?")},
+
+ {text: "We want people to be able to access it. ",
+ plan: plan,
+ user: user,
+ question: Question.find_by(text: "What is your policy for long term access to your dataset?")},
+ {plan: plan,
+ user: user,
+ question: drop_down_question,
+ question_options: [QuestionOption.find_by(text: "institutional servers")]},
+ {plan: plan,
+ user: user,
+ question: multi_select_question,
+ question_options: [QuestionOption.find_by(text: "image/video"),
+ QuestionOption.find_by(text: "other")]},
+ {plan: plan,
+ user: user,
+ question: radio_button_question,
+ question_options: [QuestionOption.find_by(text: "archive files (e.g. tar, zip)"),
+ QuestionOption.find_by(text: "csv files")]},
+ {text: "Yes",
+ plan: plan,
+ user: user,
+ question: Question.find_by(text: "Will software accompany your dataset?")},
+ {text: "On a local server",
+ plan: plan,
+ user: user,
+ question: Question.find_by(text: "Where will you store your data during the research period?")},
+ {text: "2018-05-01 00:00:01",
+ plan: plan,
+ user: user,
+ question: Question.find_by(text: "When will your data be available for public consumption?")}
+]
+answers.map{ |a| Answer.create!(a) if Answer.where(plan: a[:plan], user: a[:user], question: a[:question]).empty? }
+=end
diff --git a/html/Ability.html b/html/Ability.html
deleted file mode 100644
index d808822..0000000
--- a/html/Ability.html
+++ /dev/null
@@ -1,388 +0,0 @@
-
-
-
-
-
-
-class Ability - DMPonline4 Documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
class Ability
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Public Class Methods
-
-
-
-
-
- new(user)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/ability.rb, line 4
-definitialize(user)
- # Define abilities for the passed in user here. For example:
-
- #
-
- user||=User.new# guest user (not logged in)
-
- ifuser.has_role?:admin
- can:manage, :all
- else
- can:read, :all
- end
-
- can:manage_settings, Userdo|viewed_user|
- viewed_user.present?&&user.id==viewed_user.id
- end
- #
-
- # The first argument to `can` is the action you are giving the user
-
- # permission to do.
-
- # If you pass :manage it will apply to every action. Other common actions
-
- # here are :read, :create, :update and :destroy.
-
- #
-
- # The second argument is the resource the user can perform the action on.
-
- # If you pass :all it will apply to every resource. Otherwise pass a Ruby
-
- # class of the resource.
-
- #
-
- # The third argument is an optional hash of conditions to further filter the
-
- # objects.
-
- # For example, here the user can only update published articles.
-
- #
-
- # can :update, Article, :published => true
-
- #
-
- # See the wiki for details:
-
- # https://github.com/ryanb/cancan/wiki/Defining-Abilities
-
-
-end
- after_sign_in_error_path_for(resource)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/controllers/application_controller.rb, line 32
-defafter_sign_in_error_path_for(resource)
- session[:previous_url] ||root_path
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- after_sign_in_path_for(resource)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/controllers/application_controller.rb, line 24
-defafter_sign_in_path_for(resource)
- session[:previous_url] ||root_path
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- after_sign_up_error_path_for(resource)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/controllers/application_controller.rb, line 36
-defafter_sign_up_error_path_for(resource)
- session[:previous_url] ||root_path
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- after_sign_up_path_for(resource)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/controllers/application_controller.rb, line 28
-defafter_sign_up_path_for(resource)
- session[:previous_url] ||root_path
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- authenticate_admin!()
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/controllers/application_controller.rb, line 40
-defauthenticate_admin!
- redirect_toroot_pathunlessuser_signed_in?&¤t_user.can_super_admin?
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- get_plan_list_columns()
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/controllers/application_controller.rb, line 44
-defget_plan_list_columns
- ifuser_signed_in?
- @selected_columns = current_user.settings(:plan_list).columns
- @all_columns = Settings::PlanList::ALL_COLUMNS
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- store_location()
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/controllers/application_controller.rb, line 13
-defstore_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
-
- session[:previous_url] = request.fullpath
- end
-end
This controller is responsible for all the actions in the admin interface
-under templates (e.g. phases, versions, sections, questions, suggested
-answer) (index; show; create; edit; delete)
-
Copyright:
-
-
Digital Curation Centre
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Public Instance Methods
-
-
-
-
-
- admin_addphase()
- click to toggle source
-
-
-
-
-
-
add a new phase to a template
-
-
-
-
-
# File app/controllers/dmptemplates_controller.rb, line 187
-defadmin_addphase
- ifuser_signed_in?&¤t_user.can_org_admin?then
- @dmptemplate = Dmptemplate.find(params[:id])
- @phase = Phase.new
- if@dmptemplate.phases.count==0then
- @phase.number = '1'
- else
- @phase.number = @dmptemplate.phases.count+1
- end
-
- respond_todo|format|
- format.html
- end
- end
-end
# File app/controllers/dmptemplates_controller.rb, line 124
-defadmin_phase
- ifuser_signed_in?&¤t_user.can_org_admin?then
-
- @phase = Phase.find(params[:id])
-
- if!params.has_key?(:version_id) then
- @edit = 'false'
- #check for the most recent published version, if none is available then return the most recent one
-
- versions = @phase.versions.where('published = ?', true).order('updated_at DESC')
- ifversions.any?() then
- @version = versions.first
- else
- @version = @phase.versions.order('updated_at DESC').first
- end
- # When the version_id is passed as an argument
-
- else
- @edit = params[:edit]
- @version = Version.find(params[:version_id])
- end
-
- #verify if there are any sections if not create one
-
- @sections = @version.sections
- if!@sections.any?() ||@sections.count==0then
- @section = @version.sections.build
- @section.title = ''
- @section.version_id = params[:version_id]
- @section.number = 1
- @section.organisation_id = current_user.organisation.id
- @section.published = true
- @section.save
- end
-
- #verify if section_id has been passed, if so then open that section
-
- ifparams.has_key?(:section_id) then
- @open = true
- @section_id = params[:section_id].to_i
- end
-
- ifparams.has_key?(:question_id) then
- @question_id = params[:question_id].to_i
- end
-
- respond_todo|format|
- format.html
- end
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- admin_previewphase()
- click to toggle source
-
-
-
-
-
-
preview a phase
-
-
-
-
-
# File app/controllers/dmptemplates_controller.rb, line 173
-defadmin_previewphase
- ifuser_signed_in?&¤t_user.can_org_admin?then
-
- @version = Version.find(params[:id])
-
-
- respond_todo|format|
- format.html
- end
- end
-end
# File app/models/exported_plan.rb, line 135
-defsanitize_text(text)
- if (!text.nil?) thenActionView::Base.full_sanitizer.sanitize(text.gsub(/ /,"")) end
-end
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
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Public Class Methods
-
-
-
-
-
- by_organisation(org_id)
- click to toggle source
-
-
-
-
-
-
all guidance that belong to an organisation
-
-
-
-
-
# File app/models/guidance.rb, line 40
-defself.by_organisation(org_id)
- all_guidance = Guidance.all
- org_guidance = Array.new
-
- all_guidance.eachdo|guidance|
- ifguidance.in_group_belonging_to?(org_id) then
- org_guidance<<guidance
- end
- end
-
- returnorg_guidance
-
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Public Instance Methods
-
-
-
-
-
- get_guidance_group_templates?(guidance_group)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/guidance.rb, line 55
-defget_guidance_group_templates? (guidance_group)
- templates = guidancegroups.where("guidance_group_id (?)", guidance_group.id).template
- returntemplates
- end
-
-
-
-
-
-
-
-
-
-
-
-
-
- in_group_belonging_to?(organisation_id)
- click to toggle source
-
-
-
-
-
-
verifies if one guidance belongs to a org
-
-
-
-
-
# File app/models/guidance.rb, line 29
-defin_group_belonging_to?(organisation_id)
- guidance_groups.eachdo|guidance_group|
- ifguidance_group.organisation_id==organisation_idthen
- returntrue
- end
- end
- returnfalse
-end
# File app/controllers/guidances_controller.rb, line 76
- defupdate_phases
- # updates phases, versions, sections and questions based on template selected
-
- dmptemplate = Dmptemplate.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, "Select a phase")
- @versions = dmptemplate.versions.map{|s| [s.title, s.id]}.insert(0, "Select a version")
- @sections = dmptemplate.sections.map{|s| [s.title, s.id]}.insert(0, "Select a section")
- @questions = dmptemplate.questions.map{|s| [s.text, s.id]}.insert(0, "Select a question")
-
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- update_questions()
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/controllers/guidances_controller.rb, line 104
-defupdate_questions
- # updates songs based on artist selected
-
- section = Section.find(params[:section_id])
- @questions = section.questions.map{|s| [s.text, s.id]}.insert(0, "Select a question")
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- update_sections()
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/controllers/guidances_controller.rb, line 96
-defupdate_sections
- # 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, "Select a section")
- @questions = version.questions.map{|s| [s.text, s.id]}.insert(0, "Select a question")
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- update_versions()
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/controllers/guidances_controller.rb, line 87
-defupdate_versions
- # 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, "Select a version")
- @sections = phase.sections.map{|s| [s.title, s.id]}.insert(0, "Select a section")
- @questions = phase.questions.map{|s| [s.text, s.id]}.insert(0, "Select a question")
- end
# File app/models/plan.rb, line 36
-defdmptemplate
- self.project.try(:dmptemplate) ||Dmptemplate.new
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- editable_by(user_id)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/plan.rb, line 156
-defeditable_by(user_id)
- returnproject.editable_by(user_id)
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- guidance_for_question(question)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/plan.rb, line 81
-defguidance_for_question(question)
- guidances = {}
- # If project org isn't nil, get guidance by theme from any "non-subset" groups belonging to project org
-
- unlessproject.organisation.nil?then
- project.organisation.guidance_groups.eachdo|group|
- if!group.optional_subset&& (group.dmptemplates.pluck(:id).include?(project.dmptemplate_id) ||group.dmptemplates.count==0) then
- group.guidances.eachdo|guidance|
- guidance.themes.where("id IN (?)", question.theme_ids).eachdo|theme|
- guidances = self.add_guidance_to_array(guidances, group, theme, guidance)
- end
- end
- end
- end
- end
-
- # Get guidance by theme from any guidance groups selected on creation
-
- project.guidance_groups.eachdo|group|
- ifgroup.dmptemplates.pluck(:id).include?(project.dmptemplate_id) ||group.dmptemplates.count==0then
- group.guidances.eachdo|guidance|
- guidance.themes.where("id IN (?)", question.theme_ids).eachdo|theme|
- guidances = self.add_guidance_to_array(guidances, group, theme, guidance)
- end
- end
- end
-end
-
- # Get guidance by question where guidance group was selected on creation or if group is organisation default
-
- question.guidances.eachdo|guidance|
- guidance.guidance_groups.eachdo|group|
- if (group.organisation==project.organisation&&!group.optional_subset) ||project.guidance_groups.include?(group) then
- guidances = self.add_guidance_to_array(guidances, group, nil, guidance)
- end
- end
- end
-
- returnguidances
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- latest_update()
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/plan.rb, line 321
-deflatest_update
- ifanswers.any?then
- last_answered = answers.order("updated_at DESC").first.updated_at
- iflast_answered>updated_atthen
- returnlast_answered
- else
- returnupdated_at
- end
- else
- returnupdated_at
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- lock_all_sections(user_id)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/plan.rb, line 279
-deflock_all_sections(user_id)
- sections.eachdo|s|
- lock_section(s.id, user_id, 1800)
- end
-end
Proxy through to the template settings (or defaults if this plan
-doesn't have an associated template) if there are no settings stored
-for this plan. `key` is required by rails-settings, so it's required
-here, too.
# File app/models/plan.rb, line 40
-deftitle
- logger.debug"Title in settings: #{self.settings(:export).title}"
- ifself.settings(:export).title==""
- if!self.version.nil?&&!self.version.phase.nil?&&!self.version.phase.title?then
- returnself.version.phase.title
- else
- return"DMP title"
- end
- else
- returnself.settings(:export).title
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- unlock_all_sections(user_id)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/plan.rb, line 285
-defunlock_all_sections(user_id)
- plan_sections.where(:user_id =>user_id).order("created_at DESC").eachdo|lock|
- lock.delete
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- unlock_section(section_id, user_id)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/plan.rb, line 315
-defunlock_section(section_id, user_id)
- plan_sections.where(:section_id =>section_id, :user_id =>user_id).order("created_at DESC").eachdo|lock|
- lock.delete
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- warning(option_id)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/plan.rb, line 148
-defwarning(option_id)
- ifproject.organisation.nil?
- returnnil
- else
- returnproject.organisation.warning(option_id)
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Private Instance Methods
-
-
-
-
-
- estimate_space_used(used_height)
- click to toggle source
-
-
-
-
-
-
Based on the height of the text gathered so far and the available vertical
-space of the pdf, estimate a percentage of how much space has been used.
-This is highly dependent on the layout in the pdf. A more accurate approach
-would be to render the pdf and check how much space had been used, but that
-could be very slow. NOTE: This is only an estimate, rounded up to the
-nearest 5%; it is intended for guidance when editing plan data, not to be
-100% accurate.
-
-
-
-
-
# File app/models/plan.rb, line 372
-defestimate_space_used(used_height)
- @formatting||=self.settings(:export).formatting
-
- return0unless@formatting[:font_size] >0
-
- margin_height = @formatting[:margin][:top].to_i+@formatting[:margin][:bottom].to_i
- page_height = A4_PAGE_HEIGHT-margin_height# 297mm for A4 portrait
-
- available_height = page_height * self.dmptemplate.settings(:export).max_pages
-
- percentage = (used_height/available_height) * 100
- (percentage/ROUNDING).ceil * ROUNDING# round up to nearest five
-
-end
Take a guess at the vertical height (in mm) of the given text based on the
-font-size and left/right margins stored in the plan's settings. This
-assumes a fixed-width for each glyph, which is obviously incorrect for the
-font-face choices available; the idea is that they'll hopefully average
-out to that in the long-run. Allows for hinting different font sizes
-(offset from base via font_size_inc) and vertical margins (i.e. for heading
-text)
# File app/controllers/plans_controller.rb, line 6
- defedit
- @plan = Plan.find(params[:id])
-
-
-if!user_signed_in?then
- respond_todo|format|
- format.html { redirect_toedit_user_registration_path }
- end
- elsif!@plan.readable_by(current_user.id) then
- respond_todo|format|
- format.html { redirect_toprojects_url, notice:"This account does not have access to that plan." }
- end
- end
- end
-
-
-
-
-
-
-
-
-
-
-
-
-
- export()
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/controllers/plans_controller.rb, line 164
-defexport
- @plan = Plan.find(params[:id])
-
- ifuser_signed_in?&&@plan.readable_by(current_user.id) then
- @exported_plan = ExportedPlan.new.tapdo|ep|
- ep.plan = @plan
- ep.user = current_user
- ep.format = request.format.try(:symbol)
- plan_settings = @plan.settings(:export)
-
- Settings::Dmptemplate::DEFAULT_SETTINGS.eachdo|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_todo|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.pdfdo
- @formatting = @plan.settings(:export).formatting
- renderpdf: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
- elsif!user_signed_in?then
- respond_todo|format|
- format.html { redirect_toedit_user_registration_path }
- end
- elsif!@plan.editable_by(current_user.id) then
- respond_todo|format|
- format.html { redirect_toprojects_url, notice:"This account does not have access to that plan." }
- end
- end
-end
# File app/models/project.rb, line 77
-definstitution_id
- iforganisation.nil?
- returnnil
- else
- returnorganisation.root.id
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- institution_id=(new_institution_id)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/project.rb, line 71
-definstitution_id=(new_institution_id)
- iforganisation.nil?then
- self.organisation_id = new_institution_id
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- last_edited()
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/project.rb, line 183
-deflast_edited
- self.latest_update.to_date
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- latest_update()
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/project.rb, line 164
-deflatest_update
- latest_update = updated_at
- plans.eachdo|plan|
- ifplan.latest_update>latest_updatethen
- latest_update = plan.latest_update
- end
- end
- returnlatest_update
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- name()
- click to toggle source
-
-
-
-
-
-
Getters to match 'My plans' columns
-
-
-
-
-
# File app/models/project.rb, line 175
-defname
- self.title
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- owner()
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/project.rb, line 179
-defowner
- self.project_groups.find_by_project_creator(true).try(:user)
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- readable_by(user_id)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/project.rb, line 133
-defreadable_by(user_id)
- user = project_groups.find_by_user_id(user_id)
- if (!user.nil?) then
- returntrue
- else
- returnfalse
- end
-end
# File app/models/project_group.rb, line 9
-defemail
- unlessuser.nil?
- returnuser.email
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- email=(new_email)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/models/project_group.rb, line 15
-defemail=(new_email)
- unlessUser.find_by_email(email).nil?then
- user = User.find_by_email(email)
- end
-end
# File app/controllers/projects_controller.rb, line 71
-defedit
- @project = Project.find(params[:id])
- if!user_signed_in?then
- respond_todo|format|
- format.html { redirect_toedit_user_registration_path }
- end
- elsif!@project.editable_by(current_user.id) then
- respond_todo|format|
- format.html { redirect_toprojects_url, notice:"This account does not have access to that plan." }
- end
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- export()
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/controllers/projects_controller.rb, line 97
-defexport
- @project = Project.find(params[:id])
- if!user_signed_in?then
- respond_todo|format|
- format.html { redirect_toedit_user_registration_path }
- end
- else
- respond_todo|format|
- format.html { renderaction:"export" }
-
- end
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- index()
- click to toggle source
-
-
-
-
-
-
GET /projects GET /projects.json
-
-
-
-
-
# File app/controllers/projects_controller.rb, line 6
-defindex
- ifuser_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 'link your DMPonline account to your institutional credentials?', user_omniauth_shibboleth_path}".html_safe
- end
-
- @projects = current_user.projects.filter(params[:filter])
- @has_projects = current_user.projects.any?# unfiltered count
-
-
- respond_todo|format|
- format.html# index.html.erb
-
- format.json { renderjson:@projects }
- end
- else
- respond_todo|format|
- format.html { redirect_toedit_user_registration_path }
- end
- end
-end
# File app/controllers/projects_controller.rb, line 213
-defpossible_guidance
- if!params[:template].nil?&¶ms[:template] !=""&¶ms[:template] !="undefined"then
- template = Dmptemplate.find(params[:template])
- else
- template = nil
- end
- if!params[:institution].nil?&¶ms[:institution] !=""&¶ms[:institution] !="undefined"then
- institution = Organisation.find(params[:institution])
- else
- institution = nil
- end
- excluded_orgs = orgs_of_type(t('helpers.org_type.funder')) +orgs_of_type(t('helpers.org_type.institution')) +Organisation.orgs_with_parent_of_type(t('helpers.org_type.institution'))
- guidance_groups = {}
- ggs = GuidanceGroup.guidance_groups_excluding(excluded_orgs)
-
- ggs.eachdo|gg|
- guidance_groups[gg.id] = gg.name
- end
-
-#subset guidance that belong to the institution
-
- unlessinstitution.nil?then
- optional_gg = GuidanceGroup.where("optional_subset = ? && organisation_id = ?", true, institution.id)
- optional_gg.eachdo|optional|
- guidance_groups[optional.id] = optional.name
- end
-
- institution.children.eachdo|o|
- o.guidance_groups.eachdo|gg|
- include = false
- gg.guidances.eachdo|g|
- ifg.dmptemplate.nil?||g.dmptemplate_id==template.idthen
- include = true
- break
- end
- end
- ifincludethen
- 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==t('helpers.org_type.funder') then
- optional_gg = GuidanceGroup.where("optional_subset = ? && organisation_id = ?", true, template.organisation_id)
- optional_gg.eachdo|optional|
- guidance_groups[optional.id] = optional.name
- end
-end
-
-
- respond_todo|format|
- format.json { renderjson:guidance_groups.to_json }
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- possible_templates()
- click to toggle source
-
-
-
-
-
-
GET /projects/possible_templates.json
-
-
-
-
-
# File app/controllers/projects_controller.rb, line 181
-defpossible_templates
- if!params[:funder].nil?&¶ms[:funder] !=""&¶ms[:funder] !="undefined"then
- funder = Organisation.find(params[:funder])
- else
- funder = nil
- end
- if!params[:institution].nil?&¶ms[:institution] !=""&¶ms[:institution] !="undefined"then
- institution = Organisation.find(params[:institution])
- else
- institution = nil
- end
- templates = {}
- unlessfunder.nil?then
- funder.published_templates.eachdo|t|
- templates[t.id] = t.title
- end
- end
- iftemplates.count==0&&!institution.nil?then
- institution.published_templates.eachdo|t|
- templates[t.id] = t.title
- end
- institution.children.eachdo|o|
- o.published_templates.eachdo|t|
- templates[t.id] = t.title
- end
- end
- end
- respond_todo|format|
- format.json { renderjson:templates.to_json }
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- share()
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/controllers/projects_controller.rb, line 84
-defshare
- @project = Project.find(params[:id])
- if!user_signed_in?then
- respond_todo|format|
- format.html { redirect_toedit_user_registration_path }
- end
- elsif!@project.editable_by(current_user.id) then
- respond_todo|format|
- format.html { redirect_toprojects_url, notice:"This account does not have access to that plan." }
- end
- end
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
- show()
- click to toggle source
-
-
-
-
-
-
GET /projects/1 GET /projects/1.json
-
-
-
-
-
# File app/controllers/projects_controller.rb, line 28
-defshow
- @project = Project.find(params[:id])
- @show_form = false
- ifparams[:show_form] =="yes"then
- @show_form = true
- end
- ifuser_signed_in?&&@project.readable_by(current_user.id) then
- respond_todo|format|
- format.html# show.html.erb
-
- format.json { renderjson:@project }
- end
- elsifuser_signed_in?then
- respond_todo|format|
- format.html { redirect_toprojects_url, notice:"This account does not have access to that plan." }
- end
- else
- respond_todo|format|
- format.html { redirect_toedit_user_registration_path }
- end
- end
-end
- guidance_for_question(question, org_admin)
- click to toggle source
-
-
-
-
-
-
guidance for question in the org admin
-
-
-
-
-
# File app/models/question.rb, line 69
-defguidance_for_question(question, org_admin)
-# pulls together guidance from various sources for question
-
-guidances = {}
-theme_ids = question.theme_ids
-
-GuidanceGroup.where("organisation_id = ?", org_admin.id).eachdo|group|
- group.guidances.eachdo|g|
- g.themes.where("id IN (?)", theme_ids).eachdo|gg|
- guidances["#{group.name} guidance on #{gg.title}"] = g
- end
- end
-end
-
- # Guidance link to directly to a question
-
-question.guidances.eachdo|g_by_q|
- g_by_q.guidance_groups.eachdo|group|
- ifgroup.organisation==org_admin
- guidances["#{group.name} guidance for this question"] = g_by_q
- end
- end
- end
-
- returnguidances
-end
DMPonline is the DCC's data management planning tool, available at dmponline.dcc.ac.uk
-
-
Development of the DMPonline by the Digital Curation Centre has been funded
-by JISC. JISC inspires UK colleges and universities in the innovative use
-of digital technologies, helping to maintain the UK's position as a
-global leader in education. www.jisc.ac.uk
-
-
This is just the application code, the accompanying question data available
-at dmponline.dcc.ac.uk is not
-included.
-
-
The tool has four main functions
-
-
To help create and maintain different versions of Data Management Plans;
-
-
To provide useful guidance on data management issues and how to meet
-research funders' requirements;
-
-
To export attractive and useful plans in a variety of formats;
-
-
To allow collaborative work when creating Data Management Plans.
-
-
-
Documentation & Support
-
-
You can contact us by email, dmponline@dcc.ac.uk, but we can only provide
-limited support for your installation
DMPonline is a Ruby on Rails application and you will need to have Ruby
-2.0.0p247 or greater installed on your server and a MySQL server v5.0 or
-greater.
-
-
Further details on how to install Ruby on Rails applications are available
-from the Ruby on Rails site, rubyonrails.org
This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or (at your
-option) any later version.
-
-
This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
-for more details.
-
-
You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see www.gnu.org/licenses.
# File app/controllers/settings/projects_controller.rb, line 29
-defget_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
- sharing_notification(project_group)
- click to toggle source
-
-
-
-
-
-
-
-
-
-
-
# File app/mailers/user_mailer.rb, line 4
-defsharing_notification(project_group)
- @project_group = project_group
- mail(to:@project_group.user.email, subject:"You have been given access to a Data Management Plan")
-end
# File app/controllers/users/omniauth_shibboleth_request_controller.rb, line 17
-defassociate
- # This action is protected - can only be reached if user is already logged in.
-
- # See before_filter
-
- redirect_touser_omniauth_callback_path(:shibboleth)
-end
DMPonline is the DCC's data management planning tool, available at dmponline.dcc.ac.uk
-
-
Development of the DMPonline by the Digital Curation Centre has been funded
-by JISC. JISC inspires UK colleges and universities in the innovative use
-of digital technologies, helping to maintain the UK's position as a
-global leader in education. www.jisc.ac.uk
-
-
This is just the application code, the accompanying question data available
-at dmponline.dcc.ac.uk is not
-included.
-
-
The tool has four main functions
-
-
To help create and maintain different versions of Data Management Plans;
-
-
To provide useful guidance on data management issues and how to meet
-research funders' requirements;
-
-
To export attractive and useful plans in a variety of formats;
-
-
To allow collaborative work when creating Data Management Plans.
-
-
-
Documentation & Support
-
-
You can contact us by email, dmponline@dcc.ac.uk, but we can only provide
-limited support for your installation
DMPonline is a Ruby on Rails application and you will need to have Ruby
-2.0.0p247 or greater installed on your server and a MySQL server v5.0 or
-greater.
-
-
Further details on how to install Ruby on Rails applications are available
-from the Ruby on Rails site, rubyonrails.org
This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or (at your
-option) any later version.
-
-
This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
-for more details.
-
-
You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see www.gnu.org/licenses.
-
-
-
-
-
-
diff --git a/html/js/darkfish.js b/html/js/darkfish.js
deleted file mode 100644
index 92d8280..0000000
--- a/html/js/darkfish.js
+++ /dev/null
@@ -1,155 +0,0 @@
-/**
- *
- * Darkfish Page Functions
- * $Id: darkfish.js 53 2009-01-07 02:52:03Z deveiant $
- *
- * Author: Michael Granger
- *
- */
-
-/* Provide console simulation for firebug-less environments */
-if (!("console" in window) || !("firebug" in console)) {
- var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
- "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
-
- window.console = {};
- for (var i = 0; i < names.length; ++i)
- window.console[names[i]] = function() {};
-};
-
-
-/**
- * Unwrap the first element that matches the given @expr@ from the targets and return them.
- */
-$.fn.unwrap = function( expr ) {
- return this.each( function() {
- $(this).parents( expr ).eq( 0 ).after( this ).remove();
- });
-};
-
-
-function showSource( e ) {
- var target = e.target;
- var codeSections = $(target).
- parents('.method-detail').
- find('.method-source-code');
-
- $(target).
- parents('.method-detail').
- find('.method-source-code').
- slideToggle();
-};
-
-function hookSourceViews() {
- $('.method-heading').click( showSource );
-};
-
-function toggleDebuggingSection() {
- $('.debugging-section').slideToggle();
-};
-
-function hookDebuggingToggle() {
- $('#debugging-toggle img').click( toggleDebuggingSection );
-};
-
-function hookTableOfContentsToggle() {
- $('.indexpage li .toc-toggle').each( function() {
- $(this).click( function() {
- $(this).toggleClass('open');
- });
-
- var section = $(this).next();
-
- $(this).click( function() {
- section.slideToggle();
- });
- });
-}
-
-function hookSearch() {
- var input = $('#search-field').eq(0);
- var result = $('#search-results').eq(0);
- $(result).show();
-
- var search_section = $('#search-section').get(0);
- $(search_section).show();
-
- var search = new Search(search_data, input, result);
-
- search.renderItem = function(result) {
- var li = document.createElement('li');
- var html = '';
-
- // TODO add relative path to
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/assets/images/remove.png b/lib/assets/images/remove.png
new file mode 100644
index 0000000..b2ef137
--- /dev/null
+++ b/lib/assets/images/remove.png
Binary files differ
diff --git a/lib/assets/javascripts/admin.js b/lib/assets/javascripts/admin.js
index 6354869..f3d3aaf 100644
--- a/lib/assets/javascripts/admin.js
+++ b/lib/assets/javascripts/admin.js
@@ -1,5 +1,5 @@
//= require tinymce
-/*
+/*
**Project: DMPRoadmap
**Description: This file include all javascript regarding admin interface
**Copyright: Digital Curation Centre and University of California Curation Center
@@ -20,7 +20,7 @@
}, 1000);
}
}
-
+
//set the tinymce popover help text
$(".template_desc_popover, .phase_desc_popover, .version_desc_popover, .section_desc_popover, .question_format_popover," +
" .default_answer_popover, .suggested_answer_popover, .question_guidance_popover, .question_themes_popover," +
@@ -29,13 +29,13 @@
" .guidance_by_question_popover, .guidance_group_select_popover, .org_abbr_popover").on('click', function(e) {
e.preventDefault();
}).popover();
-
+
//show or hide divs based on what the user selects from the question format. New question
$('.ques_format').on("change", function(e) {
var s_id = $(this).prev(".section_id").val();
-
+
var selected_format = $('#new-select-format-'+ s_id).val();
-
+
//text area
if (selected_format == 1){
$("#new-options-"+ s_id).hide();
@@ -175,7 +175,7 @@
//action for show or hide template editing display
$('#edit_template_button').click(function(e){
e.preventDefault();
-
+
$('#edit_template_div').show();
$('#show_template_div').hide();
});
@@ -220,18 +220,18 @@
$('#add_question_block_div_'+ s_id).show();
$('#add_question_button_div_'+ s_id).hide();
e.preventDefault();
-
+
});
-
- //if question text area is empty send alert
- $('.new_question_save_button').click(function(e){
+
+ //if question text area is empty send alert
+ $('.new_question_save_button').click(function(e){
var s_id = $(this).prev(".section_id").val();
if ($('#new_question_text_'+ s_id).val() == ''){
alert(I18n.t("js.question_text_empty"));
return false;
}
});
-
+
//action for cancelling a new question
$('.cancel_add_new_question').click(function(e){
var s_id_new = $(this).prev(".section_id_new").val();
@@ -280,7 +280,7 @@
$('#show_suggested_answer_div_'+ q_id).hide();
e.preventDefault();
});
-
+
//GUIDANCE
//action for adding a new guidance next to the question
$('.add_guidance_button').click(function(e){
@@ -305,44 +305,44 @@
$('#show_guidance_div_'+ q_id).hide();
e.preventDefault();
});
-
-
- //Add new guidance Alerts
+
+
+ //Add new guidance Alerts
$("#return_to_new_guidance").click(function(){
$('#new_guidance_alert_dialog').modal("hide");
});
-
-
+
+
$('#new_guidance_submit').click( function(e){
// $('#new_guidance_alert_dialog').on("hide", function(){
-
+
var alert_message = [];
//verify if text area is not nil
var editorContent = tinyMCE.get('guidance-text').getContent();
if (editorContent == ''){
alert_message.push(I18n.t("js.add_guidance_text"));
- }
- //verify dropdown with questions has a selected option if guidance for a question being used
+ }
+ //verify dropdown with questions has a selected option if guidance for a question being used
if ($('#g_options').val() == '2') {
if ($('#questions_select').val() == '' || isNaN($('#questions_select').val())){
alert_message.push(I18n.t("js.select_question"));
}
}
- //verify dropdown with questions has a selected option if guidance for a question being used
+ //verify dropdown with questions has a selected option if guidance for a question being used
if ($('#g_options').val() == '1' ){
if($('#guidance_theme_ids').val() == undefined || $('#guidance_theme_ids').val() == ''){
alert_message.push(I18n.t("js.select_at_least_one_theme"));
}
}
- //verify if guidance group is selected
+ //verify if guidance group is selected
if ( ($('#guidance_guidance_group_ids').val() == '') || $('#guidance_guidance_group_ids').val() == undefined ) {
alert_message.push(I18n.t("js.select_guidance_group"));
}
if(alert_message.length == 0){
//clear dropdowns before submission
$('#new_guidance_alert_dialog').modal("hide");
-
+
if ($('#g_options').val() == '2'){
$('#guidance_theme_ids').val(null);
}
@@ -351,12 +351,12 @@
}
$('#new_guidance_form').submit();
return false;
-
+
}
else if (alert_message.length != 0){
var message = '';
$('#new_guidance_alert_dialog').on("show", function(){
-
+
$("#missing_fields_new_guidance").empty();
$.each(alert_message, function(key, value){
message += "
"+value+"
";
@@ -368,43 +368,43 @@
delete alert_message;
e.preventDefault();
});
-
+
//edit guidance alerts
$("#return_to_edit_guidance").click(function(){
$('#edit_guidance_alert_dialog').modal("hide");
});
-
-
+
+
$('#edit_guidance_submit').click( function(e){
// $('#new_guidance_alert_dialog').on("hide", function(){
-
+
var alert_message = [];
//verify if text area is not nil
var editorContent = tinyMCE.get('guidance-text').getContent();
if (editorContent == ''){
alert_message.push(I18n.t("js.add_guidance_text"));
- }
- //verify dropdown with questions has a selected option if guidance for a question being used
+ }
+ //verify dropdown with questions has a selected option if guidance for a question being used
if ($('#g_options').val() == '2') {
if ($('#questions_select').val() == '' || isNaN($('#questions_select').val())){
alert_message.push(I18n.t("js.select_question"));
}
}
- //verify dropdown with questions has a selected option if guidance for a question being used
+ //verify dropdown with questions has a selected option if guidance for a question being used
if ($('#g_options').val() == '1' ){
if($('#guidance_theme_ids').val() == undefined || $('#guidance_theme_ids').val() == ''){
alert_message.push(I18n.t("js.select_at_least_one_theme"));
}
}
- //verify if guidance group is selected
+ //verify if guidance group is selected
if ( ($('#guidance_guidance_group_ids').val() == '') || $('#guidance_guidance_group_ids').val() == undefined ) {
alert_message.push(I18n.t("js.select_guidance_group"));
}
-
+
if(alert_message.length == 0){
//clear dropdowns before submission
$('#edit_guidance_alert_dialog').modal("hide");
-
+
if ($('#g_options').val() == '2'){ $('#guidance_theme_ids').val(null);}
if($('#g_options').val() == '1'){$('#questions_select').val(null);}
$('#edit_guidance_form').submit();
@@ -413,7 +413,7 @@
else if (alert_message.length != 0){
var message = '';
$('#edit_guidance_alert_dialog').on("show", function(){
-
+
$("#missing_fields_edit_guidance").empty();
$.each(alert_message, function(key, value){
message += "
# File app/models/ability.rb, line 4
+definitialize(user)
+ # Define abilities for the passed in user here. For example:
+
+ #
+
+ user||=User.new# guest user (not logged in)
+
+ ifuser.has_role?:admin
+ can:manage, :all
+ else
+ can:read, :all
+ end
+
+ can:manage_settings, Userdo|viewed_user|
+ viewed_user.present?&&user.id==viewed_user.id
+ end
+ #
+
+ # The first argument to `can` is the action you are giving the user
+
+ # permission to do.
+
+ # If you pass :manage it will apply to every action. Other common actions
+
+ # here are :read, :create, :update and :destroy.
+
+ #
+
+ # The second argument is the resource the user can perform the action on.
+
+ # If you pass :all it will apply to every resource. Otherwise pass a Ruby
+
+ # class of the resource.
+
+ #
+
+ # The third argument is an optional hash of conditions to further filter the
+
+ # objects.
+
+ # For example, here the user can only update published articles.
+
+ #
+
+ # can :update, Article, :published => true
+
+ #
+
+ # See the wiki for details:
+
+ # https://github.com/ryanb/cancan/wiki/Defining-Abilities
+
+
+end
+ after_sign_in_error_path_for(resource)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/application_controller.rb, line 32
+defafter_sign_in_error_path_for(resource)
+ session[:previous_url] ||root_path
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ after_sign_in_path_for(resource)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/application_controller.rb, line 24
+defafter_sign_in_path_for(resource)
+ session[:previous_url] ||root_path
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ after_sign_up_error_path_for(resource)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/application_controller.rb, line 36
+defafter_sign_up_error_path_for(resource)
+ session[:previous_url] ||root_path
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ after_sign_up_path_for(resource)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/application_controller.rb, line 28
+defafter_sign_up_path_for(resource)
+ session[:previous_url] ||root_path
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ authenticate_admin!()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/application_controller.rb, line 40
+defauthenticate_admin!
+ redirect_toroot_pathunlessuser_signed_in?&¤t_user.can_super_admin?
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ get_plan_list_columns()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/application_controller.rb, line 44
+defget_plan_list_columns
+ ifuser_signed_in?
+ @selected_columns = current_user.settings(:plan_list).columns
+ @all_columns = Settings::PlanList::ALL_COLUMNS
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ store_location()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/application_controller.rb, line 13
+defstore_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
+
+ session[:previous_url] = request.fullpath
+ end
+end
This controller is responsible for all the actions in the admin interface
+under templates (e.g. phases, versions, sections, questions, suggested
+answer) (index; show; create; edit; delete)
+
Copyright:
+
+
Digital Curation Centre
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public Instance Methods
+
+
+
+
+
+ admin_addphase()
+ click to toggle source
+
+
+
+
+
+
add a new phase to a template
+
+
+
+
+
# File app/controllers/dmptemplates_controller.rb, line 187
+defadmin_addphase
+ ifuser_signed_in?&¤t_user.can_org_admin?then
+ @dmptemplate = Dmptemplate.find(params[:id])
+ @phase = Phase.new
+ if@dmptemplate.phases.count==0then
+ @phase.number = '1'
+ else
+ @phase.number = @dmptemplate.phases.count+1
+ end
+
+ respond_todo|format|
+ format.html
+ end
+ end
+end
# File app/controllers/dmptemplates_controller.rb, line 124
+defadmin_phase
+ ifuser_signed_in?&¤t_user.can_org_admin?then
+
+ @phase = Phase.find(params[:id])
+
+ if!params.has_key?(:version_id) then
+ @edit = 'false'
+ #check for the most recent published version, if none is available then return the most recent one
+
+ versions = @phase.versions.where('published = ?', true).order('updated_at DESC')
+ ifversions.any?() then
+ @version = versions.first
+ else
+ @version = @phase.versions.order('updated_at DESC').first
+ end
+ # When the version_id is passed as an argument
+
+ else
+ @edit = params[:edit]
+ @version = Version.find(params[:version_id])
+ end
+
+ #verify if there are any sections if not create one
+
+ @sections = @version.sections
+ if!@sections.any?() ||@sections.count==0then
+ @section = @version.sections.build
+ @section.title = ''
+ @section.version_id = params[:version_id]
+ @section.number = 1
+ @section.organisation_id = current_user.organisation.id
+ @section.published = true
+ @section.save
+ end
+
+ #verify if section_id has been passed, if so then open that section
+
+ ifparams.has_key?(:section_id) then
+ @open = true
+ @section_id = params[:section_id].to_i
+ end
+
+ ifparams.has_key?(:question_id) then
+ @question_id = params[:question_id].to_i
+ end
+
+ respond_todo|format|
+ format.html
+ end
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ admin_previewphase()
+ click to toggle source
+
+
+
+
+
+
preview a phase
+
+
+
+
+
# File app/controllers/dmptemplates_controller.rb, line 173
+defadmin_previewphase
+ ifuser_signed_in?&¤t_user.can_org_admin?then
+
+ @version = Version.find(params[:id])
+
+
+ respond_todo|format|
+ format.html
+ end
+ end
+end
# File app/models/exported_plan.rb, line 135
+defsanitize_text(text)
+ if (!text.nil?) thenActionView::Base.full_sanitizer.sanitize(text.gsub(/ /,"")) end
+end
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public Class Methods
+
+
+
+
+
+ by_organisation(org_id)
+ click to toggle source
+
+
+
+
+
+
all guidance that belong to an organisation
+
+
+
+
+
# File app/models/guidance.rb, line 40
+defself.by_organisation(org_id)
+ all_guidance = Guidance.all
+ org_guidance = Array.new
+
+ all_guidance.eachdo|guidance|
+ ifguidance.in_group_belonging_to?(org_id) then
+ org_guidance<<guidance
+ end
+ end
+
+ returnorg_guidance
+
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public Instance Methods
+
+
+
+
+
+ get_guidance_group_templates?(guidance_group)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/guidance.rb, line 55
+defget_guidance_group_templates? (guidance_group)
+ templates = guidancegroups.where("guidance_group_id (?)", guidance_group.id).template
+ returntemplates
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ in_group_belonging_to?(organisation_id)
+ click to toggle source
+
+
+
+
+
+
verifies if one guidance belongs to a org
+
+
+
+
+
# File app/models/guidance.rb, line 29
+defin_group_belonging_to?(organisation_id)
+ guidance_groups.eachdo|guidance_group|
+ ifguidance_group.organisation_id==organisation_idthen
+ returntrue
+ end
+ end
+ returnfalse
+end
# File app/controllers/guidances_controller.rb, line 76
+ defupdate_phases
+ # updates phases, versions, sections and questions based on template selected
+
+ dmptemplate = Dmptemplate.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, "Select a phase")
+ @versions = dmptemplate.versions.map{|s| [s.title, s.id]}.insert(0, "Select a version")
+ @sections = dmptemplate.sections.map{|s| [s.title, s.id]}.insert(0, "Select a section")
+ @questions = dmptemplate.questions.map{|s| [s.text, s.id]}.insert(0, "Select a question")
+
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ update_questions()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/guidances_controller.rb, line 104
+defupdate_questions
+ # updates songs based on artist selected
+
+ section = Section.find(params[:section_id])
+ @questions = section.questions.map{|s| [s.text, s.id]}.insert(0, "Select a question")
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ update_sections()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/guidances_controller.rb, line 96
+defupdate_sections
+ # 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, "Select a section")
+ @questions = version.questions.map{|s| [s.text, s.id]}.insert(0, "Select a question")
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ update_versions()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/guidances_controller.rb, line 87
+defupdate_versions
+ # 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, "Select a version")
+ @sections = phase.sections.map{|s| [s.title, s.id]}.insert(0, "Select a section")
+ @questions = phase.questions.map{|s| [s.text, s.id]}.insert(0, "Select a question")
+ end
# File app/models/plan.rb, line 36
+defdmptemplate
+ self.project.try(:dmptemplate) ||Dmptemplate.new
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ editable_by(user_id)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/plan.rb, line 156
+defeditable_by(user_id)
+ returnproject.editable_by(user_id)
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ guidance_for_question(question)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/plan.rb, line 81
+defguidance_for_question(question)
+ guidances = {}
+ # If project org isn't nil, get guidance by theme from any "non-subset" groups belonging to project org
+
+ unlessproject.organisation.nil?then
+ project.organisation.guidance_groups.eachdo|group|
+ if!group.optional_subset&& (group.dmptemplates.pluck(:id).include?(project.dmptemplate_id) ||group.dmptemplates.count==0) then
+ group.guidances.eachdo|guidance|
+ guidance.themes.where("id IN (?)", question.theme_ids).eachdo|theme|
+ guidances = self.add_guidance_to_array(guidances, group, theme, guidance)
+ end
+ end
+ end
+ end
+ end
+
+ # Get guidance by theme from any guidance groups selected on creation
+
+ project.guidance_groups.eachdo|group|
+ ifgroup.dmptemplates.pluck(:id).include?(project.dmptemplate_id) ||group.dmptemplates.count==0then
+ group.guidances.eachdo|guidance|
+ guidance.themes.where("id IN (?)", question.theme_ids).eachdo|theme|
+ guidances = self.add_guidance_to_array(guidances, group, theme, guidance)
+ end
+ end
+ end
+end
+
+ # Get guidance by question where guidance group was selected on creation or if group is organisation default
+
+ question.guidances.eachdo|guidance|
+ guidance.guidance_groups.eachdo|group|
+ if (group.organisation==project.organisation&&!group.optional_subset) ||project.guidance_groups.include?(group) then
+ guidances = self.add_guidance_to_array(guidances, group, nil, guidance)
+ end
+ end
+ end
+
+ returnguidances
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ latest_update()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/plan.rb, line 321
+deflatest_update
+ ifanswers.any?then
+ last_answered = answers.order("updated_at DESC").first.updated_at
+ iflast_answered>updated_atthen
+ returnlast_answered
+ else
+ returnupdated_at
+ end
+ else
+ returnupdated_at
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ lock_all_sections(user_id)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/plan.rb, line 279
+deflock_all_sections(user_id)
+ sections.eachdo|s|
+ lock_section(s.id, user_id, 1800)
+ end
+end
Proxy through to the template settings (or defaults if this plan
+doesn't have an associated template) if there are no settings stored
+for this plan. `key` is required by rails-settings, so it's required
+here, too.
# File app/models/plan.rb, line 40
+deftitle
+ logger.debug"Title in settings: #{self.settings(:export).title}"
+ ifself.settings(:export).title==""
+ if!self.version.nil?&&!self.version.phase.nil?&&!self.version.phase.title?then
+ returnself.version.phase.title
+ else
+ return"DMP title"
+ end
+ else
+ returnself.settings(:export).title
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ unlock_all_sections(user_id)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/plan.rb, line 285
+defunlock_all_sections(user_id)
+ plan_sections.where(:user_id =>user_id).order("created_at DESC").eachdo|lock|
+ lock.delete
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ unlock_section(section_id, user_id)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/plan.rb, line 315
+defunlock_section(section_id, user_id)
+ plan_sections.where(:section_id =>section_id, :user_id =>user_id).order("created_at DESC").eachdo|lock|
+ lock.delete
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ warning(option_id)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/plan.rb, line 148
+defwarning(option_id)
+ ifproject.organisation.nil?
+ returnnil
+ else
+ returnproject.organisation.warning(option_id)
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Private Instance Methods
+
+
+
+
+
+ estimate_space_used(used_height)
+ click to toggle source
+
+
+
+
+
+
Based on the height of the text gathered so far and the available vertical
+space of the pdf, estimate a percentage of how much space has been used.
+This is highly dependent on the layout in the pdf. A more accurate approach
+would be to render the pdf and check how much space had been used, but that
+could be very slow. NOTE: This is only an estimate, rounded up to the
+nearest 5%; it is intended for guidance when editing plan data, not to be
+100% accurate.
+
+
+
+
+
# File app/models/plan.rb, line 372
+defestimate_space_used(used_height)
+ @formatting||=self.settings(:export).formatting
+
+ return0unless@formatting[:font_size] >0
+
+ margin_height = @formatting[:margin][:top].to_i+@formatting[:margin][:bottom].to_i
+ page_height = A4_PAGE_HEIGHT-margin_height# 297mm for A4 portrait
+
+ available_height = page_height * self.dmptemplate.settings(:export).max_pages
+
+ percentage = (used_height/available_height) * 100
+ (percentage/ROUNDING).ceil * ROUNDING# round up to nearest five
+
+end
Take a guess at the vertical height (in mm) of the given text based on the
+font-size and left/right margins stored in the plan's settings. This
+assumes a fixed-width for each glyph, which is obviously incorrect for the
+font-face choices available; the idea is that they'll hopefully average
+out to that in the long-run. Allows for hinting different font sizes
+(offset from base via font_size_inc) and vertical margins (i.e. for heading
+text)
# File app/controllers/plans_controller.rb, line 6
+ defedit
+ @plan = Plan.find(params[:id])
+
+
+if!user_signed_in?then
+ respond_todo|format|
+ format.html { redirect_toedit_user_registration_path }
+ end
+ elsif!@plan.readable_by(current_user.id) then
+ respond_todo|format|
+ format.html { redirect_toprojects_url, notice:"This account does not have access to that plan." }
+ end
+ end
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ export()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/plans_controller.rb, line 164
+defexport
+ @plan = Plan.find(params[:id])
+
+ ifuser_signed_in?&&@plan.readable_by(current_user.id) then
+ @exported_plan = ExportedPlan.new.tapdo|ep|
+ ep.plan = @plan
+ ep.user = current_user
+ ep.format = request.format.try(:symbol)
+ plan_settings = @plan.settings(:export)
+
+ Settings::Dmptemplate::DEFAULT_SETTINGS.eachdo|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_todo|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.pdfdo
+ @formatting = @plan.settings(:export).formatting
+ renderpdf: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
+ elsif!user_signed_in?then
+ respond_todo|format|
+ format.html { redirect_toedit_user_registration_path }
+ end
+ elsif!@plan.editable_by(current_user.id) then
+ respond_todo|format|
+ format.html { redirect_toprojects_url, notice:"This account does not have access to that plan." }
+ end
+ end
+end
# File app/models/project.rb, line 77
+definstitution_id
+ iforganisation.nil?
+ returnnil
+ else
+ returnorganisation.root.id
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ institution_id=(new_institution_id)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 71
+definstitution_id=(new_institution_id)
+ iforganisation.nil?then
+ self.organisation_id = new_institution_id
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ last_edited()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 183
+deflast_edited
+ self.latest_update.to_date
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ latest_update()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 164
+deflatest_update
+ latest_update = updated_at
+ plans.eachdo|plan|
+ ifplan.latest_update>latest_updatethen
+ latest_update = plan.latest_update
+ end
+ end
+ returnlatest_update
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ name()
+ click to toggle source
+
+
+
+
+
+
Getters to match 'My plans' columns
+
+
+
+
+
# File app/models/project.rb, line 175
+defname
+ self.title
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ owner()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 179
+defowner
+ self.project_groups.find_by_project_creator(true).try(:user)
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ readable_by(user_id)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 133
+defreadable_by(user_id)
+ user = project_groups.find_by_user_id(user_id)
+ if (!user.nil?) then
+ returntrue
+ else
+ returnfalse
+ end
+end
# File app/models/project_group.rb, line 9
+defemail
+ unlessuser.nil?
+ returnuser.email
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ email=(new_email)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project_group.rb, line 15
+defemail=(new_email)
+ unlessUser.find_by_email(email).nil?then
+ user = User.find_by_email(email)
+ end
+end
# File app/controllers/projects_controller.rb, line 71
+defedit
+ @project = Project.find(params[:id])
+ if!user_signed_in?then
+ respond_todo|format|
+ format.html { redirect_toedit_user_registration_path }
+ end
+ elsif!@project.editable_by(current_user.id) then
+ respond_todo|format|
+ format.html { redirect_toprojects_url, notice:"This account does not have access to that plan." }
+ end
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ export()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/projects_controller.rb, line 97
+defexport
+ @project = Project.find(params[:id])
+ if!user_signed_in?then
+ respond_todo|format|
+ format.html { redirect_toedit_user_registration_path }
+ end
+ else
+ respond_todo|format|
+ format.html { renderaction:"export" }
+
+ end
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ index()
+ click to toggle source
+
+
+
+
+
+
GET /projects GET /projects.json
+
+
+
+
+
# File app/controllers/projects_controller.rb, line 6
+defindex
+ ifuser_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 'link your DMPonline account to your institutional credentials?', user_omniauth_shibboleth_path}".html_safe
+ end
+
+ @projects = current_user.projects.filter(params[:filter])
+ @has_projects = current_user.projects.any?# unfiltered count
+
+
+ respond_todo|format|
+ format.html# index.html.erb
+
+ format.json { renderjson:@projects }
+ end
+ else
+ respond_todo|format|
+ format.html { redirect_toedit_user_registration_path }
+ end
+ end
+end
# File app/controllers/projects_controller.rb, line 213
+defpossible_guidance
+ if!params[:template].nil?&¶ms[:template] !=""&¶ms[:template] !="undefined"then
+ template = Dmptemplate.find(params[:template])
+ else
+ template = nil
+ end
+ if!params[:institution].nil?&¶ms[:institution] !=""&¶ms[:institution] !="undefined"then
+ institution = Organisation.find(params[:institution])
+ else
+ institution = nil
+ end
+ excluded_orgs = orgs_of_type(t('helpers.org_type.funder')) +orgs_of_type(t('helpers.org_type.institution')) +Organisation.orgs_with_parent_of_type(t('helpers.org_type.institution'))
+ guidance_groups = {}
+ ggs = GuidanceGroup.guidance_groups_excluding(excluded_orgs)
+
+ ggs.eachdo|gg|
+ guidance_groups[gg.id] = gg.name
+ end
+
+#subset guidance that belong to the institution
+
+ unlessinstitution.nil?then
+ optional_gg = GuidanceGroup.where("optional_subset = ? && organisation_id = ?", true, institution.id)
+ optional_gg.eachdo|optional|
+ guidance_groups[optional.id] = optional.name
+ end
+
+ institution.children.eachdo|o|
+ o.guidance_groups.eachdo|gg|
+ include = false
+ gg.guidances.eachdo|g|
+ ifg.dmptemplate.nil?||g.dmptemplate_id==template.idthen
+ include = true
+ break
+ end
+ end
+ ifincludethen
+ 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==t('helpers.org_type.funder') then
+ optional_gg = GuidanceGroup.where("optional_subset = ? && organisation_id = ?", true, template.organisation_id)
+ optional_gg.eachdo|optional|
+ guidance_groups[optional.id] = optional.name
+ end
+end
+
+
+ respond_todo|format|
+ format.json { renderjson:guidance_groups.to_json }
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ possible_templates()
+ click to toggle source
+
+
+
+
+
+
GET /projects/possible_templates.json
+
+
+
+
+
# File app/controllers/projects_controller.rb, line 181
+defpossible_templates
+ if!params[:funder].nil?&¶ms[:funder] !=""&¶ms[:funder] !="undefined"then
+ funder = Organisation.find(params[:funder])
+ else
+ funder = nil
+ end
+ if!params[:institution].nil?&¶ms[:institution] !=""&¶ms[:institution] !="undefined"then
+ institution = Organisation.find(params[:institution])
+ else
+ institution = nil
+ end
+ templates = {}
+ unlessfunder.nil?then
+ funder.published_templates.eachdo|t|
+ templates[t.id] = t.title
+ end
+ end
+ iftemplates.count==0&&!institution.nil?then
+ institution.published_templates.eachdo|t|
+ templates[t.id] = t.title
+ end
+ institution.children.eachdo|o|
+ o.published_templates.eachdo|t|
+ templates[t.id] = t.title
+ end
+ end
+ end
+ respond_todo|format|
+ format.json { renderjson:templates.to_json }
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ share()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/projects_controller.rb, line 84
+defshare
+ @project = Project.find(params[:id])
+ if!user_signed_in?then
+ respond_todo|format|
+ format.html { redirect_toedit_user_registration_path }
+ end
+ elsif!@project.editable_by(current_user.id) then
+ respond_todo|format|
+ format.html { redirect_toprojects_url, notice:"This account does not have access to that plan." }
+ end
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ show()
+ click to toggle source
+
+
+
+
+
+
GET /projects/1 GET /projects/1.json
+
+
+
+
+
# File app/controllers/projects_controller.rb, line 28
+defshow
+ @project = Project.find(params[:id])
+ @show_form = false
+ ifparams[:show_form] =="yes"then
+ @show_form = true
+ end
+ ifuser_signed_in?&&@project.readable_by(current_user.id) then
+ respond_todo|format|
+ format.html# show.html.erb
+
+ format.json { renderjson:@project }
+ end
+ elsifuser_signed_in?then
+ respond_todo|format|
+ format.html { redirect_toprojects_url, notice:"This account does not have access to that plan." }
+ end
+ else
+ respond_todo|format|
+ format.html { redirect_toedit_user_registration_path }
+ end
+ end
+end
+ guidance_for_question(question, org_admin)
+ click to toggle source
+
+
+
+
+
+
guidance for question in the org admin
+
+
+
+
+
# File app/models/question.rb, line 69
+defguidance_for_question(question, org_admin)
+# pulls together guidance from various sources for question
+
+guidances = {}
+theme_ids = question.theme_ids
+
+GuidanceGroup.where("organisation_id = ?", org_admin.id).eachdo|group|
+ group.guidances.eachdo|g|
+ g.themes.where("id IN (?)", theme_ids).eachdo|gg|
+ guidances["#{group.name} guidance on #{gg.title}"] = g
+ end
+ end
+end
+
+ # Guidance link to directly to a question
+
+question.guidances.eachdo|g_by_q|
+ g_by_q.guidance_groups.eachdo|group|
+ ifgroup.organisation==org_admin
+ guidances["#{group.name} guidance for this question"] = g_by_q
+ end
+ end
+ end
+
+ returnguidances
+end
DMPonline is the DCC's data management planning tool, available at dmponline.dcc.ac.uk
+
+
Development of the DMPonline by the Digital Curation Centre has been funded
+by JISC. JISC inspires UK colleges and universities in the innovative use
+of digital technologies, helping to maintain the UK's position as a
+global leader in education. www.jisc.ac.uk
+
+
This is just the application code, the accompanying question data available
+at dmponline.dcc.ac.uk is not
+included.
+
+
The tool has four main functions
+
+
To help create and maintain different versions of Data Management Plans;
+
+
To provide useful guidance on data management issues and how to meet
+research funders' requirements;
+
+
To export attractive and useful plans in a variety of formats;
+
+
To allow collaborative work when creating Data Management Plans.
+
+
+
Documentation & Support
+
+
You can contact us by email, dmponline@dcc.ac.uk, but we can only provide
+limited support for your installation
DMPonline is a Ruby on Rails application and you will need to have Ruby
+2.0.0p247 or greater installed on your server and a MySQL server v5.0 or
+greater.
+
+
Further details on how to install Ruby on Rails applications are available
+from the Ruby on Rails site, rubyonrails.org
This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+
This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+for more details.
+
+
You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see www.gnu.org/licenses.
# File app/controllers/settings/projects_controller.rb, line 29
+defget_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
+ sharing_notification(project_group)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/mailers/user_mailer.rb, line 4
+defsharing_notification(project_group)
+ @project_group = project_group
+ mail(to:@project_group.user.email, subject:"You have been given access to a Data Management Plan")
+end
# File app/controllers/users/omniauth_shibboleth_request_controller.rb, line 17
+defassociate
+ # This action is protected - can only be reached if user is already logged in.
+
+ # See before_filter
+
+ redirect_touser_omniauth_callback_path(:shibboleth)
+end
DMPonline is the DCC's data management planning tool, available at dmponline.dcc.ac.uk
+
+
Development of the DMPonline by the Digital Curation Centre has been funded
+by JISC. JISC inspires UK colleges and universities in the innovative use
+of digital technologies, helping to maintain the UK's position as a
+global leader in education. www.jisc.ac.uk
+
+
This is just the application code, the accompanying question data available
+at dmponline.dcc.ac.uk is not
+included.
+
+
The tool has four main functions
+
+
To help create and maintain different versions of Data Management Plans;
+
+
To provide useful guidance on data management issues and how to meet
+research funders' requirements;
+
+
To export attractive and useful plans in a variety of formats;
+
+
To allow collaborative work when creating Data Management Plans.
+
+
+
Documentation & Support
+
+
You can contact us by email, dmponline@dcc.ac.uk, but we can only provide
+limited support for your installation
DMPonline is a Ruby on Rails application and you will need to have Ruby
+2.0.0p247 or greater installed on your server and a MySQL server v5.0 or
+greater.
+
+
Further details on how to install Ruby on Rails applications are available
+from the Ruby on Rails site, rubyonrails.org
This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+
This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+for more details.
+
+
You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see www.gnu.org/licenses.
+
+
+
+
+
+
diff --git a/public/html/js/darkfish.js b/public/html/js/darkfish.js
new file mode 100644
index 0000000..92d8280
--- /dev/null
+++ b/public/html/js/darkfish.js
@@ -0,0 +1,155 @@
+/**
+ *
+ * Darkfish Page Functions
+ * $Id: darkfish.js 53 2009-01-07 02:52:03Z deveiant $
+ *
+ * Author: Michael Granger
+ *
+ */
+
+/* Provide console simulation for firebug-less environments */
+if (!("console" in window) || !("firebug" in console)) {
+ var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
+ "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
+
+ window.console = {};
+ for (var i = 0; i < names.length; ++i)
+ window.console[names[i]] = function() {};
+};
+
+
+/**
+ * Unwrap the first element that matches the given @expr@ from the targets and return them.
+ */
+$.fn.unwrap = function( expr ) {
+ return this.each( function() {
+ $(this).parents( expr ).eq( 0 ).after( this ).remove();
+ });
+};
+
+
+function showSource( e ) {
+ var target = e.target;
+ var codeSections = $(target).
+ parents('.method-detail').
+ find('.method-source-code');
+
+ $(target).
+ parents('.method-detail').
+ find('.method-source-code').
+ slideToggle();
+};
+
+function hookSourceViews() {
+ $('.method-heading').click( showSource );
+};
+
+function toggleDebuggingSection() {
+ $('.debugging-section').slideToggle();
+};
+
+function hookDebuggingToggle() {
+ $('#debugging-toggle img').click( toggleDebuggingSection );
+};
+
+function hookTableOfContentsToggle() {
+ $('.indexpage li .toc-toggle').each( function() {
+ $(this).click( function() {
+ $(this).toggleClass('open');
+ });
+
+ var section = $(this).next();
+
+ $(this).click( function() {
+ section.slideToggle();
+ });
+ });
+}
+
+function hookSearch() {
+ var input = $('#search-field').eq(0);
+ var result = $('#search-results').eq(0);
+ $(result).show();
+
+ var search_section = $('#search-section').get(0);
+ $(search_section).show();
+
+ var search = new Search(search_data, input, result);
+
+ search.renderItem = function(result) {
+ var li = document.createElement('li');
+ var html = '';
+
+ // TODO add relative path to
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/i18n.js b/public/i18n.js
new file mode 100644
index 0000000..9797f5b
--- /dev/null
+++ b/public/i18n.js
@@ -0,0 +1,934 @@
+// I18n.js
+// =======
+//
+// This small library provides the Rails I18n API on the Javascript.
+// You don't actually have to use Rails (or even Ruby) to use I18n.js.
+// Just make sure you export all translations in an object like this:
+//
+// I18n.translations.en = {
+// hello: "Hello World"
+// };
+//
+// See tests for specific formatting like numbers and dates.
+//
+
+;(function(factory) {
+ if (typeof module !== 'undefined' && module.exports) {
+ // Node/CommonJS
+ module.exports = factory(this);
+ } else if (typeof define === 'function' && define.amd) {
+ // AMD
+ var global=this;
+ define('i18n', function(){ return factory(global);});
+ } else {
+ // Browser globals
+ this.I18n = factory(this);
+ }
+}(function(global) {
+ "use strict";
+
+ // Use previously defined object if exists in current scope
+ var I18n = global && global.I18n || {};
+
+ // Just cache the Array#slice function.
+ var slice = Array.prototype.slice;
+
+ // Apply number padding.
+ var padding = function(number) {
+ return ("0" + number.toString()).substr(-2);
+ };
+
+ // Improved toFixed number rounding function with support for unprecise floating points
+ // JavaScript's standard toFixed function does not round certain numbers correctly (for example 0.105 with precision 2).
+ var toFixed = function(number, precision) {
+ return decimalAdjust('round', number, -precision).toFixed(precision);
+ };
+
+ // Is a given variable an object?
+ // Borrowed from Underscore.js
+ var isObject = function(obj) {
+ var type = typeof obj;
+ return type === 'function' || type === 'object' && !!obj;
+ };
+
+ // Is a given value an array?
+ // Borrowed from Underscore.js
+ var isArray = function(obj) {
+ if (Array.isArray) {
+ return Array.isArray(obj);
+ };
+ return Object.prototype.toString.call(obj) === '[object Array]';
+ };
+
+ var decimalAdjust = function(type, value, exp) {
+ // If the exp is undefined or zero...
+ if (typeof exp === 'undefined' || +exp === 0) {
+ return Math[type](value);
+ }
+ value = +value;
+ exp = +exp;
+ // If the value is not a number or the exp is not an integer...
+ if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
+ return NaN;
+ }
+ // Shift
+ value = value.toString().split('e');
+ value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
+ // Shift back
+ value = value.toString().split('e');
+ return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
+ }
+
+ // Set default days/months translations.
+ var DATE = {
+ day_names: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
+ , abbr_day_names: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
+ , month_names: [null, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
+ , abbr_month_names: [null, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
+ , meridian: ["AM", "PM"]
+ };
+
+ // Set default number format.
+ var NUMBER_FORMAT = {
+ precision: 3
+ , separator: "."
+ , delimiter: ","
+ , strip_insignificant_zeros: false
+ };
+
+ // Set default currency format.
+ var CURRENCY_FORMAT = {
+ unit: "$"
+ , precision: 2
+ , format: "%u%n"
+ , sign_first: true
+ , delimiter: ","
+ , separator: "."
+ };
+
+ // Set default percentage format.
+ var PERCENTAGE_FORMAT = {
+ unit: "%"
+ , precision: 3
+ , format: "%n%u"
+ , separator: "."
+ , delimiter: ""
+ };
+
+ // Set default size units.
+ var SIZE_UNITS = [null, "kb", "mb", "gb", "tb"];
+
+ // Other default options
+ var DEFAULT_OPTIONS = {
+ // Set default locale. This locale will be used when fallback is enabled and
+ // the translation doesn't exist in a particular locale.
+ defaultLocale: "en"
+ // Set the current locale to `en`.
+ , locale: "en"
+ // Set the translation key separator.
+ , defaultSeparator: "."
+ // Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
+ , placeholder: /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm
+ // Set if engine should fallback to the default locale when a translation
+ // is missing.
+ , fallbacks: false
+ // Set the default translation object.
+ , translations: {}
+ // Set missing translation behavior. 'message' will display a message
+ // that the translation is missing, 'guess' will try to guess the string
+ , missingBehaviour: 'message'
+ // if you use missingBehaviour with 'message', but want to know that the
+ // string is actually missing for testing purposes, you can prefix the
+ // guessed string by setting the value here. By default, no prefix!
+ , missingTranslationPrefix: ''
+ };
+
+ I18n.reset = function() {
+ // Set default locale. This locale will be used when fallback is enabled and
+ // the translation doesn't exist in a particular locale.
+ this.defaultLocale = DEFAULT_OPTIONS.defaultLocale;
+
+ // Set the current locale to `en`.
+ this.locale = DEFAULT_OPTIONS.locale;
+
+ // Set the translation key separator.
+ this.defaultSeparator = DEFAULT_OPTIONS.defaultSeparator;
+
+ // Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
+ this.placeholder = DEFAULT_OPTIONS.placeholder;
+
+ // Set if engine should fallback to the default locale when a translation
+ // is missing.
+ this.fallbacks = DEFAULT_OPTIONS.fallbacks;
+
+ // Set the default translation object.
+ this.translations = DEFAULT_OPTIONS.translations;
+
+ // Set the default missing behaviour
+ this.missingBehaviour = DEFAULT_OPTIONS.missingBehaviour;
+
+ // Set the default missing string prefix for guess behaviour
+ this.missingTranslationPrefix = DEFAULT_OPTIONS.missingTranslationPrefix;
+
+ };
+
+ // Much like `reset`, but only assign options if not already assigned
+ I18n.initializeOptions = function() {
+ if (typeof(this.defaultLocale) === "undefined" && this.defaultLocale !== null)
+ this.defaultLocale = DEFAULT_OPTIONS.defaultLocale;
+
+ if (typeof(this.locale) === "undefined" && this.locale !== null)
+ this.locale = DEFAULT_OPTIONS.locale;
+
+ if (typeof(this.defaultSeparator) === "undefined" && this.defaultSeparator !== null)
+ this.defaultSeparator = DEFAULT_OPTIONS.defaultSeparator;
+
+ if (typeof(this.placeholder) === "undefined" && this.placeholder !== null)
+ this.placeholder = DEFAULT_OPTIONS.placeholder;
+
+ if (typeof(this.fallbacks) === "undefined" && this.fallbacks !== null)
+ this.fallbacks = DEFAULT_OPTIONS.fallbacks;
+
+ if (typeof(this.translations) === "undefined" && this.translations !== null)
+ this.translations = DEFAULT_OPTIONS.translations;
+ };
+ I18n.initializeOptions();
+
+ // Return a list of all locales that must be tried before returning the
+ // missing translation message. By default, this will consider the inline option,
+ // current locale and fallback locale.
+ //
+ // I18n.locales.get("de-DE");
+ // // ["de-DE", "de", "en"]
+ //
+ // You can define custom rules for any locale. Just make sure you return a array
+ // containing all locales.
+ //
+ // // Default the Wookie locale to English.
+ // I18n.locales["wk"] = function(locale) {
+ // return ["en"];
+ // };
+ //
+ I18n.locales = {};
+
+ // Retrieve locales based on inline locale, current locale or default to
+ // I18n's detection.
+ I18n.locales.get = function(locale) {
+ var result = this[locale] || this[I18n.locale] || this["default"];
+
+ if (typeof(result) === "function") {
+ result = result(locale);
+ }
+
+ if (isArray(result) === false) {
+ result = [result];
+ }
+
+ return result;
+ };
+
+ // The default locale list.
+ I18n.locales["default"] = function(locale) {
+ var locales = []
+ , list = []
+ , countryCode
+ , count
+ ;
+
+ // Handle the inline locale option that can be provided to
+ // the `I18n.t` options.
+ if (locale) {
+ locales.push(locale);
+ }
+
+ // Add the current locale to the list.
+ if (!locale && I18n.locale) {
+ locales.push(I18n.locale);
+ }
+
+ // Add the default locale if fallback strategy is enabled.
+ if (I18n.fallbacks && I18n.defaultLocale) {
+ locales.push(I18n.defaultLocale);
+ }
+
+ // Compute each locale with its country code.
+ // So this will return an array containing both
+ // `de-DE` and `de` locales.
+ locales.forEach(function(locale){
+ countryCode = locale.split("-")[0];
+
+ if (!~list.indexOf(locale)) {
+ list.push(locale);
+ }
+
+ if (I18n.fallbacks && countryCode && countryCode !== locale && !~list.indexOf(countryCode)) {
+ list.push(countryCode);
+ }
+ });
+
+ // No locales set? English it is.
+ if (!locales.length) {
+ locales.push("en");
+ }
+
+ return list;
+ };
+
+ // Hold pluralization rules.
+ I18n.pluralization = {};
+
+ // Return the pluralizer for a specific locale.
+ // If no specify locale is found, then I18n's default will be used.
+ I18n.pluralization.get = function(locale) {
+ return this[locale] || this[I18n.locale] || this["default"];
+ };
+
+ // The default pluralizer rule.
+ // It detects the `zero`, `one`, and `other` scopes.
+ I18n.pluralization["default"] = function(count) {
+ switch (count) {
+ case 0: return ["zero", "other"];
+ case 1: return ["one"];
+ default: return ["other"];
+ }
+ };
+
+ // Return current locale. If no locale has been set, then
+ // the current locale will be the default locale.
+ I18n.currentLocale = function() {
+ return this.locale || this.defaultLocale;
+ };
+
+ // Check if value is different than undefined and null;
+ I18n.isSet = function(value) {
+ return value !== undefined && value !== null;
+ };
+
+ // Find and process the translation using the provided scope and options.
+ // This is used internally by some functions and should not be used as an
+ // public API.
+ I18n.lookup = function(scope, options) {
+ options = this.prepareOptions(options);
+
+ var locales = this.locales.get(options.locale).slice()
+ , requestedLocale = locales[0]
+ , locale
+ , scopes
+ , translations
+ ;
+
+ scope = this.getFullScope(scope, options);
+
+ while (locales.length) {
+ locale = locales.shift();
+ scopes = scope.split(this.defaultSeparator);
+ translations = this.translations[locale];
+
+ if (!translations) {
+ continue;
+ }
+
+ while (scopes.length) {
+ translations = translations[scopes.shift()];
+
+ if (translations === undefined || translations === null) {
+ break;
+ }
+ }
+
+ if (translations !== undefined && translations !== null) {
+ return translations;
+ }
+ }
+
+ if (this.isSet(options.defaultValue)) {
+ return options.defaultValue;
+ }
+ };
+
+ // Rails changed the way the meridian is stored.
+ // It started with `date.meridian` returning an array,
+ // then it switched to `time.am` and `time.pm`.
+ // This function abstracts this difference and returns
+ // the correct meridian or the default value when none is provided.
+ I18n.meridian = function() {
+ var time = this.lookup("time");
+ var date = this.lookup("date");
+
+ if (time && time.am && time.pm) {
+ return [time.am, time.pm];
+ } else if (date && date.meridian) {
+ return date.meridian;
+ } else {
+ return DATE.meridian;
+ }
+ };
+
+ // Merge serveral hash options, checking if value is set before
+ // overwriting any value. The precedence is from left to right.
+ //
+ // I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"});
+ // #=> {name: "John Doe", role: "user"}
+ //
+ I18n.prepareOptions = function() {
+ var args = slice.call(arguments)
+ , options = {}
+ , subject
+ ;
+
+ while (args.length) {
+ subject = args.shift();
+
+ if (typeof(subject) != "object") {
+ continue;
+ }
+
+ for (var attr in subject) {
+ if (!subject.hasOwnProperty(attr)) {
+ continue;
+ }
+
+ if (this.isSet(options[attr])) {
+ continue;
+ }
+
+ options[attr] = subject[attr];
+ }
+ }
+
+ return options;
+ };
+
+ // Generate a list of translation options for default fallbacks.
+ // `defaultValue` is also deleted from options as it is returned as part of
+ // the translationOptions array.
+ I18n.createTranslationOptions = function(scope, options) {
+ var translationOptions = [{scope: scope}];
+
+ // Defaults should be an array of hashes containing either
+ // fallback scopes or messages
+ if (this.isSet(options.defaults)) {
+ translationOptions = translationOptions.concat(options.defaults);
+ }
+
+ // Maintain support for defaultValue. Since it is always a message
+ // insert it in to the translation options as such.
+ if (this.isSet(options.defaultValue)) {
+ translationOptions.push({ message: options.defaultValue });
+ delete options.defaultValue;
+ }
+
+ return translationOptions;
+ };
+
+ // Translate the given scope with the provided options.
+ I18n.translate = function(scope, options) {
+ options = this.prepareOptions(options);
+
+ var translationOptions = this.createTranslationOptions(scope, options);
+
+ var translation;
+ // Iterate through the translation options until a translation
+ // or message is found.
+ var translationFound =
+ translationOptions.some(function(translationOption) {
+ if (this.isSet(translationOption.scope)) {
+ translation = this.lookup(translationOption.scope, options);
+ } else if (this.isSet(translationOption.message)) {
+ translation = translationOption.message;
+ }
+
+ if (translation !== undefined && translation !== null) {
+ return true;
+ }
+ }, this);
+
+ if (!translationFound) {
+ return this.missingTranslation(scope, options);
+ }
+
+ if (typeof(translation) === "string") {
+ translation = this.interpolate(translation, options);
+ } else if (isObject(translation) && this.isSet(options.count)) {
+ translation = this.pluralize(options.count, translation, options);
+ }
+
+ return translation;
+ };
+
+ // This function interpolates the all variables in the given message.
+ I18n.interpolate = function(message, options) {
+ options = this.prepareOptions(options);
+ var matches = message.match(this.placeholder)
+ , placeholder
+ , value
+ , name
+ , regex
+ ;
+
+ if (!matches) {
+ return message;
+ }
+
+ var value;
+
+ while (matches.length) {
+ placeholder = matches.shift();
+ name = placeholder.replace(this.placeholder, "$1");
+
+ if (this.isSet(options[name])) {
+ value = options[name].toString().replace(/\$/gm, "_#$#_");
+ } else if (name in options) {
+ value = this.nullPlaceholder(placeholder, message, options);
+ } else {
+ value = this.missingPlaceholder(placeholder, message, options);
+ }
+
+ regex = new RegExp(placeholder.replace(/\{/gm, "\\{").replace(/\}/gm, "\\}"));
+ message = message.replace(regex, value);
+ }
+
+ return message.replace(/_#\$#_/g, "$");
+ };
+
+ // Pluralize the given scope using the `count` value.
+ // The pluralized translation may have other placeholders,
+ // which will be retrieved from `options`.
+ I18n.pluralize = function(count, scope, options) {
+ options = this.prepareOptions(options);
+ var translations, pluralizer, keys, key, message;
+
+ if (isObject(scope)) {
+ translations = scope;
+ } else {
+ translations = this.lookup(scope, options);
+ }
+
+ if (!translations) {
+ return this.missingTranslation(scope, options);
+ }
+
+ pluralizer = this.pluralization.get(options.locale);
+ keys = pluralizer(count);
+
+ while (keys.length) {
+ key = keys.shift();
+
+ if (this.isSet(translations[key])) {
+ message = translations[key];
+ break;
+ }
+ }
+
+ options.count = String(count);
+ return this.interpolate(message, options);
+ };
+
+ // Return a missing translation message for the given parameters.
+ I18n.missingTranslation = function(scope, options) {
+ //guess intended string
+ if(this.missingBehaviour == 'guess'){
+ //get only the last portion of the scope
+ var s = scope.split('.').slice(-1)[0];
+ //replace underscore with space && camelcase with space and lowercase letter
+ return (this.missingTranslationPrefix.length > 0 ? this.missingTranslationPrefix : '') +
+ s.replace('_',' ').replace(/([a-z])([A-Z])/g,
+ function(match, p1, p2) {return p1 + ' ' + p2.toLowerCase()} );
+ }
+
+ var fullScope = this.getFullScope(scope, options);
+ var fullScopeWithLocale = [this.currentLocale(), fullScope].join(this.defaultSeparator);
+
+ return '[missing "' + fullScopeWithLocale + '" translation]';
+ };
+
+ // Return a missing placeholder message for given parameters
+ I18n.missingPlaceholder = function(placeholder, message, options) {
+ return "[missing " + placeholder + " value]";
+ };
+
+ I18n.nullPlaceholder = function() {
+ return I18n.missingPlaceholder.apply(I18n, arguments);
+ };
+
+ // Format number using localization rules.
+ // The options will be retrieved from the `number.format` scope.
+ // If this isn't present, then the following options will be used:
+ //
+ // - `precision`: `3`
+ // - `separator`: `"."`
+ // - `delimiter`: `","`
+ // - `strip_insignificant_zeros`: `false`
+ //
+ // You can also override these options by providing the `options` argument.
+ //
+ I18n.toNumber = function(number, options) {
+ options = this.prepareOptions(
+ options
+ , this.lookup("number.format")
+ , NUMBER_FORMAT
+ );
+
+ var negative = number < 0
+ , string = toFixed(Math.abs(number), options.precision).toString()
+ , parts = string.split(".")
+ , precision
+ , buffer = []
+ , formattedNumber
+ , format = options.format || "%n"
+ , sign = negative ? "-" : ""
+ ;
+
+ number = parts[0];
+ precision = parts[1];
+
+ while (number.length > 0) {
+ buffer.unshift(number.substr(Math.max(0, number.length - 3), 3));
+ number = number.substr(0, number.length -3);
+ }
+
+ formattedNumber = buffer.join(options.delimiter);
+
+ if (options.strip_insignificant_zeros && precision) {
+ precision = precision.replace(/0+$/, "");
+ }
+
+ if (options.precision > 0 && precision) {
+ formattedNumber += options.separator + precision;
+ }
+
+ if (options.sign_first) {
+ format = "%s" + format;
+ }
+ else {
+ format = format.replace("%n", "%s%n");
+ }
+
+ formattedNumber = format
+ .replace("%u", options.unit)
+ .replace("%n", formattedNumber)
+ .replace("%s", sign)
+ ;
+
+ return formattedNumber;
+ };
+
+ // Format currency with localization rules.
+ // The options will be retrieved from the `number.currency.format` and
+ // `number.format` scopes, in that order.
+ //
+ // Any missing option will be retrieved from the `I18n.toNumber` defaults and
+ // the following options:
+ //
+ // - `unit`: `"$"`
+ // - `precision`: `2`
+ // - `format`: `"%u%n"`
+ // - `delimiter`: `","`
+ // - `separator`: `"."`
+ //
+ // You can also override these options by providing the `options` argument.
+ //
+ I18n.toCurrency = function(number, options) {
+ options = this.prepareOptions(
+ options
+ , this.lookup("number.currency.format")
+ , this.lookup("number.format")
+ , CURRENCY_FORMAT
+ );
+
+ return this.toNumber(number, options);
+ };
+
+ // Localize several values.
+ // You can provide the following scopes: `currency`, `number`, or `percentage`.
+ // If you provide a scope that matches the `/^(date|time)/` regular expression
+ // then the `value` will be converted by using the `I18n.toTime` function.
+ //
+ // It will default to the value's `toString` function.
+ //
+ I18n.localize = function(scope, value, options) {
+ options || (options = {});
+
+ switch (scope) {
+ case "currency":
+ return this.toCurrency(value);
+ case "number":
+ scope = this.lookup("number.format");
+ return this.toNumber(value, scope);
+ case "percentage":
+ return this.toPercentage(value);
+ default:
+ var localizedValue;
+
+ if (scope.match(/^(date|time)/)) {
+ localizedValue = this.toTime(scope, value);
+ } else {
+ localizedValue = value.toString();
+ }
+
+ return this.interpolate(localizedValue, options);
+ }
+ };
+
+ // Parse a given `date` string into a JavaScript Date object.
+ // This function is time zone aware.
+ //
+ // The following string formats are recognized:
+ //
+ // yyyy-mm-dd
+ // yyyy-mm-dd[ T]hh:mm::ss
+ // yyyy-mm-dd[ T]hh:mm::ss
+ // yyyy-mm-dd[ T]hh:mm::ssZ
+ // yyyy-mm-dd[ T]hh:mm::ss+0000
+ // yyyy-mm-dd[ T]hh:mm::ss+00:00
+ // yyyy-mm-dd[ T]hh:mm::ss.123Z
+ //
+ I18n.parseDate = function(date) {
+ var matches, convertedDate, fraction;
+ // we have a date, so just return it.
+ if (typeof(date) == "object") {
+ return date;
+ };
+
+ matches = date.toString().match(/(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2})([\.,]\d{1,3})?)?(Z|\+00:?00)?/);
+
+ if (matches) {
+ for (var i = 1; i <= 6; i++) {
+ matches[i] = parseInt(matches[i], 10) || 0;
+ }
+
+ // month starts on 0
+ matches[2] -= 1;
+
+ fraction = matches[7] ? 1000 * ("0" + matches[7]) : null;
+
+ if (matches[8]) {
+ convertedDate = new Date(Date.UTC(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], fraction));
+ } else {
+ convertedDate = new Date(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], fraction);
+ }
+ } else if (typeof(date) == "number") {
+ // UNIX timestamp
+ convertedDate = new Date();
+ convertedDate.setTime(date);
+ } else if (date.match(/([A-Z][a-z]{2}) ([A-Z][a-z]{2}) (\d+) (\d+:\d+:\d+) ([+-]\d+) (\d+)/)) {
+ // This format `Wed Jul 20 13:03:39 +0000 2011` is parsed by
+ // webkit/firefox, but not by IE, so we must parse it manually.
+ convertedDate = new Date();
+ convertedDate.setTime(Date.parse([
+ RegExp.$1, RegExp.$2, RegExp.$3, RegExp.$6, RegExp.$4, RegExp.$5
+ ].join(" ")));
+ } else if (date.match(/\d+ \d+:\d+:\d+ [+-]\d+ \d+/)) {
+ // a valid javascript format with timezone info
+ convertedDate = new Date();
+ convertedDate.setTime(Date.parse(date));
+ } else {
+ // an arbitrary javascript string
+ convertedDate = new Date();
+ convertedDate.setTime(Date.parse(date));
+ }
+
+ return convertedDate;
+ };
+
+ // Formats time according to the directives in the given format string.
+ // The directives begins with a percent (%) character. Any text not listed as a
+ // directive will be passed through to the output string.
+ //
+ // The accepted formats are:
+ //
+ // %a - The abbreviated weekday name (Sun)
+ // %A - The full weekday name (Sunday)
+ // %b - The abbreviated month name (Jan)
+ // %B - The full month name (January)
+ // %c - The preferred local date and time representation
+ // %d - Day of the month (01..31)
+ // %-d - Day of the month (1..31)
+ // %H - Hour of the day, 24-hour clock (00..23)
+ // %-H - Hour of the day, 24-hour clock (0..23)
+ // %I - Hour of the day, 12-hour clock (01..12)
+ // %-I - Hour of the day, 12-hour clock (1..12)
+ // %m - Month of the year (01..12)
+ // %-m - Month of the year (1..12)
+ // %M - Minute of the hour (00..59)
+ // %-M - Minute of the hour (0..59)
+ // %p - Meridian indicator (AM or PM)
+ // %S - Second of the minute (00..60)
+ // %-S - Second of the minute (0..60)
+ // %w - Day of the week (Sunday is 0, 0..6)
+ // %y - Year without a century (00..99)
+ // %-y - Year without a century (0..99)
+ // %Y - Year with century
+ // %z - Timezone offset (+0545)
+ //
+ I18n.strftime = function(date, format) {
+ var options = this.lookup("date")
+ , meridianOptions = I18n.meridian()
+ ;
+
+ if (!options) {
+ options = {};
+ }
+
+ options = this.prepareOptions(options, DATE);
+
+ var weekDay = date.getDay()
+ , day = date.getDate()
+ , year = date.getFullYear()
+ , month = date.getMonth() + 1
+ , hour = date.getHours()
+ , hour12 = hour
+ , meridian = hour > 11 ? 1 : 0
+ , secs = date.getSeconds()
+ , mins = date.getMinutes()
+ , offset = date.getTimezoneOffset()
+ , absOffsetHours = Math.floor(Math.abs(offset / 60))
+ , absOffsetMinutes = Math.abs(offset) - (absOffsetHours * 60)
+ , timezoneoffset = (offset > 0 ? "-" : "+") +
+ (absOffsetHours.toString().length < 2 ? "0" + absOffsetHours : absOffsetHours) +
+ (absOffsetMinutes.toString().length < 2 ? "0" + absOffsetMinutes : absOffsetMinutes)
+ ;
+
+ if (hour12 > 12) {
+ hour12 = hour12 - 12;
+ } else if (hour12 === 0) {
+ hour12 = 12;
+ }
+
+ format = format.replace("%a", options.abbr_day_names[weekDay]);
+ format = format.replace("%A", options.day_names[weekDay]);
+ format = format.replace("%b", options.abbr_month_names[month]);
+ format = format.replace("%B", options.month_names[month]);
+ format = format.replace("%d", padding(day));
+ format = format.replace("%e", day);
+ format = format.replace("%-d", day);
+ format = format.replace("%H", padding(hour));
+ format = format.replace("%-H", hour);
+ format = format.replace("%I", padding(hour12));
+ format = format.replace("%-I", hour12);
+ format = format.replace("%m", padding(month));
+ format = format.replace("%-m", month);
+ format = format.replace("%M", padding(mins));
+ format = format.replace("%-M", mins);
+ format = format.replace("%p", meridianOptions[meridian]);
+ format = format.replace("%S", padding(secs));
+ format = format.replace("%-S", secs);
+ format = format.replace("%w", weekDay);
+ format = format.replace("%y", padding(year));
+ format = format.replace("%-y", padding(year).replace(/^0+/, ""));
+ format = format.replace("%Y", year);
+ format = format.replace("%z", timezoneoffset);
+
+ return format;
+ };
+
+ // Convert the given dateString into a formatted date.
+ I18n.toTime = function(scope, dateString) {
+ var date = this.parseDate(dateString)
+ , format = this.lookup(scope)
+ ;
+
+ if (date.toString().match(/invalid/i)) {
+ return date.toString();
+ }
+
+ if (!format) {
+ return date.toString();
+ }
+
+ return this.strftime(date, format);
+ };
+
+ // Convert a number into a formatted percentage value.
+ I18n.toPercentage = function(number, options) {
+ options = this.prepareOptions(
+ options
+ , this.lookup("number.percentage.format")
+ , this.lookup("number.format")
+ , PERCENTAGE_FORMAT
+ );
+
+ return this.toNumber(number, options);
+ };
+
+ // Convert a number into a readable size representation.
+ I18n.toHumanSize = function(number, options) {
+ var kb = 1024
+ , size = number
+ , iterations = 0
+ , unit
+ , precision
+ ;
+
+ while (size >= kb && iterations < 4) {
+ size = size / kb;
+ iterations += 1;
+ }
+
+ if (iterations === 0) {
+ unit = this.t("number.human.storage_units.units.byte", {count: size});
+ precision = 0;
+ } else {
+ unit = this.t("number.human.storage_units.units." + SIZE_UNITS[iterations]);
+ precision = (size - Math.floor(size) === 0) ? 0 : 1;
+ }
+
+ options = this.prepareOptions(
+ options
+ , {unit: unit, precision: precision, format: "%n%u", delimiter: ""}
+ );
+
+ return this.toNumber(size, options);
+ };
+
+ I18n.getFullScope = function(scope, options) {
+ options = this.prepareOptions(options);
+
+ // Deal with the scope as an array.
+ if (scope.constructor === Array) {
+ scope = scope.join(this.defaultSeparator);
+ }
+
+ // Deal with the scope option provided through the second argument.
+ //
+ // I18n.t('hello', {scope: 'greetings'});
+ //
+ if (options.scope) {
+ scope = [options.scope, scope].join(this.defaultSeparator);
+ }
+
+ return scope;
+ };
+ /**
+ * Merge obj1 with obj2 (shallow merge), without modifying inputs
+ * @param {Object} obj1
+ * @param {Object} obj2
+ * @returns {Object} Merged values of obj1 and obj2
+ *
+ * In order to support ES3, `Object.prototype.hasOwnProperty.call` is used
+ * Idea is from:
+ * https://stackoverflow.com/questions/8157700/object-has-no-hasownproperty-method-i-e-its-undefined-ie8
+ */
+ I18n.extend = function ( obj1, obj2 ) {
+ var extended = {};
+ var prop;
+ for (prop in obj1) {
+ if (Object.prototype.hasOwnProperty.call(obj1, prop)) {
+ extended[prop] = obj1[prop];
+ }
+ }
+ for (prop in obj2) {
+ if (Object.prototype.hasOwnProperty.call(obj2, prop)) {
+ extended[prop] = obj2[prop];
+ }
+ }
+ return extended;
+ };
+
+ // Set aliases, so we can save some typing.
+ I18n.t = I18n.translate;
+ I18n.l = I18n.localize;
+ I18n.p = I18n.pluralize;
+
+ return I18n;
+}));
diff --git a/public/javascripts/i18n.js b/public/javascripts/i18n.js
deleted file mode 100644
index 9797f5b..0000000
--- a/public/javascripts/i18n.js
+++ /dev/null
@@ -1,934 +0,0 @@
-// I18n.js
-// =======
-//
-// This small library provides the Rails I18n API on the Javascript.
-// You don't actually have to use Rails (or even Ruby) to use I18n.js.
-// Just make sure you export all translations in an object like this:
-//
-// I18n.translations.en = {
-// hello: "Hello World"
-// };
-//
-// See tests for specific formatting like numbers and dates.
-//
-
-;(function(factory) {
- if (typeof module !== 'undefined' && module.exports) {
- // Node/CommonJS
- module.exports = factory(this);
- } else if (typeof define === 'function' && define.amd) {
- // AMD
- var global=this;
- define('i18n', function(){ return factory(global);});
- } else {
- // Browser globals
- this.I18n = factory(this);
- }
-}(function(global) {
- "use strict";
-
- // Use previously defined object if exists in current scope
- var I18n = global && global.I18n || {};
-
- // Just cache the Array#slice function.
- var slice = Array.prototype.slice;
-
- // Apply number padding.
- var padding = function(number) {
- return ("0" + number.toString()).substr(-2);
- };
-
- // Improved toFixed number rounding function with support for unprecise floating points
- // JavaScript's standard toFixed function does not round certain numbers correctly (for example 0.105 with precision 2).
- var toFixed = function(number, precision) {
- return decimalAdjust('round', number, -precision).toFixed(precision);
- };
-
- // Is a given variable an object?
- // Borrowed from Underscore.js
- var isObject = function(obj) {
- var type = typeof obj;
- return type === 'function' || type === 'object' && !!obj;
- };
-
- // Is a given value an array?
- // Borrowed from Underscore.js
- var isArray = function(obj) {
- if (Array.isArray) {
- return Array.isArray(obj);
- };
- return Object.prototype.toString.call(obj) === '[object Array]';
- };
-
- var decimalAdjust = function(type, value, exp) {
- // If the exp is undefined or zero...
- if (typeof exp === 'undefined' || +exp === 0) {
- return Math[type](value);
- }
- value = +value;
- exp = +exp;
- // If the value is not a number or the exp is not an integer...
- if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
- return NaN;
- }
- // Shift
- value = value.toString().split('e');
- value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
- // Shift back
- value = value.toString().split('e');
- return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
- }
-
- // Set default days/months translations.
- var DATE = {
- day_names: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
- , abbr_day_names: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
- , month_names: [null, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
- , abbr_month_names: [null, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
- , meridian: ["AM", "PM"]
- };
-
- // Set default number format.
- var NUMBER_FORMAT = {
- precision: 3
- , separator: "."
- , delimiter: ","
- , strip_insignificant_zeros: false
- };
-
- // Set default currency format.
- var CURRENCY_FORMAT = {
- unit: "$"
- , precision: 2
- , format: "%u%n"
- , sign_first: true
- , delimiter: ","
- , separator: "."
- };
-
- // Set default percentage format.
- var PERCENTAGE_FORMAT = {
- unit: "%"
- , precision: 3
- , format: "%n%u"
- , separator: "."
- , delimiter: ""
- };
-
- // Set default size units.
- var SIZE_UNITS = [null, "kb", "mb", "gb", "tb"];
-
- // Other default options
- var DEFAULT_OPTIONS = {
- // Set default locale. This locale will be used when fallback is enabled and
- // the translation doesn't exist in a particular locale.
- defaultLocale: "en"
- // Set the current locale to `en`.
- , locale: "en"
- // Set the translation key separator.
- , defaultSeparator: "."
- // Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
- , placeholder: /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm
- // Set if engine should fallback to the default locale when a translation
- // is missing.
- , fallbacks: false
- // Set the default translation object.
- , translations: {}
- // Set missing translation behavior. 'message' will display a message
- // that the translation is missing, 'guess' will try to guess the string
- , missingBehaviour: 'message'
- // if you use missingBehaviour with 'message', but want to know that the
- // string is actually missing for testing purposes, you can prefix the
- // guessed string by setting the value here. By default, no prefix!
- , missingTranslationPrefix: ''
- };
-
- I18n.reset = function() {
- // Set default locale. This locale will be used when fallback is enabled and
- // the translation doesn't exist in a particular locale.
- this.defaultLocale = DEFAULT_OPTIONS.defaultLocale;
-
- // Set the current locale to `en`.
- this.locale = DEFAULT_OPTIONS.locale;
-
- // Set the translation key separator.
- this.defaultSeparator = DEFAULT_OPTIONS.defaultSeparator;
-
- // Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
- this.placeholder = DEFAULT_OPTIONS.placeholder;
-
- // Set if engine should fallback to the default locale when a translation
- // is missing.
- this.fallbacks = DEFAULT_OPTIONS.fallbacks;
-
- // Set the default translation object.
- this.translations = DEFAULT_OPTIONS.translations;
-
- // Set the default missing behaviour
- this.missingBehaviour = DEFAULT_OPTIONS.missingBehaviour;
-
- // Set the default missing string prefix for guess behaviour
- this.missingTranslationPrefix = DEFAULT_OPTIONS.missingTranslationPrefix;
-
- };
-
- // Much like `reset`, but only assign options if not already assigned
- I18n.initializeOptions = function() {
- if (typeof(this.defaultLocale) === "undefined" && this.defaultLocale !== null)
- this.defaultLocale = DEFAULT_OPTIONS.defaultLocale;
-
- if (typeof(this.locale) === "undefined" && this.locale !== null)
- this.locale = DEFAULT_OPTIONS.locale;
-
- if (typeof(this.defaultSeparator) === "undefined" && this.defaultSeparator !== null)
- this.defaultSeparator = DEFAULT_OPTIONS.defaultSeparator;
-
- if (typeof(this.placeholder) === "undefined" && this.placeholder !== null)
- this.placeholder = DEFAULT_OPTIONS.placeholder;
-
- if (typeof(this.fallbacks) === "undefined" && this.fallbacks !== null)
- this.fallbacks = DEFAULT_OPTIONS.fallbacks;
-
- if (typeof(this.translations) === "undefined" && this.translations !== null)
- this.translations = DEFAULT_OPTIONS.translations;
- };
- I18n.initializeOptions();
-
- // Return a list of all locales that must be tried before returning the
- // missing translation message. By default, this will consider the inline option,
- // current locale and fallback locale.
- //
- // I18n.locales.get("de-DE");
- // // ["de-DE", "de", "en"]
- //
- // You can define custom rules for any locale. Just make sure you return a array
- // containing all locales.
- //
- // // Default the Wookie locale to English.
- // I18n.locales["wk"] = function(locale) {
- // return ["en"];
- // };
- //
- I18n.locales = {};
-
- // Retrieve locales based on inline locale, current locale or default to
- // I18n's detection.
- I18n.locales.get = function(locale) {
- var result = this[locale] || this[I18n.locale] || this["default"];
-
- if (typeof(result) === "function") {
- result = result(locale);
- }
-
- if (isArray(result) === false) {
- result = [result];
- }
-
- return result;
- };
-
- // The default locale list.
- I18n.locales["default"] = function(locale) {
- var locales = []
- , list = []
- , countryCode
- , count
- ;
-
- // Handle the inline locale option that can be provided to
- // the `I18n.t` options.
- if (locale) {
- locales.push(locale);
- }
-
- // Add the current locale to the list.
- if (!locale && I18n.locale) {
- locales.push(I18n.locale);
- }
-
- // Add the default locale if fallback strategy is enabled.
- if (I18n.fallbacks && I18n.defaultLocale) {
- locales.push(I18n.defaultLocale);
- }
-
- // Compute each locale with its country code.
- // So this will return an array containing both
- // `de-DE` and `de` locales.
- locales.forEach(function(locale){
- countryCode = locale.split("-")[0];
-
- if (!~list.indexOf(locale)) {
- list.push(locale);
- }
-
- if (I18n.fallbacks && countryCode && countryCode !== locale && !~list.indexOf(countryCode)) {
- list.push(countryCode);
- }
- });
-
- // No locales set? English it is.
- if (!locales.length) {
- locales.push("en");
- }
-
- return list;
- };
-
- // Hold pluralization rules.
- I18n.pluralization = {};
-
- // Return the pluralizer for a specific locale.
- // If no specify locale is found, then I18n's default will be used.
- I18n.pluralization.get = function(locale) {
- return this[locale] || this[I18n.locale] || this["default"];
- };
-
- // The default pluralizer rule.
- // It detects the `zero`, `one`, and `other` scopes.
- I18n.pluralization["default"] = function(count) {
- switch (count) {
- case 0: return ["zero", "other"];
- case 1: return ["one"];
- default: return ["other"];
- }
- };
-
- // Return current locale. If no locale has been set, then
- // the current locale will be the default locale.
- I18n.currentLocale = function() {
- return this.locale || this.defaultLocale;
- };
-
- // Check if value is different than undefined and null;
- I18n.isSet = function(value) {
- return value !== undefined && value !== null;
- };
-
- // Find and process the translation using the provided scope and options.
- // This is used internally by some functions and should not be used as an
- // public API.
- I18n.lookup = function(scope, options) {
- options = this.prepareOptions(options);
-
- var locales = this.locales.get(options.locale).slice()
- , requestedLocale = locales[0]
- , locale
- , scopes
- , translations
- ;
-
- scope = this.getFullScope(scope, options);
-
- while (locales.length) {
- locale = locales.shift();
- scopes = scope.split(this.defaultSeparator);
- translations = this.translations[locale];
-
- if (!translations) {
- continue;
- }
-
- while (scopes.length) {
- translations = translations[scopes.shift()];
-
- if (translations === undefined || translations === null) {
- break;
- }
- }
-
- if (translations !== undefined && translations !== null) {
- return translations;
- }
- }
-
- if (this.isSet(options.defaultValue)) {
- return options.defaultValue;
- }
- };
-
- // Rails changed the way the meridian is stored.
- // It started with `date.meridian` returning an array,
- // then it switched to `time.am` and `time.pm`.
- // This function abstracts this difference and returns
- // the correct meridian or the default value when none is provided.
- I18n.meridian = function() {
- var time = this.lookup("time");
- var date = this.lookup("date");
-
- if (time && time.am && time.pm) {
- return [time.am, time.pm];
- } else if (date && date.meridian) {
- return date.meridian;
- } else {
- return DATE.meridian;
- }
- };
-
- // Merge serveral hash options, checking if value is set before
- // overwriting any value. The precedence is from left to right.
- //
- // I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"});
- // #=> {name: "John Doe", role: "user"}
- //
- I18n.prepareOptions = function() {
- var args = slice.call(arguments)
- , options = {}
- , subject
- ;
-
- while (args.length) {
- subject = args.shift();
-
- if (typeof(subject) != "object") {
- continue;
- }
-
- for (var attr in subject) {
- if (!subject.hasOwnProperty(attr)) {
- continue;
- }
-
- if (this.isSet(options[attr])) {
- continue;
- }
-
- options[attr] = subject[attr];
- }
- }
-
- return options;
- };
-
- // Generate a list of translation options for default fallbacks.
- // `defaultValue` is also deleted from options as it is returned as part of
- // the translationOptions array.
- I18n.createTranslationOptions = function(scope, options) {
- var translationOptions = [{scope: scope}];
-
- // Defaults should be an array of hashes containing either
- // fallback scopes or messages
- if (this.isSet(options.defaults)) {
- translationOptions = translationOptions.concat(options.defaults);
- }
-
- // Maintain support for defaultValue. Since it is always a message
- // insert it in to the translation options as such.
- if (this.isSet(options.defaultValue)) {
- translationOptions.push({ message: options.defaultValue });
- delete options.defaultValue;
- }
-
- return translationOptions;
- };
-
- // Translate the given scope with the provided options.
- I18n.translate = function(scope, options) {
- options = this.prepareOptions(options);
-
- var translationOptions = this.createTranslationOptions(scope, options);
-
- var translation;
- // Iterate through the translation options until a translation
- // or message is found.
- var translationFound =
- translationOptions.some(function(translationOption) {
- if (this.isSet(translationOption.scope)) {
- translation = this.lookup(translationOption.scope, options);
- } else if (this.isSet(translationOption.message)) {
- translation = translationOption.message;
- }
-
- if (translation !== undefined && translation !== null) {
- return true;
- }
- }, this);
-
- if (!translationFound) {
- return this.missingTranslation(scope, options);
- }
-
- if (typeof(translation) === "string") {
- translation = this.interpolate(translation, options);
- } else if (isObject(translation) && this.isSet(options.count)) {
- translation = this.pluralize(options.count, translation, options);
- }
-
- return translation;
- };
-
- // This function interpolates the all variables in the given message.
- I18n.interpolate = function(message, options) {
- options = this.prepareOptions(options);
- var matches = message.match(this.placeholder)
- , placeholder
- , value
- , name
- , regex
- ;
-
- if (!matches) {
- return message;
- }
-
- var value;
-
- while (matches.length) {
- placeholder = matches.shift();
- name = placeholder.replace(this.placeholder, "$1");
-
- if (this.isSet(options[name])) {
- value = options[name].toString().replace(/\$/gm, "_#$#_");
- } else if (name in options) {
- value = this.nullPlaceholder(placeholder, message, options);
- } else {
- value = this.missingPlaceholder(placeholder, message, options);
- }
-
- regex = new RegExp(placeholder.replace(/\{/gm, "\\{").replace(/\}/gm, "\\}"));
- message = message.replace(regex, value);
- }
-
- return message.replace(/_#\$#_/g, "$");
- };
-
- // Pluralize the given scope using the `count` value.
- // The pluralized translation may have other placeholders,
- // which will be retrieved from `options`.
- I18n.pluralize = function(count, scope, options) {
- options = this.prepareOptions(options);
- var translations, pluralizer, keys, key, message;
-
- if (isObject(scope)) {
- translations = scope;
- } else {
- translations = this.lookup(scope, options);
- }
-
- if (!translations) {
- return this.missingTranslation(scope, options);
- }
-
- pluralizer = this.pluralization.get(options.locale);
- keys = pluralizer(count);
-
- while (keys.length) {
- key = keys.shift();
-
- if (this.isSet(translations[key])) {
- message = translations[key];
- break;
- }
- }
-
- options.count = String(count);
- return this.interpolate(message, options);
- };
-
- // Return a missing translation message for the given parameters.
- I18n.missingTranslation = function(scope, options) {
- //guess intended string
- if(this.missingBehaviour == 'guess'){
- //get only the last portion of the scope
- var s = scope.split('.').slice(-1)[0];
- //replace underscore with space && camelcase with space and lowercase letter
- return (this.missingTranslationPrefix.length > 0 ? this.missingTranslationPrefix : '') +
- s.replace('_',' ').replace(/([a-z])([A-Z])/g,
- function(match, p1, p2) {return p1 + ' ' + p2.toLowerCase()} );
- }
-
- var fullScope = this.getFullScope(scope, options);
- var fullScopeWithLocale = [this.currentLocale(), fullScope].join(this.defaultSeparator);
-
- return '[missing "' + fullScopeWithLocale + '" translation]';
- };
-
- // Return a missing placeholder message for given parameters
- I18n.missingPlaceholder = function(placeholder, message, options) {
- return "[missing " + placeholder + " value]";
- };
-
- I18n.nullPlaceholder = function() {
- return I18n.missingPlaceholder.apply(I18n, arguments);
- };
-
- // Format number using localization rules.
- // The options will be retrieved from the `number.format` scope.
- // If this isn't present, then the following options will be used:
- //
- // - `precision`: `3`
- // - `separator`: `"."`
- // - `delimiter`: `","`
- // - `strip_insignificant_zeros`: `false`
- //
- // You can also override these options by providing the `options` argument.
- //
- I18n.toNumber = function(number, options) {
- options = this.prepareOptions(
- options
- , this.lookup("number.format")
- , NUMBER_FORMAT
- );
-
- var negative = number < 0
- , string = toFixed(Math.abs(number), options.precision).toString()
- , parts = string.split(".")
- , precision
- , buffer = []
- , formattedNumber
- , format = options.format || "%n"
- , sign = negative ? "-" : ""
- ;
-
- number = parts[0];
- precision = parts[1];
-
- while (number.length > 0) {
- buffer.unshift(number.substr(Math.max(0, number.length - 3), 3));
- number = number.substr(0, number.length -3);
- }
-
- formattedNumber = buffer.join(options.delimiter);
-
- if (options.strip_insignificant_zeros && precision) {
- precision = precision.replace(/0+$/, "");
- }
-
- if (options.precision > 0 && precision) {
- formattedNumber += options.separator + precision;
- }
-
- if (options.sign_first) {
- format = "%s" + format;
- }
- else {
- format = format.replace("%n", "%s%n");
- }
-
- formattedNumber = format
- .replace("%u", options.unit)
- .replace("%n", formattedNumber)
- .replace("%s", sign)
- ;
-
- return formattedNumber;
- };
-
- // Format currency with localization rules.
- // The options will be retrieved from the `number.currency.format` and
- // `number.format` scopes, in that order.
- //
- // Any missing option will be retrieved from the `I18n.toNumber` defaults and
- // the following options:
- //
- // - `unit`: `"$"`
- // - `precision`: `2`
- // - `format`: `"%u%n"`
- // - `delimiter`: `","`
- // - `separator`: `"."`
- //
- // You can also override these options by providing the `options` argument.
- //
- I18n.toCurrency = function(number, options) {
- options = this.prepareOptions(
- options
- , this.lookup("number.currency.format")
- , this.lookup("number.format")
- , CURRENCY_FORMAT
- );
-
- return this.toNumber(number, options);
- };
-
- // Localize several values.
- // You can provide the following scopes: `currency`, `number`, or `percentage`.
- // If you provide a scope that matches the `/^(date|time)/` regular expression
- // then the `value` will be converted by using the `I18n.toTime` function.
- //
- // It will default to the value's `toString` function.
- //
- I18n.localize = function(scope, value, options) {
- options || (options = {});
-
- switch (scope) {
- case "currency":
- return this.toCurrency(value);
- case "number":
- scope = this.lookup("number.format");
- return this.toNumber(value, scope);
- case "percentage":
- return this.toPercentage(value);
- default:
- var localizedValue;
-
- if (scope.match(/^(date|time)/)) {
- localizedValue = this.toTime(scope, value);
- } else {
- localizedValue = value.toString();
- }
-
- return this.interpolate(localizedValue, options);
- }
- };
-
- // Parse a given `date` string into a JavaScript Date object.
- // This function is time zone aware.
- //
- // The following string formats are recognized:
- //
- // yyyy-mm-dd
- // yyyy-mm-dd[ T]hh:mm::ss
- // yyyy-mm-dd[ T]hh:mm::ss
- // yyyy-mm-dd[ T]hh:mm::ssZ
- // yyyy-mm-dd[ T]hh:mm::ss+0000
- // yyyy-mm-dd[ T]hh:mm::ss+00:00
- // yyyy-mm-dd[ T]hh:mm::ss.123Z
- //
- I18n.parseDate = function(date) {
- var matches, convertedDate, fraction;
- // we have a date, so just return it.
- if (typeof(date) == "object") {
- return date;
- };
-
- matches = date.toString().match(/(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2})([\.,]\d{1,3})?)?(Z|\+00:?00)?/);
-
- if (matches) {
- for (var i = 1; i <= 6; i++) {
- matches[i] = parseInt(matches[i], 10) || 0;
- }
-
- // month starts on 0
- matches[2] -= 1;
-
- fraction = matches[7] ? 1000 * ("0" + matches[7]) : null;
-
- if (matches[8]) {
- convertedDate = new Date(Date.UTC(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], fraction));
- } else {
- convertedDate = new Date(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], fraction);
- }
- } else if (typeof(date) == "number") {
- // UNIX timestamp
- convertedDate = new Date();
- convertedDate.setTime(date);
- } else if (date.match(/([A-Z][a-z]{2}) ([A-Z][a-z]{2}) (\d+) (\d+:\d+:\d+) ([+-]\d+) (\d+)/)) {
- // This format `Wed Jul 20 13:03:39 +0000 2011` is parsed by
- // webkit/firefox, but not by IE, so we must parse it manually.
- convertedDate = new Date();
- convertedDate.setTime(Date.parse([
- RegExp.$1, RegExp.$2, RegExp.$3, RegExp.$6, RegExp.$4, RegExp.$5
- ].join(" ")));
- } else if (date.match(/\d+ \d+:\d+:\d+ [+-]\d+ \d+/)) {
- // a valid javascript format with timezone info
- convertedDate = new Date();
- convertedDate.setTime(Date.parse(date));
- } else {
- // an arbitrary javascript string
- convertedDate = new Date();
- convertedDate.setTime(Date.parse(date));
- }
-
- return convertedDate;
- };
-
- // Formats time according to the directives in the given format string.
- // The directives begins with a percent (%) character. Any text not listed as a
- // directive will be passed through to the output string.
- //
- // The accepted formats are:
- //
- // %a - The abbreviated weekday name (Sun)
- // %A - The full weekday name (Sunday)
- // %b - The abbreviated month name (Jan)
- // %B - The full month name (January)
- // %c - The preferred local date and time representation
- // %d - Day of the month (01..31)
- // %-d - Day of the month (1..31)
- // %H - Hour of the day, 24-hour clock (00..23)
- // %-H - Hour of the day, 24-hour clock (0..23)
- // %I - Hour of the day, 12-hour clock (01..12)
- // %-I - Hour of the day, 12-hour clock (1..12)
- // %m - Month of the year (01..12)
- // %-m - Month of the year (1..12)
- // %M - Minute of the hour (00..59)
- // %-M - Minute of the hour (0..59)
- // %p - Meridian indicator (AM or PM)
- // %S - Second of the minute (00..60)
- // %-S - Second of the minute (0..60)
- // %w - Day of the week (Sunday is 0, 0..6)
- // %y - Year without a century (00..99)
- // %-y - Year without a century (0..99)
- // %Y - Year with century
- // %z - Timezone offset (+0545)
- //
- I18n.strftime = function(date, format) {
- var options = this.lookup("date")
- , meridianOptions = I18n.meridian()
- ;
-
- if (!options) {
- options = {};
- }
-
- options = this.prepareOptions(options, DATE);
-
- var weekDay = date.getDay()
- , day = date.getDate()
- , year = date.getFullYear()
- , month = date.getMonth() + 1
- , hour = date.getHours()
- , hour12 = hour
- , meridian = hour > 11 ? 1 : 0
- , secs = date.getSeconds()
- , mins = date.getMinutes()
- , offset = date.getTimezoneOffset()
- , absOffsetHours = Math.floor(Math.abs(offset / 60))
- , absOffsetMinutes = Math.abs(offset) - (absOffsetHours * 60)
- , timezoneoffset = (offset > 0 ? "-" : "+") +
- (absOffsetHours.toString().length < 2 ? "0" + absOffsetHours : absOffsetHours) +
- (absOffsetMinutes.toString().length < 2 ? "0" + absOffsetMinutes : absOffsetMinutes)
- ;
-
- if (hour12 > 12) {
- hour12 = hour12 - 12;
- } else if (hour12 === 0) {
- hour12 = 12;
- }
-
- format = format.replace("%a", options.abbr_day_names[weekDay]);
- format = format.replace("%A", options.day_names[weekDay]);
- format = format.replace("%b", options.abbr_month_names[month]);
- format = format.replace("%B", options.month_names[month]);
- format = format.replace("%d", padding(day));
- format = format.replace("%e", day);
- format = format.replace("%-d", day);
- format = format.replace("%H", padding(hour));
- format = format.replace("%-H", hour);
- format = format.replace("%I", padding(hour12));
- format = format.replace("%-I", hour12);
- format = format.replace("%m", padding(month));
- format = format.replace("%-m", month);
- format = format.replace("%M", padding(mins));
- format = format.replace("%-M", mins);
- format = format.replace("%p", meridianOptions[meridian]);
- format = format.replace("%S", padding(secs));
- format = format.replace("%-S", secs);
- format = format.replace("%w", weekDay);
- format = format.replace("%y", padding(year));
- format = format.replace("%-y", padding(year).replace(/^0+/, ""));
- format = format.replace("%Y", year);
- format = format.replace("%z", timezoneoffset);
-
- return format;
- };
-
- // Convert the given dateString into a formatted date.
- I18n.toTime = function(scope, dateString) {
- var date = this.parseDate(dateString)
- , format = this.lookup(scope)
- ;
-
- if (date.toString().match(/invalid/i)) {
- return date.toString();
- }
-
- if (!format) {
- return date.toString();
- }
-
- return this.strftime(date, format);
- };
-
- // Convert a number into a formatted percentage value.
- I18n.toPercentage = function(number, options) {
- options = this.prepareOptions(
- options
- , this.lookup("number.percentage.format")
- , this.lookup("number.format")
- , PERCENTAGE_FORMAT
- );
-
- return this.toNumber(number, options);
- };
-
- // Convert a number into a readable size representation.
- I18n.toHumanSize = function(number, options) {
- var kb = 1024
- , size = number
- , iterations = 0
- , unit
- , precision
- ;
-
- while (size >= kb && iterations < 4) {
- size = size / kb;
- iterations += 1;
- }
-
- if (iterations === 0) {
- unit = this.t("number.human.storage_units.units.byte", {count: size});
- precision = 0;
- } else {
- unit = this.t("number.human.storage_units.units." + SIZE_UNITS[iterations]);
- precision = (size - Math.floor(size) === 0) ? 0 : 1;
- }
-
- options = this.prepareOptions(
- options
- , {unit: unit, precision: precision, format: "%n%u", delimiter: ""}
- );
-
- return this.toNumber(size, options);
- };
-
- I18n.getFullScope = function(scope, options) {
- options = this.prepareOptions(options);
-
- // Deal with the scope as an array.
- if (scope.constructor === Array) {
- scope = scope.join(this.defaultSeparator);
- }
-
- // Deal with the scope option provided through the second argument.
- //
- // I18n.t('hello', {scope: 'greetings'});
- //
- if (options.scope) {
- scope = [options.scope, scope].join(this.defaultSeparator);
- }
-
- return scope;
- };
- /**
- * Merge obj1 with obj2 (shallow merge), without modifying inputs
- * @param {Object} obj1
- * @param {Object} obj2
- * @returns {Object} Merged values of obj1 and obj2
- *
- * In order to support ES3, `Object.prototype.hasOwnProperty.call` is used
- * Idea is from:
- * https://stackoverflow.com/questions/8157700/object-has-no-hasownproperty-method-i-e-its-undefined-ie8
- */
- I18n.extend = function ( obj1, obj2 ) {
- var extended = {};
- var prop;
- for (prop in obj1) {
- if (Object.prototype.hasOwnProperty.call(obj1, prop)) {
- extended[prop] = obj1[prop];
- }
- }
- for (prop in obj2) {
- if (Object.prototype.hasOwnProperty.call(obj2, prop)) {
- extended[prop] = obj2[prop];
- }
- }
- return extended;
- };
-
- // Set aliases, so we can save some typing.
- I18n.t = I18n.translate;
- I18n.l = I18n.localize;
- I18n.p = I18n.pluralize;
-
- return I18n;
-}));
diff --git a/test/configuration_test.rb b/test/configuration_test.rb
new file mode 100644
index 0000000..44562b6
--- /dev/null
+++ b/test/configuration_test.rb
@@ -0,0 +1,18 @@
+require 'test_helper'
+
+class ConfigurationHelper < ActionDispatch::IntegrationTest
+
+ # --------------------------------------------------------------------
+ test "Make sure that all of the example YAML files have been setup properly" do
+ # Check for YAML configs
+ ['database.yml', 'branding.yml', 'secrets.yml'].each do |yml|
+ assert File.exist?("./config/#{yml}"), "Was expecting to find ./config/#{yml}"
+ end
+
+ # Check for initializers
+ ['contact_us.rb', 'devise.rb', 'recaptcha.rb', 'wicked_pdf.rb'].each do |rb|
+ assert File.exist?("./config/initializers/#{rb}"), "Was expecting to find ./config/initializers/#{rb}"
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/test/fixtures/answers.yml b/test/fixtures/answers.yml
deleted file mode 100644
index af9ebc8..0000000
--- a/test/fixtures/answers.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
-
-one:
- text: MyText
- plan_id: 1
- user_id: 1
- question_id: 1
-
-#two:
-# text: MyText
-# plan_id: 1
-# user_id: 1
-# question_id: 1
diff --git a/test/fixtures/comments.yml b/test/fixtures/comments.yml
deleted file mode 100644
index 69b84d4..0000000
--- a/test/fixtures/comments.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
-
-one:
- user_id: 1
- question_id: 1
- text: MyText
-
-two:
- user_id: 1
- question_id: 1
- text: MyText
diff --git a/test/fixtures/dmptemplates.yml b/test/fixtures/dmptemplates.yml
deleted file mode 100644
index 5e0fa48..0000000
--- a/test/fixtures/dmptemplates.yml
+++ /dev/null
@@ -1,70 +0,0 @@
-# Produces:
-# -----------------------------
-# cc_template <-- belongs to organisation: cc
-# cc_template_unpublished <-- belongs to organisation: cc
-#
-# funder_template_1 <-- belongs to organisation: funder
-# funder_template_2 <-- belongs to organisation: funder
-# funder_template_unpublished <-- belongs to organisation: funder
-#
-# complete_template <-- belongs to organisation: complete
-#
-# institution_[1..2]_template <-- belongs to organisation: institution_X
-# institution_[1..2]_template_unpublished <-- belongs to organisation: institution_X
-#
-# school_[1..2]_template <-- belongs to organisation: school_X
-# school_[1..2]_template_unpublished <-- belongs to organisation: school_X
-#
-# project_[1..2]_template <-- belongs to organisation: project_X
-# project_[1..2]_template_unpublished <-- belongs to organisation: project_X
-#
-
-# Import organisation_types.yml so that we can dynamically generate organisations
-<% organisation_types = YAML::load(ERB.new(File.read('./test/fixtures/organisation_types.yml')).result) %>
-
-cc_template:
- title: "Curation Centre Default Template"
- description: "The default template"
- published: true
- organisation: curation_center
- locale: en-UK
- is_default: true
-
-cc_template_unpublished:
- title: "Curation Centre Default Template"
- description: "The default template"
- published: false
- organisation: curation_center
- locale: en-UK
- is_default: true
-
-<% 3.times do |n| %>
-funder_template_<%= (n == 1 ? 'unpublished' : n + 1) %>:
- title: <%= "Funder Template #{(n == 1 ? 'unpublished' : n + 1)}" %>
- published: <%= (n != 1) %>
- organisation: funder
- locale: en-UK
-<% end %>
-
-complete_template:
- title: "Complete Organisation's Template"
- description: "The template for the complete organisation"
- published: true
- organisation: complete
- locale: en-UK
-
-<% organisation_types.each do |lbl, obj| %>
- <% unless ['funder', 'organisation'].include?(lbl) %>
- <% 2.times do |x| %>
- <% 2.times do |y| %>
-
-<%= lbl %>_<%= x + 1 %>_template<%= (y == 0 ? '' : '_unpublished') %>:
- title: <%= "#{obj['name']} #{x + 1} Template #{(y == 0 ? '' : 'Unpublished')}" %>
- published: <%= (y == 0) %>
- organisation: <%= lbl %>_<%= x + 1 %>
- locale: en-UK
-
- <% end %>
- <% end %>
- <% end %>
-<% end %>
\ No newline at end of file
diff --git a/test/fixtures/file_types.yml b/test/fixtures/file_types.yml
deleted file mode 100644
index 2fbb4fb..0000000
--- a/test/fixtures/file_types.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
-
-#one:
-# name: MyString
-# icon_name: MyString
-# icon_size: 1
-# icon_location: MyString
-#
-#two:
-# name: MyString
-# icon_name: MyString
-# icon_size: 1
-# icon_location: MyString
diff --git a/test/fixtures/file_uploads.yml b/test/fixtures/file_uploads.yml
deleted file mode 100644
index 4499d51..0000000
--- a/test/fixtures/file_uploads.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
-
-#one:
-# name: MyString
-# title: MyString
-# description: MyText
-# size: 1
-# published: false
-# location: MyString
-# file_type_id: 1
-#
-#two:
-# name: MyString
-# title: MyString
-# description: MyText
-# size: 1
-# published: false
-# location: MyString
-# file_type_id: 1
diff --git a/test/fixtures/guidance_groups.yml b/test/fixtures/guidance_groups.yml
deleted file mode 100644
index 06003a8..0000000
--- a/test/fixtures/guidance_groups.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
-
-dcc_guidance_group_1:
- name: "DCC guidance group 1"
- organisation: dcc
- guidances: related_policies, existing_data, licensing_of_existing_data, relationship_to_existing_data, description_of_data_content, data_format, data_volumes, data_type, data_capture_methods, data_organisation, data_quality, documentation, metadata_capture, metadata_standards, discovery_by_users, ethical_issues, ipr_ownership_and_licencing, active_data_storage, backup_procedures, data_security, data_selection, preservation_plan, period_of_preservation, data_repository, audience, expected_reuse, method_for_data_sharing, timeframe_for_data_sharing, embargo_period, restrictions_on_sharing, managed_access_procedures, responsibilities, resourcing_skills_and_training, resourcing_hardware_and_software, resourcing_preservation_and_data_sharing
- dmptemplates: dcc_template
-
-# funder groups
-funder_guidance_group_1:
- name: "Funder guidance group 1"
- organisation: ahrc
- guidances: ahrc_funder_guidance
- dmptemplates: ahrc_template
-
-funder_guidance_group_2:
- name: "Funder guidance group 2"
- organisation: bbsrc
- guidances: bbsrc_funder_guidance
- dmptemplates: bbsrc_template
-
-# institution groups
-institution_guidance_group_1:
- name: "Anglia Ruskin University guidance group"
- organisation: aru
- guidances: aru_institution_guidance
- dmptemplates: aru_template
-
-institution_guidance_group_2:
- name: "Aston University guidance group"
- organisation: au
- guidances: au_institution_guidance_1, au_institution_guidance_2
- dmptemplates: au_template
-
-institution_guidance_group_3:
- name: "Bangor University guidance group 1"
- organisation: bu
- guidances: bu_institution_guidance_1
- dmptemplates: bu_template
-
-institution_guidance_group_4:
- name: "Bangor University guidance group 2"
- organisation: bu
- guidances: bu_institution_guidance_2
- dmptemplates: bu_template
-
-institution_guidance_group_5:
- name: "institution child guidance group 1"
- organisation: institution_child_one
-
-institution_guidance_group_6:
- name: "institution child guidance group 2"
- organisation: institution_child_one
diff --git a/test/fixtures/guidances.yml b/test/fixtures/guidances.yml
deleted file mode 100644
index 7aaac07..0000000
--- a/test/fixtures/guidances.yml
+++ /dev/null
@@ -1,176 +0,0 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
-
-related_policies:
- text: "
Questions to consider:
Are there any existing procedures that you will base your approach on?
Does your department/group have data management guidelines?
Does your institution have a data protection or security policy that you will follow?
Does your institution have a Research Data Management (RDM) policy?
Does your funder have a Research Data Management policy?
Are there any formal standards that you will adopt?
Guidance:
List any other relevant funder, institutional, departmental or group policies on data management, data sharing and data security. Some of the information you give in the remainder of the DMP will be determined by the content of other policies. If so, point/link to them here.
Do the chosen formats and software enable sharing and long-term validity of data?
Guidance:
Outline and justify your choice of format e.g. SPSS, Open Document Format, tab-delimited format, MS Excel.
Decisions may be based on staff expertise, a preference for Open formats, the standards accepted by data centres or widespread usage with a given community. Using standardised and interchangeable or open lossless data formats ensures the long-term usability of data.
Do you need to include costs for additional managed storage?
Will the scale of the data pose challenges when sharing or transferring data between sites?
Guidance:
Consider the implications of data volumes in terms of storage, backup and access.
Estimate the volume of data in KB/MB/GB and how this will grow to make sure any additional storage and technical support required can be provided.
"
- themes: data_volumes
-
-data_type:
- text: "
Questions to consider:
What types of data will you create?
Which types of data will have long-term value?
Guidance:
Outline the types of data that are expected to be produced from the project e.g. quantitative, qualitative, survey data, experimental measurements, models, images, audiovisual data, samples…
Include the raw data arising directly from the research, the reduced data derived from it, and published data.
How will you structure and name your folders and files?
How will you ensure that different versions of a dataset are easily identifiable?
Guidance:
Indicate how the data will be organised during the project, mentioning for example naming conventions, version control and folder structures. Consistent, well-ordered research data will be easier for the research team to find, understand and reuse.
How will you control data capture to ensure data quality?
What quality assurance processes will you adopt?
Guidance:
Explain how the consistency and quality of data collection will be controlled and documented.
This may include processes such as calibration, repeat samples or measurements, standardised data capture or recording, data entry validation, peer review of data or representation with controlled vocabularies.
What metadata, documentation or other supporting material should accompany the data for it to be interpreted correctly?
What information needs to be retained to enable the data to be read and interpreted in the future?
Guidance:
Describe the types of documentation that will accompany the data to provide a secondary users with any necessary details to prevent misuse, misinterpretation or confusion. This may include information on the methodology used to collect the data, analytical and procedural information, definitions of variables, units of measurement, any assumptions made, the format and file type of the data.
Can any of this information be created automatically?
Guidance:
Metadata should be created to describe the data and aid discovery. Consider how you will capture this information and where it will be recorded e.g. in a database with links to each item, in a ‘readme’ text file, in file headers.
Researchers are strongly encouraged to utilise community standards to describe and structure data, where these are in place. The DCC offers a catalogue of disciplinary metadata standards.
How will potential users find out about your data?
Will you provide metadata online to aid discovery and reuse?
Guidance:
Indicate how potential new users can find out about your data and identify whether they could be suitable for their research purposes. For example, you may provide basic discovery metadata online, such as title, author, subjects, keywords and publisher.
Have you gained consent for data preservation and sharing?
How will sensitive data be handled to ensure it is stored and transferred securely?
How will you protect the identity of participants? e.g. via anonymisation or using managed access procedures?
Guidance:
Investigators carrying out research involving human participants must ensure that consent is obtained to share data. Managing ethical concerns may include: anonymisation of data; referral to departmental or institutional ethics committees; and formal consent agreements. Ethical issues may affect how you store data, who can see/use it and how long it is kept. You should show that you’re aware of this and have planned accordingly.
See UKDA Guidance on Consent, Confidentiality and Ethics.
Will data sharing be postponed / restricted e.g. to seek patents?
Guidance:
State who will own the copyright and IPR of any new data that you will generate. For multi-partner projects, IPR ownership may be worth covering in a consortium agreement. Outline any restrictions needed on data sharing e.g. to protect proprietary or patentable data.
Do you have access to enough storage or will you need to include charges for additional services?
Guidance:
Storing data on laptops, computer hard drives or external storage devices alone is very risky. The use of robust, managed storage provided by university IT teams is preferable.
How will the data be backed up? i.e. how often, to where, how many copies, is this automated…
Who will be responsible for backup?
Have you tested whether you can restore from your backups?
Guidance:
Describe the data back-up procedures that you will adopt to ensure the data and metadata are securely stored during the lifetime of the project. You may need to discuss your institution’s policy on back-ups. It is better to use automatic backup services provided by university IT than rely on manual processes.
What are the risks to data security and how will these be managed?
Will you follow any formal standards?
Guidance:
If your data is sensitive (e.g. detailed personal data, politically sensitive information or trade secrets) you should discuss any appropriate security measures that you will be taking. Note the main risks and how these will be managed. Identify any formal standards that you will comply with e.g. ISO 27001.
See DCC Briefing Paper on Information Security Management - ISO 27000.
Which data are of long-term value and should be shared and/or preserved?
How will you decide what to keep?
Guidance:
Indicate which data you intend to preserve beyond the period of funding. This should be based on what has long-term value and is economically viable to keep. Consider how long you wish to keep the data and what will happen to it e.g. deposit in a data repository to enable reuse.
What is the long-term preservation plan for the dataset? e.g. deposit in a data repository
Will additional resources be needed to prepare data for deposit or meet charges from data repositories?
Guidance:
Researchers should consider how datasets that have long-term value will be preserved and curated beyond the lifetime of the grant. Also outline the plans for preparing and documenting data for sharing and archiving.
If you do not propose to use an established repository, the data management plan should demonstrate that resources and systems will be in place to enable the data to be curated effectively beyond the lifetime of the grant.
This may depend on the type of data. Most research funders expect data to be retained for a minimum of 10 years from the end of the project. For data that by their nature cannot be re-measured, efforts should be made to retain them indefinitely.
Where (i.e. in which repository) will the data be deposited?
Guidance:
Most research funders recommend the use of established data repositories, community databases and related initiatives to aid data preservation, sharing and reuse.
An international list of data repositories is available via Databib or Re3data.
What are the further intended or foreseeable research uses for the data?
Guidance:
You should think about the possibilities for re-use of your data in other contexts and by other users, and connect this as appropriate with your plans for dissemination and Pathways to Impact. Where there is potential for reuse, you should use standards and formats that facilitate this.
With whom will you share the data, and under what conditions?
Guidance:
Consider where, how, and to whom the data should be made available. Will you share data via a data repository, handle data requests directly or use another mechanism?
The methods used to share data will be dependent on a number of factors such as the type, size, complexity and sensitivity of data. Mention earlier examples to show a track record of effective data sharing.
Data (with accompanying metadata) should be shared in a timely fashion. It is generally expected that timely release would generally be no later than the release through publication of the main findings and should be in-line with established best practice in the field.
For how long do you need exclusive use of the data and why?
Guidance:
The value of data often depends on timeliness. Researchers have a legitimate interest in benefiting from their investment of time and effort in producing data, but not in prolonged exclusive use. Research funders typically allow embargoes in line with practice in the field, but expect these to be outlined and justified.
Are any restrictions on data sharing required? e.g. limits on who can use the data, when and for what purpose.
What restrictions are needed and why?
What action will you take to overcome or minimise restrictions?
Guidance:
Outline any expected difficulties in data sharing, along with causes and possible measures to overcome these. Restrictions to data sharing may be due to participant confidentiality, consent agreements or IPR. Strategies to limit restrictions may include: anonymising or aggregating data; gaining participant consent for data sharing; gaining copyright permissions; and agreeing a limited embargo period.
Will access be tightly controlled or restricted? e.g. by using data enclaves / secure data services
Will a data sharing agreement be required?
How will the data be licensed for reuse?
Guidance:
Indicate whether external users are (will be) bound by data sharing agreements, licenses or end-user agreements. If so, set out the terms and key responsibilities to be followed.
Note how access will be controlled, for example by the use of specialist services. A data enclave provides a controlled secure environments in which eligible researchers can perform analyses using restricted data resources.
Where a managed access process is required, the procedure should be clearly described and transparent.
Who is responsible for each data management activity?
How are responsibilities split across partner sites in collaborative research projects?
Guidance:
Outline the roles and responsibilities for all activities e.g. data capture, metadata production, data quality, storage and backup, data archiving & data sharing. Individuals should be named where possible. For collaborative projects you should explain the co-ordination of data management responsibilities across partners.
See UKDA Guidance on data management roles and responsibilities.
Are there appropriate computational facilities to manage, store and analyse the data?
Guidance:
Carefully consider any resources needed to deliver the plan. Where dedicated resources are needed, these should be outlined and justified.
Provide details and justification for any hardware or software which will be used to support the project’s research methodology, which is additional or exceptional to conventional desk-based research and institutional provision. This includes additional storage and backup costs that may be charged by IT services.
Have you costed in time and effort to prepare the data for sharing / preservation?
Guidance:
Carefully consider any resources needed to deliver the plan. Where dedicated resources are needed, these should be outlined and justified.
Funding should be included to cover any charges applied by data repositories, for example to handle data of exceptional size or complexity. Also remember to cost in time and effort to prepare data for deposit and ensure it is adequately documented to enable reuse.
If you are not depositing in a data repository, ensure you have appropriate resources and systems in place to share and preserve the data.
See UKDA How to cost data management.
"
- themes: resourcing_preservation_and_data_sharing
-
-ahrc_funder_guidance:
- text: "sample funder guidance ahrc"
- themes: embargo_period
-
-bbsrc_funder_guidance:
- text: "sample funder guidance bbsrc"
- themes: embargo_period
-
-aru_institution_guidance:
- text: "sample institution guidance aru"
- themes: embargo_period
-
-au_institution_guidance_1:
- text: "sample institution guidance au 1"
- themes: embargo_period
-
-au_institution_guidance_2:
- text: "sample instiution guidance au 2"
- themes: embargo_period
-
-bu_institution_guidance_1:
- text: "sample institution guidance bu 1"
- themes: embargo_period
-
-bu_institution_guidance_2:
- text: "sample institution guidance bu 2"
- themes: embargo_period
-
-one:
- text: "one"
- themes: embargo_period
-
-
-
diff --git a/test/fixtures/languages.yml b/test/fixtures/languages.yml
deleted file mode 100644
index 55ea794..0000000
--- a/test/fixtures/languages.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-en-UK:
- abbreviation: 'en-UK'
- description: 'UK English'
- name: 'English (UK)'
- default_language: true
-
-en-US:
- abbreviation: 'en-US'
- description: 'US English'
- name: 'English (US)'
- default_language: false
-
-fr:
- abbreviation: 'fr'
- description: 'French'
- name: 'French'
- default_language: false
\ No newline at end of file
diff --git a/test/fixtures/option_warnings.yml b/test/fixtures/option_warnings.yml
deleted file mode 100644
index 46bac23..0000000
--- a/test/fixtures/option_warnings.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-single_select_1_warning:
- option: single_select_1
- organisation: uog
- text: This warning should display when option 1 of the single item select box example is selected for a project at the University of Glasgow
-
-single_select_2_warning:
- option: single_select_2
- organisation: hatii
- text: This warning should display when option 2 of the single item select box example is selected for a project at HATII
-
-
-multiple_select_3_warning:
- option: multiple_select_3
- organisation: uoe
- text: This warning should display when option 3 of the multiple item select box example is selected for a project at the University of Edinburgh
-
-multiple_select_4_warning:
- option: multiple_select_4
- organisation: uoe_si
- text: This warning should display when option 4 of the multiple item select box example is selected for a project at the School of Informatics
-
-radio_button_1_warning:
- option: radio_button_1
- organisation: uog
- text: This warning should display when option 1 of the radio button example is selected for a project at the University of Glasgow
-
-radio_button_2_warning:
- option: radio_button_2
- organisation: hatii
- text: This warning should display when option 2 of the radio button example is selected for a project at HATII
-
-checkbox_3_warning:
- option: checkbox_3
- organisation: uoe
- text: This warning should display when option 3 of the checkbox example is selected for a project at the University of Edinburgh
-
-checkbox_4_warning:
- option: checkbox_4
- organisation: uoe_si
- text: This warning should display when option 4 of the checkbox example is selected for a project at the School of Informatics
\ No newline at end of file
diff --git a/test/fixtures/options.yml b/test/fixtures/options.yml
deleted file mode 100644
index e54b8d9..0000000
--- a/test/fixtures/options.yml
+++ /dev/null
@@ -1,89 +0,0 @@
-single_select_1:
- question: single_select_box
- text: Option 1
- number: 1
-
-single_select_2:
- question: single_select_box
- text: Option 2
- number: 2
-
-single_select_3:
- question: single_select_box
- text: Option 3
- number: 3
-
-single_select_4:
- question: single_select_box
- text: Option 4
- number: 4
-
-multiple_select_1:
- question: multiple_select_box
- text: Option 1
- number: 1
-
-multiple_select_2:
- question: multiple_select_box
- text: Option 2
- number: 2
-
-multiple_select_3:
- question: multiple_select_box
- text: Option 3
- number: 3
-
-multiple_select_4:
- question: multiple_select_box
- text: Option 4
- number: 4
-
-radio_button_1:
- question: radio_button
- text: Option 1
- number: 1
-
-radio_button_2:
- question: radio_button
- text: Option 2
- number: 2
-
-radio_button_3:
- question: radio_button
- text: Option 3
- number: 3
-
-radio_button_4:
- question: radio_button
- text: Option 4
- number: 4
-
-checkbox_1:
- question: checkbox
- text: Option 1
- number: 1
-
-checkbox_2:
- question: checkbox
- text: Option 2
- number: 2
-
-checkbox_3:
- question: checkbox
- text: Option 3
- number: 3
-
-checkbox_4:
- question: checkbox
- text: Option 4
- number: 4
-
-mrc_5_2_yes:
- question: mrc_5_2
- text: "Yes"
- number: 1
-
-mrc_5_2_no:
- question: mrc_5_2
- text: "No"
- number: 2
\ No newline at end of file
diff --git a/test/fixtures/org_token_permissions.yml b/test/fixtures/org_token_permissions.yml
deleted file mode 100644
index a4748f5..0000000
--- a/test/fixtures/org_token_permissions.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-dcc_one:
- token_permission_type: plans_token_type
- organisation: dcc
-
-dcc_two:
- token_permission_type: guidances_token_type
- organisation: dcc
-
-aru_one:
- token_permission_type: plans_token_type
- organisation: aru
-
-au_one:
- token_permission_type: guidances_token_type
- organisation: au
\ No newline at end of file
diff --git a/test/fixtures/organisation_types.yml b/test/fixtures/organisation_types.yml
deleted file mode 100644
index c969384..0000000
--- a/test/fixtures/organisation_types.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-<% # Load the org types from thosedefined in the MagicStrings section of the locale %>
-<% I18n.t("magic_strings.organisation_types").each do |k,v| %>
-<%= k %>:
- name: <%= "#{v}" %>
-<% end %>
\ No newline at end of file
diff --git a/test/fixtures/organisations.yml b/test/fixtures/organisations.yml
deleted file mode 100644
index df643f5..0000000
--- a/test/fixtures/organisations.yml
+++ /dev/null
@@ -1,57 +0,0 @@
-# Produces:
-# -----------------------------
-# curation_center
-# funder
-# complete <-- child of curation_center
-#
-# institution_[1..2]
-# school_[1..2]
-# project_[1..2]
-
-# Import organisation_types.yml so that we can dynamically generate organisations
-<% organisation_types = YAML::load(ERB.new(File.read('./test/fixtures/organisation_types.yml')).result) %>
-
-curation_center:
- name: 'Curation Centre'
- abbreviation: 'cc'
- organisation_type: organisation
- contact_email: 'admin@example-curation-centre.org'
-
-funder:
- name: 'Grant Funder'
- abbreviation: 'funder'
- organisation_type: funder
- contact_email: 'admin@example-funder.org'
-
-# We unfortunatley cannot tab this out nicely because YAML is expecting the values in
-# the first column
-<% organisation_types.each do |lbl, obj| %>
- <% unless ['funder', 'organisation'].include?(lbl) %>
- <% 2.times do |n| %>
-
-<%= lbl %>_<%= n + 1 %>:
- name: <%= "#{obj['name']} #{n}" %>
- domain: <%= "www.#{lbl}-#{n + 1}.org" %>
- organisation_type: <%= "#{lbl}" %>
- contact_email: "admin@example-#{lbl}-#{n + 1}.org"
-
- <% end %>
- <% end %>
-<% end %>
-
-complete:
- name: 'Organisation with all attributes'
- abbreviation: 'complete'
- target_url: 'http:\/\/www.complete-org.org'
- organisation_type: organisation
- domain: 'www.complete-org.org'
- wayfless_entity: ''
- stylesheet_file_id: 'complete-org.css'
- is_other: false
- sort_name: 'complete'
- banner_text: 'Complete organisation banner text'
- region_id: eu
- language_id: en-UK
- logo_uid: '2016/08/30/1234abcd-complete-org.gif'
- logo_name: 'complete-org.gif'
- contact_email: 'admin@example-complete-org.org'
\ No newline at end of file
diff --git a/test/fixtures/phases.yml b/test/fixtures/phases.yml
deleted file mode 100644
index 1a24240..0000000
--- a/test/fixtures/phases.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-# Produces:
-# -----------------------------
-# Generates 1 Phase for each published template and 2 Phases for each one that
-# is unpublished (see dmptemplates.yml for template list)
-#
-# [template]_phase_1
-# [template]_unpublished_phase_[1..2]
-#
-#
-
-# Import dmptemplates.yml so that we can dynamically generate phases
-<% templates = YAML::load(ERB.new(File.read('./test/fixtures/dmptemplates.yml')).result) %>
-
-<% templates.each do |lbl, hash| %>
-
-<%= lbl %>_phase_1:
- title: <%= "hash['title'] - Phase 1" %>
- number: 1
- dmptemplate: <%= lbl %>
-
- <% if lbl.include?('_unpublished') %>
-<%= lbl %>_phase_2:
- title: <%= "hash['title'] - Phase 2" %>
- number: 2
- dmptemplate: <%= lbl %>
- <% end %>
-
-<% end %>
diff --git a/test/fixtures/plan_sections.yml b/test/fixtures/plan_sections.yml
deleted file mode 100644
index b5a70f5..0000000
--- a/test/fixtures/plan_sections.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
-
-#one:
-# edit: false
-# at: 2013-06-11 15:17:04
-# user_editing_id: 1
-# section_id: 1
-# plan_id: 1
-#
-#two:
-# edit: false
-# at: 2013-06-11 15:17:04
-# user_editing_id: 1
-# section_id: 1
-# plan_id: 1
diff --git a/test/fixtures/plans.yml b/test/fixtures/plans.yml
deleted file mode 100644
index 6b64ebd..0000000
--- a/test/fixtures/plans.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
-
-#one:
-# locked: false
-# project_id: 1
-# version_id: 1
-#
-#two:
-# locked: false
-# project_id: 1
-# version_id: 1
diff --git a/test/fixtures/project_groups.yml b/test/fixtures/project_groups.yml
deleted file mode 100644
index d0dd7b2..0000000
--- a/test/fixtures/project_groups.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
-
-#one:
-# project_creator: false
-# project_editor: false
-# user_id: 1
-# project_id: 1
-#
-#two:
-# project_creator: false
-# project_editor: false
-# user_id: 1
-# project_id: 1
-
-<% 4.times do |n| %>
- many_projects_group_<%= n + 1 %>:
- project_creator: true
- project_editor: true
- user: with_many_projects
- project: test_plan<%= "_#{n + 1}" if n > 0 %>
-<% end %>
diff --git a/test/fixtures/projects.yml b/test/fixtures/projects.yml
deleted file mode 100644
index 5218482..0000000
--- a/test/fixtures/projects.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
-#two:
-# title: MyString
-# note: MyText
-# locked: false
-# dmptemplate_id: 1
-
-test_plan:
- title: "AHRC Template project"
- dmptemplate: ahrc_template
- organisation: ahrc
-
-test_plan_2:
- title: "AHRC Template second project"
- dmptemplate: ahrc_template_2
- organisation: ahrc
-
-test_plan_3:
- title: "DCC Template project"
- dmptemplate: dcc_template
- organisation: dcc
-
-test_plan_4:
- title: "DMP Template project"
- dmptemplate: dmp_template
- organisation: dcc
\ No newline at end of file
diff --git a/test/fixtures/questions.yml b/test/fixtures/questions.yml
deleted file mode 100644
index a730517..0000000
--- a/test/fixtures/questions.yml
+++ /dev/null
@@ -1,746 +0,0 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
-
-#Administrative Data
-
-related_policies:
- text: "Related Policies:"
- guidance: "
Questions to consider:
Are there any existing procedures that you will base your approach on?
Does your department/group have data management guidelines?
Does your institution have a data protection or security policy that you will follow? - Does your institution have a Research Data Management (RDM) policy?
Does your funder have a Research Data Management policy?
Are there any formal standards that you will adopt?
Guidance:
List any other relevant funder, institutional, departmental or group policies on data management, data sharing and data security. Some of the information you give in the remainder of the DMP will be determined by the content of other policies. If so, point/link to them here.
"
- number: 1
- section: administrative_data
- themes: related_policies
-
-#Data Collection
-
-what_data_will_you_collect_or_create:
- text: What data will you collect or create?
- guidance: "
Questions to consider:
What type, format and volume of data?
Do your chosen formats and software enable sharing and long-term access to the data?
Are there any existing data that you can reuse?
Guidance:
Give a brief description of the data, including any existing data or third-party sources that will be used, in each case noting its content, type and coverage. Outline and justify your choice of format and consider the implications of data format and data volumes in terms of storage, backup and access.
"
- number: 1
- section: data_collection
- themes: data_format, data_volumes, data_type, existing_data, description_of_data_content
-
-how_will_the_data_be_collected_or_created:
- text: How will the data be collected or created?
- guidance: "
Questions to consider:
What standards or methodologies will you use?
How will you structure and name your folders and files?
How will you handle versioning?
What quality assurance processes will you adopt?
Guidance:
Outline how the data will be collected/created and which community data standards (if any) will be used. Consider how the data will be organised during the project, mentioning for example naming conventions, version control and folder structures. Explain how the consistency and quality of data collection will be controlled and documented. This may include processes such as calibration, repeat samples or measurements, standardised data capture or recording, data entry validation, peer review of data or representation with controlled vocabularies.
"
- number: 2
- section: data_collection
- themes: data_capture_methods, data_quality
-
-#Documentation and Metadata
-
-what_documentation_and_metadata_will_acompany_the_data:
- text: What documentation and metadata will acompany the data?
- guidance: "
Questions to consider:
What information is needed for the data to be to be read and interpreted in the future?
How will you capture / create this documentation and metadata?
What metadata standards will you use and why?
Guidance:
Describe the types of documentation that will accompany the data to help secondary users to understand and reuse it. This should at least include basic details that will help people to find the data, including who created or contributed to the data, its title, date of creation and under what conditions it can be accessed.
Documentation may also include details on the methodology used, analytical and procedural information, definitions of variables, vocabularies, units of measurement, any assumptions made, and the format and file type of the data. Consider how you will capture this information and where it will be recorded. Wherever possible you should identify and use existing community standards.
"
- number: 1
- section: documentation_and_metadata
- themes: metadata_capture, documentation, metadata_standards
-
-#Ethics and Legal Compliance
-
-how_will_you_manage_any_ethical_issues:
- text: How will you manage any ethical issues?
- guidance: "
Questions to consider:
Have you gained consent for data preservation and sharing?
How will you protect the identity of participants if required? e.g. via anonymisation
How will sensitive data be handled to ensure it is stored and transferred securely?
Guidance:
Ethical issues affect how you store data, who can see/use it and how long it is kept. Managing ethical concerns may include: anonymisation of data; referral to departmental or institutional ethics committees; and formal consent agreements. You should show that you are aware of any issues and have planned accordingly. If you are carrying out research involving human participants, you must also ensure that consent is requested to allow data to be shared and reused.
"
- number: 1
- section: ethics_and_legal_compliance
- themes: ethical_issues, data_security
-
-how_will_you_manage_copyright_and_intellectual_property_rights_ipr_issues:
- text: How will you manage copyright and Intellectual Property Rights (IPR) issues?
- guidance: "
Questions to consider:
Who owns the data?
How will the data be licensed for reuse?
Are there any restrictions on the reuse of third-party data?
Will data sharing be postponed / restricted e.g. to publish or seek patents?
Guidance:
State who will own the copyright and IPR of any data that you will collect or create, along with the licence(s) for its use and reuse. For multi-partner projects, IPR ownership may be worth covering in a consortium agreement. Consider any relevant funder, institutional, departmental or group policies on copyright or IPR. Also consider permissions to reuse third-party data and any restrictions needed on data sharing.
"
- number: 2
- section: ethics_and_legal_compliance
- themes: licensing_of_existing_data, ipr_ownership_and_licencing
-
-#Storage and Backup
-
-how_will_the_data_be_stored_and_backed_up_during_the_research:
- text: How will the data be stored and backed up during the research?
- guidance: "
Questions to consider:
Do you have sufficient storage or will you need to include charges for additional services?
How will the data be backed up?
Who will be responsible for backup and recovery?
How will the data be recovered in the event of an incident?
Guidance:
State how often the data will be backed up and to which locations. How many copies are being made? Storing data on laptops, computer hard drives or external storage devices alone is very risky. The use of robust, managed storage provided by university IT teams is preferable. Similarly, it is normally better to use automatic backup services provided by IT Services than rely on manual processes. If you choose to use a third-party service, you should ensure that this does not conflict with any funder, institutional, departmental or group policies, for example in terms of the legal jurisdiction in which data are held or the protection of sensitive data.
"
- number: 1
- section: storage_and_backup
- themes: active_data_storage, backup_procedures
-
-how_will_you_manage_access_and_security:
- text: How will you manage access and security?
- guidance: "
Questions to consider:
What are the risks to data security and how will these be managed?
How will you control access to keep the data secure?
How will you ensure that collaborators can access your data securely?
If creating or collecting data in the field how will you ensure its safe transfer into your main secured systems?
Guidance:
If your data is confidential (e.g. personal data not already in the public domain, confidential information or trade secrets), you should outline any appropriate security measures and note any formal standards that you will comply with e.g. ISO 27001."
"
- number: 2
- section: storage_and_backup
- themes: data_security, managed_access_procedures
-
-#Selection and Preservation
-
-which_data_are_of_long-term_value_and_should_be_retained_shared_and-or_preserved:
- text: Which data are of long-term value and should be retained, shared, and/or preserved?
- guidance: "
Questions to consider:
What data must be retained/destroyed for contractual, legal, or regulatory purposes?
How will you decide what other data to keep?
What are the foreseeable research uses for the data?
How long will the data be retained and preserved?
Guidance:
Consider how the data may be reused e.g. to validate your research findings, conduct new studies, or for teaching. Decide which data to keep and for how long. This could be based on any obligations to retain certain data, the potential reuse value, what is economically viable to keep, and any additional effort required to prepare the data for data sharing and preservation. Remember to consider any additional effort required to prepare the data for sharing and preservation, such as changing file formats.
"
- number: 1
- section: selection_and_preservation
- themes: data_selection
-
-what_is_the_long-term_preservation_plan_for_the_dataset:
- text: What is the long-term preservation plan for the dataset?
- guidance: "
Questions to consider:
Where e.g. in which repository or archive will the data be held?
What costs if any will your selected data repository or archive charge?
Have you costed in time and effort to prepare the data for sharing / preservation?
Guidance:
Consider how datasets that have long-term value will be preserved and curated beyond the lifetime of the grant. Also outline the plans for preparing and documenting data for sharing and archiving. If you do not propose to use an established repository, the data management plan should demonstrate that resources and systems will be in place to enable the data to be curated effectively beyond the lifetime of the grant.
"
- number: 2
- section: selection_and_preservation
- themes: preservation_plan
-
-#Data Sharing
-
-how_will_you_share_the_data:
- text: How will you share the data?
- guidance: "
Questions to consider:
How will potential users find out about your data?
With whom will you share the data, and under what conditions?
Will you share data via a repository, handle requests directly or use another mechanism?
When will you make the data available?
Will you pursue getting a persistent identifier for your data?
Guidance:
Consider where, how, and to whom data with acknowledged long-term value should be made available. The methods used to share data will be dependent on a number of factors such as the type, size, complexity and sensitivity of data. If possible, mention earlier examples to show a track record of effective data sharing. Consider how people might acknowledge the reuse of your data.
"
- number: 1
- section: data_sharing
- themes: method_for_data_sharing
-
-are_any_restrictions_on_data_sharing_required:
- text: Are any restrictions on data sharing required?
- guidance: "
Questions to consider:
What action will you take to overcome or minimise restrictions?
For how long do you need exclusive use of the data and why?
Will a data sharing agreement (or equivalent) be required?
Guidance:
Outline any expected difficulties in sharing data with acknowledged long-term value, along with causes and possible measures to overcome these. Restrictions may be due to confidentiality, lack of consent agreements or IPR, for example. Consider whether a non-disclosure agreement would give sufficient protection for confidential data.
"
- number: 2
- section: data_sharing
- themes: restrictions_on_sharing, embargo_period
-
-#Responsibilities and Resources
-
-who_will_be_responsible_for_data_management:
- text: Who will be responsible for data management?
- guidance: "
Questions to consider:
Who is responsible for implementing the DMP, and ensuring it is reviewed and revised?
Who will be responsible for each data management activity?
How will responsibilities be split across partner sites in collaborative research projects?
Will data ownership and responsibilities for RDM be part of any consortium agreement or contract agreed between partners?
Guidance:
Outline the roles and responsibilities for all activities e.g. data capture, metadata production, data quality, storage and backup, data archiving & data sharing. Consider who will be responsible for ensuring relevant policies will be respected. Individuals should be named where possible.
"
- number: 1
- section: responsibilities_and_resources
- themes: responsibilities
-
-what_resources_will_you_require_to_deliver_your_plan:
- text: What resources will you require to deliver your plan?
- guidance: "
Questions to consider:
Is additional specialist expertise (or training for existing staff) required?
Do you require hardware or software which is additional or exceptional to existing institutional provision?
Will charges be applied by data repositories?
Guidance:
Carefully consider any resources needed to deliver the plan, e.g. software, hardware, technical expertise, etc. Where dedicated resources are needed, these should be outlined and justified.
"
- number: 2
- section: responsibilities_and_resources
- themes: resourcing_skills_and_training, resourcing_hardware_and_software, resourcing_preservation_and_data_sharing
-
-#Multiple Choice
-
-#single_select_box:
-# text: Example select box limited to one option
-# number: 1
-# section: multiple_choice
-#
-#multiple_select_box:
-# text: Example select box allowing multiple options
-# number: 2
-# section: multiple_choice
-#
-#radio_button:
-# text: Example radio button
-# number: 3
-# section: multiple_choice
-#
-#checkbox:
-# text: Example checkbox
-# number: 4
-# section: multiple_choice
-
-ahrc_1_1:
- text: Summary of Digital Outputs and Digital Technologies
- guidance: "
You should provide a brief and clear description of the digital output or digital technology being proposed, considering the following aspects: purpose, source data, content, functionality, use and its relationship to the research questions. You should identify the type of access envisaged, if applicable, such as 'freely available online'.
The summary should provide clear overview of what you intend to achieve technically, to enable reviewers to assess whether the plans for achieving this are appropriate. You should provide a level of detail which is appropriate to the digital output or digital technology being proposed and its cost and status within the project.
You should provide information about your choice of data and file formats. You must provide any relevant vital statistics relating to the data, such as size, quantity and duration. Although such statistics might need to rely on estimation, you should provide the reasoning behind your calculations. You should give your reasons for using the standards or formats chosen.
You should provide information about and the rationale for any hardware or software which will be used to support the project’s research methodology, which is additional or exceptional to conventional desk-based research and institutional provision. They should be included in the Justification of Resources and cross-referenced if there is an associated budget line. Where necessary you should produce additional justification of the use of such items.
You must write ‘Not applicable’ if this section is not relevant to the type of digital output or digital technology proposed.
You should provide information about the process of technical development, showing how the standards and formats described in section 2.a and the hardware and software described in section 2.b relate to each other. You must show that you have considered how you will achieve your digital output or digital technology in practice, including issues of timetabling.
You should consider the technical development process from the point of data capture or data creation through to final delivery (in the case of a digital output) or analysis (in the case of a digital process). You should consider issues such as backup, monitoring, quality control and internal documentation where relevant, identifying procedures which are appropriate to the research environments. For example Technical Reviewers acknowledge that the backup procedures which are possible during fieldwork might be very different to those which are possible within an office environments.
This section needs to relate to the timetable and milestones given in the Case for Support as well as the project’s overall research methodology. The Technical Reviewer will be assessing the alignment of the technical development process with other project activities for logic and timeliness.
Preservation of digital outputs is necessary in order for them to endure changes in the technological environments and remain potentially re-usable in the future. In this section you must state what, if any, digital outputs of your project you intend to preserve beyond the period of funding.
The length and cost of preservation should be proportionate to the value and significance of the digital outputs. If you believe that none of these should be preserved this must be justified, and if the case is a good one the application will not be prejudiced.
You must consider preservation in four ways: what, where, how and for how long. You must also consider any institutional support needed in order to carry out these plans, whether from an individual, facility, organisation or service.
You should think about the possibilities for re-use of your data in other contexts and by other users, and connect this as appropriate with your plans for dissemination and Pathways to Impact.Where there is potential for re-usability, you should use standards and formats that facilitate this.
The Technical Reviewer will be looking for evidence that you understand the reasons for the choice of technical standards and formats described in Section 2.a Technical Methodology: Standards and Formats.
You should describe the types of documentation which will accompany the data. Documentation in this sense means technical documentation as well as user documentation. It includes, for instance, technical description, code commenting, project-build guidelines, the documentation of technical decisions and resource metadata which is additional to the standards which you have described in Section 2.a. Not all types of documentation will be relevant to a project and the quantity of documentation proposed should be proportionate to the envisaged value of the data.
"
- number: 1
- section: ahrc_4
- themes: preservation_plan, period_of_preservation, resourcing_preservation_and_data_sharing, documentation
-
-ahrc_4_2:
- text: "Ensuring Continued Accessibility and Use of Your Digital Outputs"
- guidance: "
In this section you must provide information about any plans for ensuring that digital outputs remain sustainable in the sense of immediately accessible and usable beyond the period of funding. There are costs to ensuring sustainability in this sense over and above the costs of preservation. The project's sustainability plan should therefore be proportionate to the envisaged longer-term value of the data for the research community and should be closely related to your plans for dissemination and Pathways to Impact.
If you believe that digital outputs should not be sustained beyond the period of funding then this should be justified. It is not mandatory to sustain all digital outputs. While you should consider the long-term value of the digital outputs to the research community, where they are purely ancillary to a project’s research outputs there may not be a case for sustaining them (though there would usually be a case for preservation).
You must consider the sustainability of your digital outputs in five ways: what, where, how, for how long, and how the cost will be covered. You must make appropriate provision for user consultation and user testing in this connection, and plan the development of suitable user documentation.
You should provide justification if you do not envisage open, public access. A case can be made for charging for or otherwise limiting access, but the default expectation is that access will be open. The Technical Reviewer will be looking for realistic commitments to sustaining public access in line with affordability and the longer-term value of the digital output.
You must consider any institutional support needed in order to carry out these plans, if not covered under Section 3, as well as the cost of keeping the digital output publicly available in the future, including issues relating to maintenance, infrastructure and upgrade (such as the need to modify aspects of a web interface or software application in order to account for changes in the technological environments). In order to minimise sustainability costs, it is generally useful that the expertise involved in the development of your project is supported by expertise in your own or a partner institution.
A sustainability plan does not necessarily mean a requirement to generate income or prevent resources from being freely available. Rather it is a requirement to consider the direct costs and expertise of maintaining digital outputs for continued access. Some applicants might be able to demonstrate that there will be no significant sustainability problems with their digital output; in some cases the university’s computing services or library might provide a firm commitment to sustaining the resource for a specified period; others might see the benefit of Open Source community development models. You should provide reassurances of sustainability which are proportionate to the envisaged longer-term value of the digital outputs for the research community.
When completing this section, you should consider the potential impact of the data on research in your field (if research in the discipline will be improved through the creation of the digital output, how will it be affected if the resource then disappears?), and make the necessary connections with your Impact Plan. You must factor in the effects of any IP, copyright and ethical issues during the period in which the digital output will be publicly accessible, connecting what you say with the relevant part of your Case for Support.
You must identify whether or not you envisage the academic content (as distinct from the technology) of the digital output being extended or updated beyond the period of funding, addressing the following issues: how this will be done, by who and at what cost. You will need to show how the cost of this will be sustained after the period of funding ends.
"
- number: 2
- section: ahrc_4
- themes: resourcing_preservation_and_data_sharing, managed_access_procedures, data_repository, method_for_data_sharing, timeframe_for_data_sharing
-
-bbsrc_1_1:
- text: "Data areas and data types - the volume, type and content of data that will be generated e.g. experimental measurements, models, records and images"
- guidance: "
BBSRC recognises that effective data sharing is already practiced in certain areas and expects this to continue. BBSRC supports, either directly or indirectly, a number of such resources. Data sharing in other areas is also expected where there is a strong scientific case and where it is cost effective.
BBSRC has identified a number of areas where there is a particularly strong scientific case for data sharing. These are:
Data arising from high volume experimentation
Low throughput data arising from long time series or cumulative approaches
Models generated using systems approaches
BBSRC expects data sharing to take place in these areas."
- number: 1
- section: bbsrc_1
- themes: description_of_data_content, data_type, data_volumes
-
-bbsrc_2_1:
- text: "Standards and metadata - the standards and methodologies that will be adopted for data collection and management, and why these have been selected"
- guidance: "
Standards are fundamental to effective data sharing. These can include standards for administrative processes, as well as for methodologies relating to data management and data formats. Researchers are expected to make use of current guidance and information on best practice.
It is expected that, in order to maximise the potential for re-use of data, BBSRC researchers should generate and manage data using existing widely accepted formats and methodologies where available. Data released for sharing should be validated and verified in line with accepted best practice and be of high quality. Data should be accompanied by the contextual information or documentation (metadata) needed to provide a secondary user with any necessary details on the origin or manipulation of the data in order to prevent any misuse, misinterpretation or confusion. Where standards for metadata exist, it is expected that these should be adhered to.
BBSRC encourages community development of standards where these do not currently exist or are not widely accepted and provides funding mechanisms for support of this type of activity.
"
- number: 1
- section: bbsrc_2
- themes: data_format, metadata_standards, data_quality, documentation
-
-bbsrc_3_1:
- text: "Relationship to other data available in public repositories"
- guidance: ""
- number: 1
- section: bbsrc_3
- themes: existing_data, relationship_to_existing data, licensing_of_existing data
-
-bbsrc_4_1:
- text: "Secondary use - further intended and/or foreseeable research uses for the completed dataset(s)"
- guidance: "
BBSRC supports the view that those enabling sharing should receive full and appropriate recognition by funders, their academic institutions and new users for promoting secondary research.
Where data are shared through a third party resource or databases, secondary users should acknowledge the source of data. Where data are shared directly from the originator, depending on the level of usage and collaboration either joint authorship or acknowledgement to the data originator may be appropriate. It is also important to ensure that researchers and their research institutions are protected against claims that application of their data led to wrong conclusions/decisions by others: any use made of any data generated by third parties would not come with a warranty of its quality.
Furthermore, BBSRC expects that researchers accessing data have responsibilities to preserve data confidentiality and to observe the ethical and legal obligations pertaining to the data.
"
- number: 1
- section: bbsrc_4
- themes: expected_reuse, audience
-
-bbsrc_5_1:
- text: "Methods for data sharing - planned mechanisms for making these data available, e.g. through deposition in existing public databases or on request, including access mechanisms where appropriate"
- guidance: "
BBSRC recognises that different approaches to data sharing will be required in different situations and considers that it is most appropriate for researchers to determine their own strategies for data sharing and outline these within their research grant proposal(s). Applicants should consider where, how, and to whom their data should be made available.
In addition, data sharing practices will change as areas of research develop and become more mature. This can be observed by looking at the areas of sequencing (i.e. well established mechanisms in place), microarrays (i.e. standards developed and being implemented) and systems biology (i.e. databases currently not well developed). Consideration should be given to what constitutes good practice in emerging areas of research.
It is expected that data sharing strategies will fall into the two broad categories below.
Data Sharing via a 3rd Party
Data sharing via deposition in an existing database, repository or other community resource is expected where possible and researchers are encouraged to share data through mechanisms affording the widest availability for generating added value and enabling re-use.
Researchers are encouraged to use existing infrastructure to facilitate data sharing where possible. BBSRC funds or otherwise supports a number of such resources. Where no such resources exist, applicants may consider sharing data via other third party mechanisms such as journal websites and / or open access repositories, many of which are now able to capture and share data underpinning publications.
Direct Data Sharing: from Originator to Others
This method of data sharing may be appropriate for areas where suitable third party mechanisms are not available. Researchers are expected to ensure that data are maintained for a period of 10 years after the completion of the research project in suitable accessible formats using established standards where possible such that the data can be made available on request in line with BBSRC guidance on good scientific practice. This may lead to collaboration between the new user and the original data creators, with the responsibilities and rights of all parties agreed at the outset.
Other mechanisms for data sharing may be used where appropriate. These could include sharing data within closed communities or a combination of methods for different datasets. Specific access mechanisms could be appropriate for example where there are ethical considerations, a need to protect confidential data, or other reasons for limiting access.
"
- number: 1
- section: bbsrc_5
- themes: discovery_by_users, method_for_data_sharing, managed_access_procedures, data_repository
-
-bbsrc_6_1:
- text: "Proprietary data - any restrictions on data sharing due to the need to protect proprietary or patentable data"
- guidance: "
In instances where BBSRC and a commercial partner jointly fund academic research work (for example LINK projects) there may be some restrictions over releasing data. Any such restrictions on data sharing due to co-funding arrangements should be set out in the “statement on data sharing” section of an application and will be considered when a grant application is peer reviewed. Applicants should also ensure they have obtained necessary clearances from relevant collaborators with regards to the content of the proposal including the data sharing plan in line with the BBSRC Research Grants Guide.
"
- number: 1
- section: bbsrc_6
- themes: ipr_ownership_and_licencing, restrictions_on_sharing
-
-bbsrc_7_1:
- text: "Timeframes - timescales for public release of data"
- guidance: "
The value of data often depends on timeliness. Researchers have a legitimate interest in benefiting from their own time and effort in producing data, but not in prolonged exclusive use of these data. BBSRC expects that all data (with accompanying metadata) should be shared in a timely fashion as soon as it is verified. It is expected that timely release would generally be no later than the release through publication of the main findings and should be in-line with established best practice in the field. Where best practices does not exist release within three years of generation of the dataset is suggested as a guide.
The timescale for release for the data may differ for several reasons, depending on the nature of the data. These reasons may include:
Scientific Area: Researchers are expected to make data available in-line with established practices within the relevant research community. Examples include:
Crystallography (Protein Data Bank) - the community has agreed a maximum 12-month delay between publishing the first paper on a structure and making coordinates public for secondary use.
Sequencing (EMBL Nucleotide Sequence database) – submitted data can be withheld from public access until publication of results but no later.
Metabolomics (MeT-RO) – Up to a six-month delay in publication can be requested.
Arabidopsis microarray data (NASC Affymetrix service) – all data are made available after a maximum one-year confidential period.
Intellectual Property (IP) issues and potential for commercialisation of research outputs: New knowledge generates patentable ideas. BBSRC is also driving a policy of Knowledge Transfer and strongly encourages the commercialisation of IP through various initiatives. BBSRC recognises the need for periods of exclusive use of data but considers that commercialisation of research does not preclude data sharing and should not unduly delay or prevent data sharing. Any IP issues or plans for commercialisation should be highlighted in the case for support of the grant application.
Length or scope of research project: Data from large studies may be released in waves as they become available or as they are published.
"
- number: 1
- section: bbsrc_7
- themes: timeframe_for_data_sharing
-
-bbsrc_8_1:
- text: "Format of the final dataset"
- guidance: ""
- number: 1
- section: bbsrc_8
- themes: data_format
-
-cruk_1_1:
- text: "The volume, type, content and format of the final dataset"
- guidance: ""
- number: 1
- section: cruk_1
- themes: description_of_data_content, data_format, data_volumes, data_type
-
-cruk_2_1:
- text: "The standards that will be utilised for data collection and management"
- guidance: ""
- number: 1
- section: cruk_2
- themes: data_capture_methods, metadata_standards
-
-cruk_3_1:
- text: "The metadata, documentation or other supporting material that should accompany the data for it to be interpreted correctly"
- guidance: "
For data sharing to be a success it is important that data are prepared in such a way that those using the dataset have a clear understanding of what the data mean so that they can be used appropriately. To enable this, applicants are encouraged to include with the dataset all the necessary information (metadata) describing the data and their format. This information should include such information as the methodology used to collect data, definitions of variables, units of measurement, any assumptions made, the format of the data, file type of the data etc. To support this researchers are strongly encouraged to utilise community standards to describe and structure data, (e.g. common terminology, minimum information guidelines and standard data exchange formats).
"
- number: 1
- section: cruk_3
- themes: documentation, metadata_capture, data_quality
-
-cruk_4_1:
- text: "The method used to share data"
- guidance: "
The methods used to share data will be dependent on a number of factors such as the type, size, complexity and sensitivity of data. Data can be shared by any of the following methods:
Under the auspices of the Principal Investigator
Investigators sharing under their own auspices may securely send data to a requestor, or upload the data to their institutional website. Investigators should consider using a data-sharing agreement (see below) to impose appropriate limitations on the secondary use of the data.
Through a third party
Investigators can share their data by transferring it to a data archive facility to distribute more widely to the scientific community, to maintain documentation and meet reporting requirements. Data archives are particularly attractive for investigators concerned about managing a large volume of requests for data, vetting frivolous or inappropriate requests, or providing technical assistance for users seeking to help with analyses.
Using a data enclave
Datasets that cannot be distributed to the general public due to confidentially concerns, or third-party licensing or use agreements that prohibit redistribution, can be accessed through a data enclave. A data enclave provides a controlled secure environments in which eligible researchers can perform analyses using restricted data resources.
Through a combination of methods
Investigators may wish to share their data by a combination of the above methods or in different versions, in order to control the level of access permitted.
"
- number: 1
- section: cruk_4
- themes: discovery_by_users, method_for_data_sharing, data_repository
-
-cruk_5_1:
- text: "The timescale for public release of data"
- guidance: "
As the value of data is often dependent on its timeliness Cancer Research UK expects that data sharing should occur in a timely manner. Cancer Research UK acknowledges that the investigators who generated the data have a legitimate interest in benefiting from their investment of time and effort and we therefore support the initial investigator having a reasonable period of private use of the data but not prolonged exclusive use.
Cancer Research UK expects data to be released no later than the acceptance for publication of the main findings from the final dataset (unless restrictions from third party agreements or IP protection still apply) or on a timescale in line with the procedures of the relevant research area. For example, for crystallography data there is an agreed 12-month delay between publishing the first paper on a structure and making the co-ordinates public.
With experiments carried out over an extended period of time, (e.g. population based studies), it is reasonable to expect that subsets of data analysed by the investigator(s) be made available for sharing. The investigator(s) can then continue to benefit from further reasonable periods of exclusive analysis while the dataset as a whole matures.
"
- number: 1
- section: cruk_5
- themes: timeframe_for_data_sharing
-
-cruk_6_1:
- text: "The long-term preservation plan for the dataset"
- guidance: "
Once the funding for a project has ceased researchers should preserve all data resulting from that grant to ensure that data can be used for follow-up or new studies. Cancer Research UK expects that data be preserved and available for sharing with the science community for a minimum period of five years following the end of a research grant.
"
- number: 1
- section: cruk_6
- themes: preservation_plan
-
-cruk_7_1:
- text: "Whether a data sharing agreement will be required"
- guidance: "
Data Sharing Agreements
To ensure that data are used appropriately investigators may consider implementing a data sharing agreement that indicates the criteria for data access and conditions for research use. This can ensure the responsibilities of both parties, along with intellectual property, citation and publication rights are agreed at the outset. It may incorporate privacy and confidentiality standards, as needed, to ensure data security at the recipient site and prohibit manipulation of data. For further guidance on managing data access and the development of data sharing agreements please refer to the 'Samples and Data for Cancer Research: Template for Access Policy Development' document available from the NCRI website.
Data Acknowledgement
As a minimum, researchers using shared data are expected to acknowledge the investigators who generated the data upon which any published findings are based. When both parties have collaborated using a shared dataset, co-authorship on publications may be more appropriate. Researchers using shared data are also expected to acknowledge Cancer Research UK for supporting the original study.
"
- number: 1
- section: cruk_7
- themes: managed_access_procedures
-
-cruk_8_1:
- text: "Any reasons why there may be restrictions on data sharing?"
- guidance: "
Data which might have the potential to be exploited commercially or otherwise to deliver patient benefit should be discussed with your technology transfer office and Cancer Research Technology prior to data sharing. Cancer Research UK encourages the appropriate filing of patents and recognises that there may be a need to delay the release of data until patent applications have been filed. Whilst there may be a delay in the release of data due to the application process, appropriate intellectual property protection should not hinder data sharing and may be the best way of ensuring that patient (and public) benefit is delivered. Any intellectual property issues or plans for commercialisation that may affect data sharing should be addressed in the data sharing plan. Cancer Research UK understands that unexpected intellectual property may arise during the course of the study and investigators may need to depart from their data sharing plan to protect intellectual property and for any other necessary steps to be taken. Data sharing may also be affected when co-funding is provided by the private sector (e.g. by a pharmaceutical company) or host institution resulting in some restrictions on the disclosure of data. For example with clinical trials, the Trial Management Group and/or trial sponsor etc may impose restrictions on data access. Any restrictions should be outlined in the data sharing plan and applicants should explore ways data sharing requests can be considered by the body that owns the data.
e.g. Development arrangements through Cancer Research Technology including intellectual property protection and commercialisation
e.g. Proprietary Data - restrictions due to collaborations with for profit organisations International policies governing the sharing of data collected outside of the UK
My research seeks supports from both the public and private sectors. How do I deal with the sharing of data? Where research is funded by a commercial sponsor, restrictions on data sharing may apply in arrangements agreed with the sponsor. Any such restriction(s) should be highlighted in the data management and sharing plan. In the event that researchers apply for or receive commercial funding for any part of their research that Cancer Research UK supports they should advise Cancer Research Technology of the situation without delay.
e.g. Confidentiality, ethical or consent issues that may arise with the use of data involving human subjects.
Investigators carrying out research involving human participants must ensure that consent is obtained to share information; furthermore the necessary legal, ethical and regulatory permissions regarding data sharing should be in place prior to disclosing any data. Every effort must be made to protect the identity of participants and, prior to sharing, data should be anonymised. In addition, any indirect identifiers that may lead to deductive disclosures should be removed to reduce the risk of identification. In most instances, sharing data should be possible without compromising the confidentiality of participants but if there are circumstances where data needs to be restricted due to the inability to protect confidentiality this should be fully addressed in the data management and sharing plan.
"
- number: 1
- section: cruk_8
- themes: restrictions_on_sharing, ipr_ownership_and_licencing, licensing_of_existing_data, ethical_issues
-
-esrc_1_1:
- text: "An explanation of the existing data sources that will be used by the research project (with references)"
- guidance: "
When creating new data sources, explain why existing data sources can not be re-used. If purchasing or re-using existing data sources, explain whether issues such as copyright and IPR have been addressed to ensure that the data can be shared i.e. explain how you plan to deal with permissions to share data you have created which is derived from data which you do not own.
The following sources can be reviewed for the availability of existing data that could be used:
Data Catalogue - an integrated catalogue containing over 5,000 datasets covering an extensive range of key economic, social and historical data - both quantitative and qualitative - spanning many disciplines and themes, and with links to census data
ESRC Research Catalogue - the ESRC's repository of past and present research awards and their outputs
"
- number: 1
- section: esrc_1
- themes: existing_data, licensing_of_existing_data
-
-esrc_1_2:
- text: "An analysis of the gaps identified between the currently available and required data for the research"
- guidance: "
When creating new data sources, explain why existing data sources can not be re-used. If purchasing or re-using existing data sources, explain whether issues such as copyright and IPR have been addressed to ensure that the data can be shared i.e. explain how you plan to deal with permissions to share data you have created which is derived from data which you do not own.
The following sources can be reviewed for the availability of existing data that could be used:
Data Catalogue - an integrated catalogue containing over 5,000 datasets covering an extensive range of key economic, social and historical data - both quantitative and qualitative - spanning many disciplines and themes, and with links to census data
ESRC Research Catalogue - the ESRC's repository of past and present research awards and their outputs
"
- number: 2
- section: esrc_1
- themes: relationship_to_existing_data
-
-esrc_2_1:
- text: "Data volume and data type, e.g. qualitative or quantitative data"
- guidance: "
Give a brief description of new data which you envisage creating. This information should include how the data will be collected (in line with the proposed research methods), their format (e.g. SPSS, Open Document Format, tab-delimited format, MS Excel), and how they will be documented.
Using standardised and interchangeable or open lossless data formats ensures the long-term usability of data. Clear and detailed data descriptions and annotation, together with user-friendly accompanying documentation on methods and contextual information, makes data easy to understand and interpret and therefore shareable and with long-lasting usability.
Give a brief description of new data which you envisage creating. This information should include how the data will be collected (in line with the proposed research methods), their format (e.g. SPSS, Open Document Format, tab-delimited format, MS Excel), and how they will be documented.
Using standardised and interchangeable or open lossless data formats ensures the long-term usability of data. Clear and detailed data descriptions and annotation, together with user-friendly accompanying documentation on methods and contextual information, makes data easy to understand and interpret and therefore shareable and with long-lasting usability.
Give a brief description of new data which you envisage creating. This information should include how the data will be collected (in line with the proposed research methods), their format (e.g. SPSS, Open Document Format, tab-delimited format, MS Excel), and how they will be documented.
Using standardised and interchangeable or open lossless data formats ensures the long-term usability of data. Clear and detailed data descriptions and annotation, together with user-friendly accompanying documentation on methods and contextual information, makes data easy to understand and interpret and therefore shareable and with long-lasting usability.
Quality control of data is an integral part of a research process. Describe the procedures for quality assurance that will be carried out on the data collected at the time of data collection, data entry, digitisation and data checking.
For example this might include:
Documenting the calibration of instruments
Taking duplicate samples or measurements
Standardised data capture, data entry or recording methods
Describe the data back-up procedures that you will adopt to ensure the data and metadata are securely stored during the lifetime of the project. You may need to discuss your institution's policy on back-ups. If your data is sensitive (e.g. detailed personal data) you should discuss appropriate security measures which you will be taking.
The methods of version control of data files should also be stated. Version control includes making sure that if the information in one file is altered, the related information in other files is also adapted, as well as keeping track of versions of data files and their locations.
"
- number: 2
- section: esrc_3
- themes: backup_procedures, data_security, data_organisation
-
-esrc_4_1:
- text: "Plans for management and archiving of collected data"
- guidance: "
Outline your plans for preparing and documenting data for sharing and archiving (unless otherwise agreed). Identify any additional plans for data sharing, if any. A crucial part of making data user-friendly, shareable and with long-lasting usability is to ensure they can be understood and interpreted by other users. This requires clear and detailed data description, annotation and contextual information.
"
- number: 1
- section: esrc_4
- themes: data_selection, preservation_plan, documentation
-
-esrc_5_1:
- text: "Expected difficulties in data sharing, along with causes and possible measures to overcome these difficulties."
- guidance: "
We require that all applicants seeking ESRC funding include a statement on data sharing in the relevant section of the Je-S application form. If data sharing is not possible, the applicant must present a strong argument to justify their case. We reserve the right to decline the request or demand additional information from the applicant.
Data Protection and Freedom of Information
We expect grant holders to adhere to the Data Protection Act 1998, which contains eight (enforceable) principles of good practice, applying to anyone processing personal data, including the use of personal data in research. These include obtaining the data subject’s consent or meeting at least one of the ‘necessary’ conditions described in the Act.
The ESRC complies with the requirements of the Freedom of Information Act 2000 that establishes a general right of access to all types of recorded information held by public authorities, including Government Departments and Non-Departmental Public Bodies.
If the Principal Investigator does not state to the contrary in the Je-S application form, it will be assumed that they are willing for their contact details and other relevant information to be shared with the relevant data service provider working with the ESRC.
"
- number: 1
- section: esrc_5
- themes: restrictions_on_sharing, managed_access_procedures
-
-esrc_6_1:
- text: "Explicit mention of consent, confidentiality, anonymisation and other ethical considerations"
- guidance: "
In facilitating innovative and high quality research, we require that the research we supports will be carried out to a high ethical standard. ESRC grant holders are, therefore, required to adhere to the key principles of ethical research addressed in the ESRC Framework for Research Ethics
"
- number: 1
- section: esrc_6
- themes: ethical_issues
-
-esrc_7_1:
- text: "Copyright and intellectual property ownership of the data"
- guidance: "
Intellectual Property Rights
In respect of research grant funding, unless stated otherwise, the ownership of intellectual property and responsibility for its exploitation, rests with the organisation carrying out the research. The ESRC may, in specific cases, reserve the right to retain ownership of the intellectual property and to arrange for it to be exploited for the national benefit in other ways. If exercised, this condition is included in the terms of the relevant award.
In taking responsibility for exploiting intellectual property, we expect the research organisation to ensure that individuals associated with the research understand the arrangements for exploitation. Where research is funded by or undertaken in collaboration with others, the research organisation is responsible for putting appropriate formal agreements in place covering the contributions and rights of the various organisations and individuals involved. Such agreements must be in place before the research begins. Research organisations are required to ensure that the terms of collaboration agreements do not conflict with the Terms and Conditions for Research Council Grants.
Copyright
The ESRC expects grant holders to meet the copyright requirements set down in the Copyright, Designs and Patents Act 1988. Responsibility for ensuring compliance with all laws and other legal instruments rests with the grant holders and/or their institutions. We will not accept liability for any complaint or legal action taken against a researcher or the ESDS for infringements of copyrights, defamation or any other data protection requirements.
"
- number: 1
- section: esrc_7
- themes: ipr_ownership_and_licencing
-
-esrc_8_1:
- text: "Responsibilities for data management and curation within research teams at all participating institutions"
- guidance: "
Indicate who within your research team will be responsible for data management, metadata production, dealing with quality issues and the final delivery of data for sharing or archiving. Provide this information within the Staff Duties section in the Je-S form and where appropriate in the Justification of Resources. If several people will be responsible state their roles and responsibilities in the relevant section of the Je-S form. For collaborative projects you should explain the co-ordination of data management responsibilities across partners in your Data Management Plan.
"
- number: 1
- section: esrc_8
- themes: project_data_contact, responsibilities
-
-nerc_1_1_1:
- text: Data management procedures to be followed during the lifetime of the grant or fellowship
- guidance: "
Consider issues like:
metadata: will you document discovery (what, where, when, why, who) and descriptive (how collected, how processed, how stored, how linked) metadata and implement the NERC Discovery Metadata Standard (http://data-search.nerc.ac.uk/documents/metadatastandard_v1.0.pdf) early in the project?
data storage: have you access to enough storage and backup? Will you need specialist help with database design?
data quality: will there be an earmarked data manager within the team, what data quality checks will be used, will student data be integrated in the data plan?
ethical and access issues: are there special data security or licensing issues and how will you address these?
"
- number: 1
- section: nerc_1_1
- themes: metadata_capture, active_data_storage, data_quality, ethical_issues, managed_access_procedures
-
-nerc_1_2_1:
- text: Existing datasets to be used by the grant or fellowship
- guidance: "
Comment on any restrictions on reuse.
"
- number: 1
- section: nerc_1_2
- themes: existing_data, licensing_of_existing_data
-
-nerc_1_3_1:
- text: Data Centre
- guidance: "
The most appropriate NERC Data Centre – projects can contribute to more than one Data Centre.
Possible user types and estimate of numbers if possible.
"
- number: 4
- section: nerc_1_3
- themes: expected_reuse
-
-nerc_2_1_1:
- text: Nominated Data Centre
- number: 1
- section: nerc_2_1
- themes: data_repository
-
-nerc_2_1_2:
- text: Data Centre Contact
- number: 2
- section: nerc_2_1
-
-nerc_2_1_3:
- text: Please specify any other team members with responsibility for data
- number: 3
- section: nerc_2_1
-
-nerc_2_2_1:
- text: Roles and Responsibilities
- guidance: "
For example: who is responsible for obtaining 3rd party data, for capturing data in the field, producing metadata, transferring metadata and data to DDC.
Any exceptional expectations of Data Centres (for example exceptional size or complexity) - funding for which should be included within the project's Directly Incurred costs and explained within the Justification of Resources attachment.
"
- number: 1
- section: nerc_2_7
- themes: resourcing_preservation_and_data_sharing
-
-nerc_2_8_1:
- text: Digital Information
- guidance: "
Enter a brief description of the activities that will produce the data.
Enter a brief description of the activities that will produce the data
"
- number: 3
- section: nerc_2_8
- themes: data_capture_methods,project_data_contact,data_volumes,data_format,ipr_ownership_and_licencing,timeframe_for_data_sharing,preservation_plan
-
-nerc_2_9_1:
- text: Third Party/Existing Datasets
- number: 1
- section: nerc_2_9
- themes: existing_data, data_volumes, responsibilities, licensing_of_existing_data, restrictions_on_sharing
-
-mrc_1_1:
- text: Type of Study
- guidance: "
Up to three lines of text that summarise the type of study (or studies) for which the data are being collected.
"
- number: 1
- section: mrc_1
- themes: project_description
-
-mrc_1_2:
- text: Types of Data
- guidance: "
Types of research data to be managed in the following terms: quantitative, qualitative; generated from surveys, clinical measurements, interviews, medical records, electronic health records, administrative records, genotypic data, images, tissue samples,...
"
- number: 2
- section: mrc_1
- themes: data_type
-
-mrc_1_3:
- text: Format and scale of the data
- guidance: "
File formats, software used, number of records, databases, sweeps, repetitions,… (in terms that are meaningful in your field of research). Do formats and software enable sharing and long-term validity of data?
How consistency and quality of data collection / generation will be controlled and documented, through processes of calibration, repeat samples or measurements, standardised data capture or recording, data entry validation, peer review of data or representation with controlled vocabularies.
Briefly, how data will be stored, backed-up, managed and curated in the short to medium term. Specify any community agreed or other formal data standards used (with URL references). [Enter data security standards in Section 4].
Plans for documenting, annotating and describing data so that research data are usable by others than your own team. This may include documenting the methods used to generate the data, analytical and procedural information, capturing instrument metadata alongside data, documenting provenance of data and their coding, detailed descriptions for variables, records, etc.
Plans and place for long-term storage, preservation and planned retention period for the research data. Formal preservation standards, if any. Indicate which data may not be retained (if any).
Identify formal information standards with which your study is or will be compliant. An example is ISO 27001.
"
- number: 1
- section: mrc_4
- themes: data_security
-
-mrc_4_2:
- text: Main risks to data security
- guidance: "
If not using formal standards, summarise the main risks to the confidentiality and security of information related to human participants, and how these risks will be managed. Cover the main processes or facilities for storage and processing of personal data, data access, with controls put in place and any auditing of user compliance with consent and security conditions.
MRC guidance on the categories of data availability is provided.
Identify any data repository (-ies) that are, or will be, entrusted with storing, curating and/or sharing data from your study, where they exist for particular disciplinary domains or data types. Information on repositories is available here.
Indicate whether the data you propose to collect (or existing data you propose to use) in the study will be suitable for sharing. (“Yes” or “No”)
If “No,” indicate why they will not be suitable for sharing and then go to Section 6.
"
- number: 2
- section: mrc_5
-
-mrc_5_3:
- text: Discovery by potential users of the research data
- guidance: "
Indicate how potential new users can find out about your data and identify whether they could be suitable for their research purposes, e.g. through summary information (metadata) being readily available on the study website, in the MRC gateway for population and patient research data, or in other databases or catalogues. Indicate whether your policy or approach to data sharing is (or will be) published on your study website (or by other means).
Identify who makes or will make the decision on whether to supply research data to a potential new user.
For population health and patient-based research, indicate how independent oversight of data access and sharing works (or will work) in compliance with MRC policy.
Indicate whether the research data will be deposited in and available from an identified community database, repository, archive or other infrastructure established to curate and share data.
"
- number: 4
- section: mrc_5
- themes: managed_access_procedures, method_for_data_sharing
-
-mrc_5_5:
- text: The study team’s exclusive use of the data
- guidance: "
MRC’s requirement is for timely data sharing, with the understanding that a limited, defined period of exclusive use of data for primary research is reasonable according to the nature and value of the data, and that this restriction on sharing should be based on simple, clear principles.
Summarise the principles of your current/intended policy.
"
- number: 5
- section: mrc_5
- themes: timeframe_for_data_sharing
-
-mrc_5_6:
- text: Restrictions or delays to sharing, with planned actions to limit such restrictions
- guidance: "
Restriction to data sharing may be due to participant confidentiality, consent agreements or IPR. Strategies to limit restrictions may include data being anonymised or aggregated; gaining participant consent for data sharing; gaining copyright permissions. For prospective studies, consent procedures should include provision for data sharing to maximise the value of the data for wider research use, while providing adequate safeguards for participants. As part of the consent process, proposed procedures for data sharing should be set out clearly and current and potential future risks associated with this explained to research participants.
Specify who, alongside the PI, is responsible for ensuring the study-wide data management, as well as for specific roles such as metadata creation, data security and quality assurance of data.
"
- number: 1
- section: mrc_6
- themes: responsibilities
-
-mrc_6_2:
- text: Relevant institutional, departmental or study policies on data sharing and data security
- guidance: "
List policy, URL & reference
Please complete, where such policies are (i) relevant to your study, and (ii) are in the public domain, e.g. accessibly through the internet. Add any others that are relevant
"
- number: 2
- section: mrc_6
- themes: related_policies
-
-stfc_1_1:
- text: Specify the types of data the research will generate.
- guidance: "
Data management plans should describe the types of data that are expected to be produced from the project, including the raw data arising directly from the research, the reduced data derived from it, and published data.
"
- number: 1
- section: stfc_1
- themes: data_type
-
-stfc_2_1:
- text: Specify which data will be preserved and how.
- guidance: "
Unless there are compelling reasons not to do so, STFC expects data to be managed through an established repository, chosen to maximise the scientific value from aggregation of related data. This may be at the grant holder's institution or elsewhere. Data management plans may refer to the general policies of the chosen repository and only include further details if necessary to the specific project. (If it is proposed not to use an established repository, the data management plan will need to demonstrate that resources and systems will be in place to enable the data to be curated effectively beyond the lifetime of the grant, although STFC recognises that applicants may not have the expertise to describe in detail how data will be curated).
The data management plan should specify the software and metadata that will be retained to enable the data to be read and interpreted.
"
- number: 1
- section: stfc_3
- themes: documentation, metadata_standards
-
-stfc_4_1:
- text: Specify for how long the data will be preserved.
- guidance: "
This may depend on the type of data. Where possible, STFC expects the original data, from which other related data can in principle be derived, to be retained for a minimum of 10 years from the end of the project. For data that by their nature cannot be re-measured, efforts should be made to retain them indefinitely.
"
- number: 1
- section: stfc_4
- themes: period_of_preservation
-
-stfc_5_1:
- text: Specify and justify which data will have value to others and should be shared.
- guidance: "
Any data that are shared should be of a sufficiently high quality to be of value to other researchers. In general, published data – data that are displayed or otherwise referred to in a publication – should be made publicly available, but it is for applicants to consider and justify which types of data will, in the context of their project, meaningfully and practically constitute published data. Publicly available means available to anyone, but there may be a requirement for registration to enable tracking of data use and to provide notification of terms and conditions of use where they apply. Other data should be made available wherever it is appropriate and cost-effective to do so, taking into account the cost of curation compared with the cost or feasibility of re-creation, the potential long-term demand for the data and the feasibility of their reuse by others.
"
- number: 1
- section: stfc_5
- themes: audience, expected_reuse, data_selection
-
-stfc_6_1:
- text: Specify and justify the length of any proprietary period.
- guidance: "
This might for example refer to the reasonable needs of the research team to have a first opportunity to exploit the results of their research, including any intellectual property arising. Where there are accepted norms within a scientific field or specific archive they should normally be followed. In general, STFC expects that published data should be made publicly available within six months of publication unless justified otherwise.
"
- number: 1
- section: stfc_6
- themes: timeframe_for_data_sharing
-
-stfc_7_1:
- text: Specify how data will be shared
- guidance: "
The minimum level of data sharing expected would be that of making the data available in the natural format in which they were created, along with documentation and metadata, according to the standard accepted procedures within the scientific field. Where the data are likely to be in great demand by others it may be appropriate to request resources for a more proactive approach to data sharing, which maximises opportunities for cross linkage with other sectors.
"
- number: 1
- section: stfc_7
- themes: method_for_data_sharing
-
-stfc_8_1:
- text: Specify and justify any resources required to preserve and share the data.
- guidance: "
Wherever possible, data management should make use of existing skills and capabilities. However, justification should be made for any additional specialist staff (or training for existing staff) needed within the grant to enable the research team to manage, preserve and share data effectively; and for any computational facilities needed to manage, store and share the data generated by the research.
"
- number: 1
- section: stfc_8
- themes: resourcing_preservation_and_data_sharing, resourcing_skills_and_training
-
-wellcome_1_1:
- text: What data outputs will your research generate and what data will have value to other researchers?
- guidance: "
Researchers should maximise access to research datasets of value to the wider research community in a timely and responsible manner. Any data that is shared should be of a sufficiently high quality that it will have value to other researchers and should be provided in a format that enables it to be used effectively.
We recognise that in some cases it may not be appropriate for researchers to share their data. However, if your research meets the criteria for requiring a data management and sharing plan but you are intending not to share your data, the reasons for this must be clearly justified.
Data should be shared in accordance with recognised data standards where these exist, and in a way that maximises opportunities for data linkage and interoperability. Sufficient metadata must be provided to enable the dataset to be used by others. Agreed best practice standards for metadata provision should be adopted where these are in place.
When developing data management and sharing plans, researchers should therefore consider and briefly describe:
what types of data the proposed research will generate?
which data will have value to other research users and could be shared?
what data formats and quality standards will be applied to enable the data to be shared effectively?
"
- number: 1
- section: wellcome_1
- themes: description_of_data_content, data_selection, audience, data_format, data_quality, data_type
-
-wellcome_2_1:
- text: When will you share the data?
- guidance: "
All data management and sharing plans must state clearly the timescales over which datasets of value will be shared. Such timescales should take account of any recognised standards of good practice in the applicant's research field.
In considering the timescales that are appropriate, the Trust recognises fully that data generators have the right to a reasonable (but not unlimited) period of exclusive use for the research data that they produce.
As set out in our guidelines on good research practice, all grant holders must ensure as an absolute minimum that the data underpinning research papers are made available to other researchers on publication, providing this is consistent with any ethics approvals and consents which cover the data and any intellectual property rights in them.
In cases where the creation of a database resource is the primary goal of a Trust-funded activity, we would normally expect the data to be made widely available to user communities at the earliest feasible opportunity.
In line with the Fort Lauderdale Principles and subsequent Toronto statement on pre-publication data sharing, the Trust also encourages timely and responsible pre-publication data sharing for research that might constitute a \"community resource\" (i.e. those that have the characteristics set out in point 7 above).
Where appropriate, researchers may use publication moratoria to facilitate pre-publication sharing of data with other researchers, while protecting their right to first publication. Any such restrictions on data use should be reasonable, transparent and in line with established best practice.
Illustrative examples of timescales for data sharing are provided to help demonstrate different models that have been adopted and may be considered as examples of good practice in the field of large-scale genetics and genomics studies.
"
- number: 1
- section: wellcome_2
- themes: timeframe_for_data_sharing
-
-wellcome_3_1:
- text: Where will you make the data available?
- guidance: "
Researchers should deposit data in recognised data repositories where these exist for particular data types, unless there is a compelling reason not to do so. Further information on repositories that may be appropriate
If the intention is to create a tailored database resource or to store data locally, researchers should ensure that they have the resources and systems in place so that the data are curated, secured and shared in an way that maximises its value and safeguards any associated risks.This includes consideration of how data held in this way can be effectively linked and integrated with other datasets to enhance its value to users.
"
- number: 1
- section: wellcome_3
- themes: method_for_data_sharing, data_repository
-
-wellcome_4_1:
- text: How will other researchers be able to access the data?
- guidance: "
Data should be made available to other researchers with as few restrictions as possible. Where a managed access process is required - for example, where a study involves potentially identifiable data about research participants - the access mechanisms established should be proportionate to the risks associated with the data, and must not unduly restrict or delay access. Any managed access procedures that are proposed must be described clearly as part of your data management and sharing plan.
Depending on the study, it may be appropriate to establish a graded access procedure in which less sensitive data (e.g. anonymised and aggregate data) are made readily available, whereas applications to access to more sensitive datasets are subject to a more stringent assessment process.
Any managed access procedures should be consistent and transparent. In cases where a Data Access Committee is required to assess applications to access data, the composition of such Committees should include individuals with appropriate expertise who are independent of the project.
Where appropriate, the Trust would encourage those generating datasets that are likely to be of significant value to other researchers to publish a 'marker paper' or other form of publication, which enables data users to formally cite their usage of the resource.
Where a database resource is being developed as part of a funded activity, researchers should take reasonable steps to ensure that potential users are made aware of its availability. These should be outlined briefly in your plan.
"
- number: 1
- section: wellcome_4
- themes: managed_access_procedures, method_for_data_sharing
-
-wellcome_5_1:
- text: Are any limits to data sharing required - for example, to either safeguard research participants or to gain appropriate intellectual property protection?
- guidance: "
For some research, delays or limits on data sharing may be necessary and appropriate to safeguard research participants or to ensure intellectual property protection is gained. Any such restrictions should, however, be minimised as far as feasible and set out clearly in data management and sharing plans where these are required.
Safeguarding Research Participants
For research involving samples or information pertaining to human subjects, data must be managed and shared in a way which is fully consistent with the terms of the consent under which samples and data were provided by the research participants.
For prospective studies, consent procedures should include provision for data sharing in a way that maximises the value of the data for wider research use, while providing adequate safeguards for participants. As part of the consent process, proposed procedures for data sharing should be set out clearly and current and potential future risks associated with this explained to research participants.
In designing studies, researchers must ensure that they have appropriate systems to protect the confidentiality and security of data pertaining to human subjects, and minimise any risks of identification by data users. This can be achieved through the use of appropriate anonymisation procedures and managed access processes. Such systems should be sufficient to safeguard participants, but proportionate to the level of sensitivity of the data and associated risk. They should not unduly inhibit responsible data sharing for legitimate research uses.
Intellectual Property
In line with our policy on intellectual property and patenting, we expect our funded researchers to ensure that any intellectual property in the outputs of their research is suitably protected and managed in a way that best enables the use of that knowledge for ultimate health benefit.
Delays or restrictions on data sharing may be appropriate to gain intellectual property protection or to further development of a technology for public benefit. As noted above, any such limits should be minimised as far as is feasible.
"
- number: 1
- section: wellcome_5
- themes: restrictions_on_sharing, data_security, ethical_issues, ipr_ownership_and_licencing
-
-wellcome_6_1:
- text: How will you ensure that key datasets are preserved to ensure their long-term value?
- guidance: "
Researchers must consider how datasets that have long-term value will be preserved and curated beyond the lifetime of the grant. If the proposal is to create a bespoke data resource or to store data locally rather than to use a recognised data repository, data management plans should state clearly how the applicant expects that the dataset will be preserved and shared when the period of grant funding comes to an end.
The Trust is happy to discuss issues relating to longer-term preservation and sustainability with researchers so as to help provide the support required to maximise the long-term value of key research datasets.
"
- number: 1
- section: wellcome_6
- themes: preservation_plan, data_repository
-
-wellcome_7_1:
- text: What resources will you require to deliver your plan?
- guidance: "
In preparing data management and sharing plans, researchers should consider carefully any resources they may need to deliver their plan.Where dedicated resources are required, these should be outlined and justified as part of the plan.
Issues to consider include:
People and skills - is there sufficient expertise and resource in the research team to manage, preserve and share the data effectively?Is additional specialist expertise (or training for existing staff) required? If so, how will this be sourced?
Infrastructure - are there appropriate computational facilities to manage, store and analyse the data generated by the research?
Tools - will additional computational facilities and resources need to be accessed, and what will be the costs associated with this?
"
- number: 1
- section: wellcome_7
- themes: resourcing_skills_and_training, resourcing_hardware_and_software, resourcing_preservation_and_data_sharing
diff --git a/test/fixtures/roles.yml b/test/fixtures/roles.yml
deleted file mode 100644
index 5da7d93..0000000
--- a/test/fixtures/roles.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-<% # Load the roles from those defined within the MagicStrings section of the locale %>
-<% I18n.t("magic_strings.user_role_types").each do |k,v| %>
-<%= v %>:
- name: <%= "#{v}" %>
-<% end %>
diff --git a/test/fixtures/sections.yml b/test/fixtures/sections.yml
deleted file mode 100644
index ae406fd..0000000
--- a/test/fixtures/sections.yml
+++ /dev/null
@@ -1,48 +0,0 @@
-# Produces:
-# -----------------------------
-# Generates 2 Sections for each Version of a published template and 4 Sections for
-# each Version of an unpublished template
-# (see dmptemplates.yml, phases.yml and versions.yml)
-#
-# [template]_phase_1_version_1_section_[1..2]
-# [template]_unpublished_phase_[1..2]_version_[1..2]_section_[1..4]
-#
-# The complete organisation has 2 sections attached to its template and 2
-# customisations
-#
-# complete_customised_template_phase_1_version_1_section_[1..2]
-#
-
-# Import versions.yml so that we can dynamically generate sections
-<% versions = YAML::load(ERB.new(File.read('./test/fixtures/versions.yml')).result) %>
-
-<% versions.each do |lbl, hash| %>
- <% if lbl.include?('customised_') %>
-
- <% 2.times do |n| %>
-<%= lbl %>_customisation_<%= n + 1 %>:
- title: <%= "#{(n == 0) ? 'Licensing (Customisation)' : 'Access (Customisation)'}" %>
- number: <%= 3 + n %>
- version: <%= lbl %>
- organisation: complete
- <% end %>
-
- <% else %>
-
- <% 2.times do |x| %>
-<%= lbl %>_section_<%= x + 1 %>:
- title: <%= "#{(x == 0) ? 'Data Collection' : 'Storage and Backup'}" %>
- number: <%= x + 1 %>
- version: <%= lbl %>
- <% end %>
-
- <% if lbl.include?('_unpublished') %>
- <% 2.times do |y| %>
-<%= lbl %>_section_<%= y + 3 %>:
- title: <%= "#{(y == 0) ? 'Documentation' : 'Compliance'}" %>
- number: <%= 3 + y %>
- version: <%= lbl %>
- <% end %>
- <% end %>
- <% end %>
-<% end %>
diff --git a/test/fixtures/templates.yml b/test/fixtures/templates.yml
deleted file mode 100644
index 937a0c0..0000000
--- a/test/fixtures/templates.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
-
-# This model initially had no columns defined. If you add columns to the
-# model remove the '{}' from the fixture names and add the columns immediately
-# below each fixture, per the syntax in the comments below
-#
-one: {}
-# column: value
-#
-two: {}
-# column: value
diff --git a/test/fixtures/themes.yml b/test/fixtures/themes.yml
deleted file mode 100644
index d02ca85..0000000
--- a/test/fixtures/themes.yml
+++ /dev/null
@@ -1,176 +0,0 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
-
-related_policies:
- title: Related Policies
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-existing_data:
- title: Existing Data
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-licensing_of_existing_data:
- title: Licensing of Existing Data
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-relationship_to_existing_data:
- title: Relationship to Existing Data
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-description_of_data_content:
- title: Description of Data Content
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-data_format:
- title: Data Format
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-data_volumes:
- title: Data Volumes
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-data_type:
- title: Data Type
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-data_capture_methods:
- title: Data Capture Methods
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-data_organisation:
- title: Data Organisation
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-data_quality:
- title: Data Quality
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-documentation:
- title: Documentation
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-metadata_capture:
- title: Metadata Capture
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-metadata_standards:
- title: Metadata Standards
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-discovery_by_users:
- title: Discovery by Users
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-ethical_issues:
- title: Ethical Issues
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-ipr_ownership_and_licencing:
- title: IPR Ownership and Licencing
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-active_data_storage:
- title: Active Data Storage
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-backup_procedures:
- title: Backup Procedures
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-data_security:
- title: Data Security
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-data_selection:
- title: Data Selection
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-preservation_plan:
- title: Preservation Plan
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-period_of_preservation:
- title: Period of Preservation
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-data_repository:
- title: Data Repository
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-audience:
- title: Audience
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-expected_reuse:
- title: Expected Reuse
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-method_for_data_sharing:
- title: Method For Data Sharing
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-timeframe_for_data_sharing:
- title: Timeframe For Data Sharing
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-embargo_period:
- title: Embargo Period
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-restrictions_on_sharing:
- title: Restrictions on Sharing
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-managed_access_procedures:
- title: Managed Access Procedures
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-responsibilities:
- title: Responsibilities
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-resourcing_skills_and_training:
- title: "Resourcing: Skills and Training"
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-resourcing_hardware_and_software:
- title: "Resourcing: Hardware and Software"
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
-
-resourcing_preservation_and_data_sharing:
- title: "Resourcing: Preservation and Data Sharing"
- description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- locale: en
diff --git a/test/fixtures/token_permission_types.yml b/test/fixtures/token_permission_types.yml
deleted file mode 100644
index 3c39e5b..0000000
--- a/test/fixtures/token_permission_types.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-plans_token_type:
- token_type: 'plans'
- text_description: 'allows a user access to the plans api endpoint'
-
-guidances_token_type:
- token_type: 'guidances'
- text_description: 'allows a user access to the guidances api endpoint'
\ No newline at end of file
diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml
deleted file mode 100644
index 250a3fc..0000000
--- a/test/fixtures/users.yml
+++ /dev/null
@@ -1,115 +0,0 @@
-# Produces:
-# -----------------------------
-# cc_super
-# cc_admin
-#
-# funder_admin
-#
-# complete_admin
-# complete_user
-#
-# institution_[1..2]_admin
-# institution_[1..2]_user
-#
-# school_[1..2]_admin
-# school_[1..2]_user
-#
-# project_[1..2]_admin
-# project_[1..2]_user
-#
-
-# Import organisation_types.yml and roles.yml
-<% organisation_types = YAML::load(ERB.new(File.read('./test/fixtures/organisation_types.yml')).result) %>
-
-cc_super:
- firstname: 'Curation Centre'
- surname: 'Super Admin'
- email: 'super-admin@example-cc.org'
- accept_terms: true
- organisation: curation_center
- roles: [add_organisations, change_org_affiliation, grant_api_to_orgs, grant_permissions, modify_templates, modify_guidance, change_org_details, use_api]
- api_token: "ABCD1234ZYX987supercc"
- language: en-UK
- confirmed_at: '2016-09-09 10:10:10'
-
-cc_admin:
- firstname: 'Curation Centre'
- surname: 'Administrator'
- email: 'admin@example-cc.org'
- accept_terms: true
- organisation: curation_center
- roles: [grant_permissions, modify_templates, modify_guidance, change_org_details, use_api]
- api_token: "ABCD1234ZYX987admincc"
- language: en-UK
- confirmed_at: '2016-09-09 10:10:10'
-
-funder_admin:
- firstname: 'Funder'
- surname: 'Administrator'
- email: 'admin@example-funder.org'
- accept_terms: true
- organisation: funder
- roles: [grant_permissions, modify_templates, modify_guidance, change_org_details, use_api]
- api_token: "ABCD1234ZYX987adminfunder"
- language: en-UK
- confirmed_at: '2016-09-09 10:10:10'
-
-# We unfortunatley cannot tab this out nicely because YAML is expecting the values in
-# the first column
-<% organisation_types.each do |lbl, obj| %>
- <% unless ['funder', 'organisation'].include?(lbl) %>
- <% 2.times do |x| %>
-
-<%= lbl %>_<%= x + 1 %>_admin:
- firstname: <%= "#{obj['name']} #{x + 1}" %>
- surname: "Admin"
- email: <%= "admin@example-#{lbl}-#{x + 1}.org" %>
- orcid_id: <%= "orcid-#{lbl}-#{x + 1}-admin12345" %>
- shibboleth_id: <%= "shib-#{lbl}-#{x + 1}-admin12345" %>
- accept_terms: true
- organisation: <%= lbl %>_<%= x + 1 %>
- roles: [grant_permissions, modify_templates, modify_guidance, change_org_details, use_api]
- api_token: "ABCD1234ZYX987admin#{lbl}#{x + 1}"
- language: en-UK
- confirmed_at: '2016-09-09 10:10:10'
-
-<%= lbl %>_<%= x + 1 %>_user:
- firstname: <%= "#{obj['name']} #{x + 1}" %>
- surname: "User"
- email: <%= "user@example-#{lbl}-#{x + 1}.org" %>
- orcid_id: <%= "orcid-#{lbl}-#{x + 1}-user12345" %>
- shibboleth_id: <%= "shib-#{lbl}-#{x + 1}-user12345" %>
- accept_terms: true
- organisation: <%= lbl %>_<%= x + 1 %>
- api_token: "ABCD1234ZYX987user#{lbl}#{x + 1}"
- language: en-UK
- confirmed_at: '2016-09-09 10:10:10'
-
- <% end %>
- <% end %>
-<% end %>
-
-complete_admin:
- firstname: "Complete"
- surname: "Admin"
- email: <%= "admin@example-complete.org" %>
- orcid_id: <%= "orcid-complete-admin12345" %>
- shibboleth_id: <%= "shib-complete-admin12345" %>
- accept_terms: true
- organisation: complete
- roles: [grant_permissions, modify_templates, modify_guidance, change_org_details, use_api]
- api_token: "ABCD1234ZYX987admincomplete"
- language: en-UK
- confirmed_at: '2016-09-09 10:10:10'
-
-complete_user:
- firstname: "Complete"
- surname: "User"
- email: <%= "user@example-complete.org" %>
- orcid_id: <%= "orcid-complete-user12345" %>
- shibboleth_id: <%= "shib-complete-user12345" %>
- accept_terms: true
- organisation: complete
- api_token: "ABCD1234ZYX987usercomplete"
- language: en-UK
- confirmed_at: '2016-09-09 10:10:10'
\ No newline at end of file
diff --git a/test/fixtures/versions.yml b/test/fixtures/versions.yml
deleted file mode 100644
index d4e9758..0000000
--- a/test/fixtures/versions.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-# Produces:
-# -----------------------------
-# Generates 1 Version for each Phase of a published template and 2 Versions for
-# each Phase of an unpublished template
-# (see dmptemplates.yml for template list and phases.yml for phase list)
-#
-# [template]_phase_1_version_1
-# [template]_unpublished_phase_[1..2]_version_[1..2]
-#
-# A copy of Funder Template 1 Phase 1 that contains customisations
-#
-# complete_template_customised_phase
-#
-
-# Import phases.yml so that we can dynamically generate versions
-<% phases = YAML::load(ERB.new(File.read('./test/fixtures/phases.yml')).result) %>
-
-<% phases.each do |lbl, hash| %>
-
-<%= lbl %>_version_1:
- title: <%= "hash['title'] - Version 1" %>
- number: 1
- published: true
- phase: <%= lbl %>
-
- <% if lbl.include?('_unpublished') %>
-<%= lbl %>_version_2:
- title: <%= "hash['title'] - Version 2" %>
- number: 2
- published: false
- phase: <%= lbl %>
- <% end %>
-
-<% end %>
-
-complete_customised_template_phase_1_version_1:
- title: "Customisation of Funder Template 1, Phase 1, Version 1"
- number: 1
- published: false
- phase: funder_template_1_phase_1
\ No newline at end of file
diff --git a/test/functional/answers_controller_test.rb b/test/functional/answers_controller_test.rb
deleted file mode 100644
index 9981abc..0000000
--- a/test/functional/answers_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class AnswersControllerTest < ActionController::TestCase
-=begin
- setup do
- @answer = answers(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:answers)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create answer" do
- assert_difference('Answer.count') do
- post :create, answer: { text: @answer.text, plan_id: @answer.plan_id, question_id: @answer.question_id, user_id: @answer.user_id }
- end
-
- assert_redirected_to answer_path(assigns(:answer))
- end
-
- test "should show answer" do
- get :show, id: @answer
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @answer
- assert_response :success
- end
-
- test "should update answer" do
- put :update, id: @answer, answer: { text: @answer.text, plan_id: @answer.plan_id, question_id: @answer.question_id, user_id: @answer.user_id }
- assert_redirected_to answer_path(assigns(:answer))
- end
-
- test "should destroy answer" do
- assert_difference('Answer.count', -1) do
- delete :destroy, id: @answer
- end
-
- assert_redirected_to answers_path
- end
-=end
-end
diff --git a/test/functional/application_controller_test.rb b/test/functional/application_controller_test.rb
new file mode 100644
index 0000000..df2ad7d
--- /dev/null
+++ b/test/functional/application_controller_test.rb
@@ -0,0 +1,77 @@
+require 'test_helper'
+
+class ApplicationControllerTest < ActionDispatch::IntegrationTest
+ include Devise::Test::IntegrationHelpers
+
+ setup do
+ @user = users(:cc_super)
+
+ stub_blog_calls
+ end
+
+ # In order to test methods on the application controller, we must call routes
+ # on controllers that extend the ApplicationController class.
+
+ # ----------------------------------------------------------------
+ test "make sure unauthorized users are redirected to the root path" do
+ proj = Project.first
+ get project_path(I18n.locale, proj)
+
+ assert_redirected_to "#{root_path}?locale=#{I18n.locale}"
+ end
+
+ # ----------------------------------------------------------------
+ test "we can change the locale by changing the URL" do
+ proj = Project.first
+
+ if I18n.available_locales.count > 1
+ # Verify that passing a locale in the URL will set the locale
+ other = I18n.available_locales.last
+
+ get project_path(other, proj)
+ assert_redirected_to "#{root_path}?locale=#{I18n.locale}", "Expected the changed locale to appear in the query string"
+ assert_equal other, I18n.locale, "Expected the locale to have been set when passing it in URL"
+ end
+ end
+
+ # ----------------------------------------------------------------
+ test "a user's language specification is used if no locale is passed in the URL" do
+ if I18n.available_locales.count > 1
+ @user.language = Language.find_by(abbreviation: I18n.available_locales.last)
+ @user.save!
+
+ sign_in @user
+
+ get root_path
+ assert_equal @user.language.abbreviation.to_s, I18n.locale.to_s, "Expected the locale to have been set to the user's chosen language"
+ assert "#{projects_path}".starts_with?("/#{@user.language.abbreviation}/"), "Expected the system to use the user's language specification"
+ end
+ end
+
+ # ----------------------------------------------------------------
+ test "a user's organisation language specification is used if no locale is passed in the URL and the user has no language setting" do
+ if I18n.available_locales.count > 1
+ @user.language = nil
+ @user.organisation[:language_id] = Language.find_by(abbreviation: I18n.available_locales.last).id
+ @user.save!
+
+ sign_in @user
+
+ get root_path
+ org_lang = Language.find(@user.organisation[:language_id]).abbreviation
+ assert_equal org_lang.to_s, I18n.locale.to_s, "Expected the locale to have been set to the organisation's chosen language"
+ assert "#{projects_path}".starts_with?("/#{org_lang}/"), "Expected the system to use the organisation's language specification"
+ end
+ end
+
+ # ----------------------------------------------------------------
+ test "the last visited url is stored in the session" do
+ get root_path
+ assert_equal root_path, session[:previous_url]
+
+ sign_in @user
+ get projects_path
+ assert_equal projects_path, session[:previous_url]
+ end
+
+end
diff --git a/test/functional/dmptemplates_controller_test.rb b/test/functional/dmptemplates_controller_test.rb
deleted file mode 100644
index a3a7521..0000000
--- a/test/functional/dmptemplates_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class DmptemplatesControllerTest < ActionController::TestCase
-=begin
- setup do
- @dmptemplate = dmptemplates(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:dmptemplates)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create dmptemplate" do
- assert_difference('Dmptemplate.count') do
- post :create, dmptemplate: { organisation_id: @dmptemplate.organisation_id, description: @dmptemplate.description, published: @dmptemplate.published, title: @dmptemplate.title, user_id: @dmptemplate.user_id }
- end
-
- assert_redirected_to dmptemplate_path(assigns(:dmptemplate))
- end
-
- test "should show dmptemplate" do
- get :show, id: @dmptemplate
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @dmptemplate
- assert_response :success
- end
-
- test "should update dmptemplate" do
- put :update, id: @dmptemplate, dmptemplate: { organisation_id: @dmptemplate.organisation_id, description: @dmptemplate.description, published: @dmptemplate.published, title: @dmptemplate.title, user_id: @dmptemplate.user_id }
- assert_redirected_to dmptemplate_path(assigns(:dmptemplate))
- end
-
- test "should destroy dmptemplate" do
- assert_difference('Dmptemplate.count', -1) do
- delete :destroy, id: @dmptemplate
- end
-
- assert_redirected_to dmptemplates_path
- end
-=end
-end
diff --git a/test/functional/file_types_controller_test.rb b/test/functional/file_types_controller_test.rb
deleted file mode 100644
index 168c370..0000000
--- a/test/functional/file_types_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class FileTypesControllerTest < ActionController::TestCase
-=begin
- setup do
- @file_type = file_types(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:file_types)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create file_type" do
- assert_difference('FileType.count') do
- post :create, file_type: { name: @file_type.name, icon_location: @file_type.icon_location, icon_name: @file_type.icon_name, icon_size: @file_type.icon_size }
- end
-
- assert_redirected_to file_type_path(assigns(:file_type))
- end
-
- test "should show file_type" do
- get :show, id: @file_type
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @file_type
- assert_response :success
- end
-
- test "should update file_type" do
- put :update, id: @file_type, file_type: { name: @file_type.name, icon_location: @file_type.icon_location, icon_name: @file_type.icon_name, icon_size: @file_type.icon_size }
- assert_redirected_to file_type_path(assigns(:file_type))
- end
-
- test "should destroy file_type" do
- assert_difference('FileType.count', -1) do
- delete :destroy, id: @file_type
- end
-
- assert_redirected_to file_types_path
- end
-=end
-end
diff --git a/test/functional/file_uploads_controller_test.rb b/test/functional/file_uploads_controller_test.rb
deleted file mode 100644
index 41a1a64..0000000
--- a/test/functional/file_uploads_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class FileUploadsControllerTest < ActionController::TestCase
-=begin
- setup do
- @file_upload = file_uploads(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:file_uploads)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create file_upload" do
- assert_difference('FileUpload.count') do
- post :create, file_upload: { file_type_id: @file_upload.file_type_id, description: @file_upload.description, location: @file_upload.location, name: @file_upload.name, published: @file_upload.published, size: @file_upload.size, title: @file_upload.title }
- end
-
- assert_redirected_to file_upload_path(assigns(:file_upload))
- end
-
- test "should show file_upload" do
- get :show, id: @file_upload
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @file_upload
- assert_response :success
- end
-
- test "should update file_upload" do
- put :update, id: @file_upload, file_upload: { file_type_id: @file_upload.file_type_id, description: @file_upload.description, location: @file_upload.location, name: @file_upload.name, published: @file_upload.published, size: @file_upload.size, title: @file_upload.title }
- assert_redirected_to file_upload_path(assigns(:file_upload))
- end
-
- test "should destroy file_upload" do
- assert_difference('FileUpload.count', -1) do
- delete :destroy, id: @file_upload
- end
-
- assert_redirected_to file_uploads_path
- end
-=end
-end
diff --git a/test/functional/guidances_controller_test.rb b/test/functional/guidances_controller_test.rb
deleted file mode 100644
index 2dc60d1..0000000
--- a/test/functional/guidances_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class GuidancesControllerTest < ActionController::TestCase
-=begin
- setup do
- @guidance = guidances(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:guidances)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create guidance" do
- assert_difference('Guidance.count') do
- post :create, guidance: { file_id: @guidance.file_id, text: @guidance.text, organisation_id: @guidance.organisation_id, theme_id: @guidance.theme_id }
- end
-
- assert_redirected_to guidance_path(assigns(:guidance))
- end
-
- test "should show guidance" do
- get :show, id: @guidance
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @guidance
- assert_response :success
- end
-
- test "should update guidance" do
- put :update, id: @guidance, guidance: { file_id: @guidance.file_id, text: @guidance.text, organisation_id: @guidance.organisation_id, theme_id: @guidance.theme_id }
- assert_redirected_to guidance_path(assigns(:guidance))
- end
-
- test "should destroy guidance" do
- assert_difference('Guidance.count', -1) do
- delete :destroy, id: @guidance
- end
-
- assert_redirected_to guidances_path
- end
-=end
-end
diff --git a/test/functional/home_controller_test.rb b/test/functional/home_controller_test.rb
deleted file mode 100644
index d088a29..0000000
--- a/test/functional/home_controller_test.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require 'test_helper'
-
-class HomeControllerTest < ActionController::TestCase
-=begin
- test "should get index" do
- get :index
- assert_response :success
- end
-=end
-end
diff --git a/test/functional/organisation_types_controller_test.rb b/test/functional/organisation_types_controller_test.rb
deleted file mode 100644
index 380dd88..0000000
--- a/test/functional/organisation_types_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class OrganisationTypesControllerTest < ActionController::TestCase
-=begin
- setup do
- @organisation_type = organisation_types(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:organisation_types)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create organisation_type" do
- assert_difference('OrganisationType.count') do
- post :create, organisation_type: { description: @organisation_type.description, name: @organisation_type.name }
- end
-
- assert_redirected_to organisation_type_path(assigns(:organisation_type))
- end
-
- test "should show organisation_type" do
- get :show, id: @organisation_type
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @organisation_type
- assert_response :success
- end
-
- test "should update organisation_type" do
- put :update, id: @organisation_type, organisation_type: { description: @organisation_type.description, name: @organisation_type.name }
- assert_redirected_to organisation_type_path(assigns(:organisation_type))
- end
-
- test "should destroy organisation_type" do
- assert_difference('OrganisationType.count', -1) do
- delete :destroy, id: @organisation_type
- end
-
- assert_redirected_to organisation_types_path
- end
-=end
-end
diff --git a/test/functional/pages_controller_test.rb b/test/functional/pages_controller_test.rb
deleted file mode 100644
index b525098..0000000
--- a/test/functional/pages_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class PagesControllerTest < ActionController::TestCase
-=begin
- setup do
- @page = pages(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:pages)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create page" do
- assert_difference('Page.count') do
- post :create, page: { organisation_id: @page.organisation_id, body_text: @page.body_text, location: @page.location, menu: @page.menu, menu_position: @page.menu_position, public: @page.public, slug: @page.slug, target_url: @page.target_url, title: @page.title }
- end
-
- assert_redirected_to page_path(assigns(:page))
- end
-
- test "should show page" do
- get :show, id: @page
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @page
- assert_response :success
- end
-
- test "should update page" do
- put :update, id: @page, page: { organisation_id: @page.organisation_id, body_text: @page.body_text, location: @page.location, menu: @page.menu, menu_position: @page.menu_position, public: @page.public, slug: @page.slug, target_url: @page.target_url, title: @page.title }
- assert_redirected_to page_path(assigns(:page))
- end
-
- test "should destroy page" do
- assert_difference('Page.count', -1) do
- delete :destroy, id: @page
- end
-
- assert_redirected_to pages_path
- end
-=end
-end
diff --git a/test/functional/phases_controller_test.rb b/test/functional/phases_controller_test.rb
deleted file mode 100644
index b392886..0000000
--- a/test/functional/phases_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class PhasesControllerTest < ActionController::TestCase
-=begin
- setup do
- @phase = phases(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:phases)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create phase" do
- assert_difference('Phase.count') do
- post :create, phase: { description: @phase.description, order: @phase.order, title: @phase.title }
- end
-
- assert_redirected_to phase_path(assigns(:phase))
- end
-
- test "should show phase" do
- get :show, id: @phase
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @phase
- assert_response :success
- end
-
- test "should update phase" do
- put :update, id: @phase, phase: { description: @phase.description, order: @phase.order, title: @phase.title }
- assert_redirected_to phase_path(assigns(:phase))
- end
-
- test "should destroy phase" do
- assert_difference('Phase.count', -1) do
- delete :destroy, id: @phase
- end
-
- assert_redirected_to phases_path
- end
-=end
-end
diff --git a/test/functional/plan_sections_controller_test.rb b/test/functional/plan_sections_controller_test.rb
deleted file mode 100644
index 97bbe62..0000000
--- a/test/functional/plan_sections_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class PlanSectionsControllerTest < ActionController::TestCase
-=begin
- setup do
- @plan_section = plan_sections(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:plan_sections)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create plan_section" do
- assert_difference('PlanSection.count') do
- post :create, plan_section: { plan_id: @plan_section.plan_id, at: @plan_section.at, edit: @plan_section.edit, section_id: @plan_section.section_id, user_editing_id: @plan_section.user_editing_id }
- end
-
- assert_redirected_to plan_section_path(assigns(:plan_section))
- end
-
- test "should show plan_section" do
- get :show, id: @plan_section
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @plan_section
- assert_response :success
- end
-
- test "should update plan_section" do
- put :update, id: @plan_section, plan_section: { plan_id: @plan_section.plan_id, at: @plan_section.at, edit: @plan_section.edit, section_id: @plan_section.section_id, user_editing_id: @plan_section.user_editing_id }
- assert_redirected_to plan_section_path(assigns(:plan_section))
- end
-
- test "should destroy plan_section" do
- assert_difference('PlanSection.count', -1) do
- delete :destroy, id: @plan_section
- end
-
- assert_redirected_to plan_sections_path
- end
-=end
-end
diff --git a/test/functional/plans_controller_test.rb b/test/functional/plans_controller_test.rb
deleted file mode 100644
index d2931bf..0000000
--- a/test/functional/plans_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class PlansControllerTest < ActionController::TestCase
-=begin
- setup do
- @plan = plans(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:plans)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create plan" do
- assert_difference('Plan.count') do
- post :create, plan: { locked: @plan.locked, project_id: @plan.project_id, version_id: @plan.version_id }
- end
-
- assert_redirected_to plan_path(assigns(:plan))
- end
-
- test "should show plan" do
- get :show, id: @plan
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @plan
- assert_response :success
- end
-
- test "should update plan" do
- put :update, id: @plan, plan: { locked: @plan.locked, project_id: @plan.project_id, version_id: @plan.version_id }
- assert_redirected_to plan_path(assigns(:plan))
- end
-
- test "should destroy plan" do
- assert_difference('Plan.count', -1) do
- delete :destroy, id: @plan
- end
-
- assert_redirected_to plans_path
- end
-=end
-end
diff --git a/test/functional/project_groups_controller_test.rb b/test/functional/project_groups_controller_test.rb
deleted file mode 100644
index 0e129f1..0000000
--- a/test/functional/project_groups_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class ProjectGroupsControllerTest < ActionController::TestCase
-=begin
- setup do
- @project_group = project_groups(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:project_groups)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create project_group" do
- assert_difference('ProjectGroup.count') do
- post :create, project_group: { project_creator: @project_group.project_creator, project_editor: @project_group.project_editor, project_id: @project_group.project_id, user_id: @project_group.user_id }
- end
-
- assert_redirected_to project_group_path(assigns(:project_group))
- end
-
- test "should show project_group" do
- get :show, id: @project_group
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @project_group
- assert_response :success
- end
-
- test "should update project_group" do
- put :update, id: @project_group, project_group: { project_creator: @project_group.project_creator, project_editor: @project_group.project_editor, project_id: @project_group.project_id, user_id: @project_group.user_id }
- assert_redirected_to project_group_path(assigns(:project_group))
- end
-
- test "should destroy project_group" do
- assert_difference('ProjectGroup.count', -1) do
- delete :destroy, id: @project_group
- end
-
- assert_redirected_to project_groups_path
- end
-=end
-end
diff --git a/test/functional/project_partners_controller_test.rb b/test/functional/project_partners_controller_test.rb
deleted file mode 100644
index c975fb2..0000000
--- a/test/functional/project_partners_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class ProjectPartnersControllerTest < ActionController::TestCase
-=begin
- setup do
- @project_partner = project_partners(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:project_partners)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create project_partner" do
- assert_difference('ProjectPartner.count') do
- post :create, project_partner: { leader_org: @project_partner.leader_org, organisation_id: @project_partner.organisation_id, project_id: @project_partner.project_id }
- end
-
- assert_redirected_to project_partner_path(assigns(:project_partner))
- end
-
- test "should show project_partner" do
- get :show, id: @project_partner
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @project_partner
- assert_response :success
- end
-
- test "should update project_partner" do
- put :update, id: @project_partner, project_partner: { leader_org: @project_partner.leader_org, organisation_id: @project_partner.organisation_id, project_id: @project_partner.project_id }
- assert_redirected_to project_partner_path(assigns(:project_partner))
- end
-
- test "should destroy project_partner" do
- assert_difference('ProjectPartner.count', -1) do
- delete :destroy, id: @project_partner
- end
-
- assert_redirected_to project_partners_path
- end
-=end
-end
diff --git a/test/functional/projects_controller_test.rb b/test/functional/projects_controller_test.rb
deleted file mode 100644
index 4238699..0000000
--- a/test/functional/projects_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class ProjectsControllerTest < ActionController::TestCase
-=begin
- setup do
- @project = projects(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:projects)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create project" do
- assert_difference('Project.count') do
- post :create, project: { dmptemplate_id: @project.dmptemplate_id, locked: @project.locked, note: @project.note, title: @project.title }
- end
-
- assert_redirected_to project_path(assigns(:project))
- end
-
- test "should show project" do
- get :show, id: @project
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @project
- assert_response :success
- end
-
- test "should update project" do
- put :update, id: @project, project: { dmptemplate_id: @project.dmptemplate_id, locked: @project.locked, note: @project.note, title: @project.title }
- assert_redirected_to project_path(assigns(:project))
- end
-
- test "should destroy project" do
- assert_difference('Project.count', -1) do
- delete :destroy, id: @project
- end
-
- assert_redirected_to projects_path
- end
-=end
-end
diff --git a/test/functional/question_themes_controller_test.rb b/test/functional/question_themes_controller_test.rb
deleted file mode 100644
index e4d015f..0000000
--- a/test/functional/question_themes_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class QuestionThemesControllerTest < ActionController::TestCase
-=begin
- setup do
- @question_theme = question_themes(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:question_themes)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create question_theme" do
- assert_difference('QuestionTheme.count') do
- post :create, question_theme: { question_id: @question_theme.question_id, theme_id: @question_theme.theme_id }
- end
-
- assert_redirected_to question_theme_path(assigns(:question_theme))
- end
-
- test "should show question_theme" do
- get :show, id: @question_theme
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @question_theme
- assert_response :success
- end
-
- test "should update question_theme" do
- put :update, id: @question_theme, question_theme: { question_id: @question_theme.question_id, theme_id: @question_theme.theme_id }
- assert_redirected_to question_theme_path(assigns(:question_theme))
- end
-
- test "should destroy question_theme" do
- assert_difference('QuestionTheme.count', -1) do
- delete :destroy, id: @question_theme
- end
-
- assert_redirected_to question_themes_path
- end
-=end
-end
diff --git a/test/functional/questions_controller_test.rb b/test/functional/questions_controller_test.rb
deleted file mode 100644
index 6ecfde8..0000000
--- a/test/functional/questions_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class QuestionsControllerTest < ActionController::TestCase
-=begin
- setup do
- @question = questions(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:questions)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create question" do
- assert_difference('Question.count') do
- post :create, question: { default_value: @question.default_value, dependency_id: @question.dependency_id, dependency_text: @question.dependency_text, guidance: @question.guidance, order: @question.order, parent_id: @question.parent_id, suggested_answer: @question.suggested_answer, text: @question.text, type: @question.type, section_id: @question.section_id }
- end
-
- assert_redirected_to question_path(assigns(:question))
- end
-
- test "should show question" do
- get :show, id: @question
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @question
- assert_response :success
- end
-
- test "should update question" do
- put :update, id: @question, question: { default_value: @question.default_value, dependency_id: @question.dependency_id, dependency_text: @question.dependency_text, guidance: @question.guidance, order: @question.order, parent_id: @question.parent_id, suggested_answer: @question.suggested_answer, text: @question.text, type: @question.type, section_id: @question.section_id }
- assert_redirected_to question_path(assigns(:question))
- end
-
- test "should destroy question" do
- assert_difference('Question.count', -1) do
- delete :destroy, id: @question
- end
-
- assert_redirected_to questions_path
- end
-=end
-end
diff --git a/test/functional/registrations_controller_test.rb b/test/functional/registrations_controller_test.rb
new file mode 100644
index 0000000..d610c83
--- /dev/null
+++ b/test/functional/registrations_controller_test.rb
@@ -0,0 +1,119 @@
+require 'test_helper'
+
+class RegistrationsControllerTest < ActionDispatch::IntegrationTest
+ include Devise::Test::IntegrationHelpers
+
+ setup do
+ @user = users(:cc_super)
+ end
+
+ # -------------------------------------------------------------
+ test "sign up form loads" do
+ get new_user_registration_path
+
+ assert_response :success
+ assert_not '#new_user'.nil?
+ end
+
+ # -------------------------------------------------------------
+ test "user receives proper error messaging if they have not accepted terms" do
+ post user_registration_path, {user: {accept_terms: false}}
+
+ assert_response :redirect
+ follow_redirect!
+
+ assert_response :success
+ assert_equal I18n.t('helpers.you_must_accept'), flash[:alert]
+ end
+
+ # -------------------------------------------------------------
+ test "user receives proper error messaging if they have not provided a valid email and/or password" do
+ [ {},
+ {email: 'foo.bar@test.org'}, # No Password or Confirmation
+ {password: 'test12345'}, # No Confirmation
+ {password_confirmation: 'test12345'}, # No Password
+ {password: 'test12345', password_confirmation: 'test12345'}, # No Email
+ {email: 'foo.bar@test.org', password: 'test', password_confirmation: 'test'}, # Password is too short
+ {email: 'foo.bar@test.org', password: 'test12345', password_confirmation: 'test123'}, # Passwords do not match
+ {email: 'foo.bar$test.org', password: 'test12345', password_confirmation: 'test12345'} # invalid email
+ ].each do |params|
+ post user_registration_path, {user: {accept_terms: 1}.merge(params)}
+
+ assert_response :redirect
+ follow_redirect!
+
+ assert_response :success
+ assert_equal I18n.t('helpers.error_registration_check'), flash[:alert]
+ end
+ end
+
+ # -------------------------------------------------------------
+ test "user is able to register and is auto-logged in and brought to profile page" do
+ form = {accept_terms: 1,
+ email: 'foo.bar@test.org',
+ password: 'Test12345',
+ password_confirmation: 'Test12345'}
+
+ cntr = 1
+ # Test the bare minimum requirements and then all options
+ [form, form.merge({email: "foo.bar#{cntr}@test.org",
+ organisation_id: Organisation.first.id})].each do |params|
+ post user_registration_path, {user: params}
+
+ assert_response :redirect
+ assert_redirected_to "#{root_url}?locale=#{I18n.locale}"
+
+ follow_redirect!
+ assert_response :success
+ assert_equal I18n.t('devise.registrations.signed_up_but_unconfirmed'), flash[:notice]
+ assert_select '.welcome-message h2', I18n.t('welcome_title')
+
+ cntr += 1
+ end
+ end
+
+ # -------------------------------------------------------------
+ test "edit profile page loads when logged in" do
+ sign_in @user
+
+ get edit_user_registration_path
+
+ assert_response :success
+ assert_select '.main_page_content h1', I18n.t('helpers.edit_profile')
+
+ end
+
+ # -------------------------------------------------------------
+ test "user is able to edit their profile" do
+ sign_in @user
+
+ put user_registration_path, {user: {firstname: 'Foo', surname: 'Bar'}}
+
+ assert_response :success
+ assert_equal nil, flash[:notice]
+ assert_select '.main_page_content h1', I18n.t('helpers.edit_profile')
+ end
+
+# INVALID AUTH REROUTING CHECKS
+ # -------------------------------------------------------------
+ test "sign up form does NOT load if already logged in" do
+ sign_in @user
+ get new_user_registration_path
+
+ assert_authorized_redirect_to_plans_page
+ end
+
+ # -------------------------------------------------------------
+ test "edit profile page does NOT load if not logged in" do
+ get edit_user_registration_path
+
+ assert_unauthorized_redirect_to_root_path
+ end
+
+ # -------------------------------------------------------------
+ test "can NOT edit profile if not logged in" do
+ post user_registration_path, {user: {firstname: 'Foo', surname: 'Bar'}}
+
+ assert_unauthorized_redirect_to_root_path
+ end
+end
\ No newline at end of file
diff --git a/test/functional/sections_controller_test.rb b/test/functional/sections_controller_test.rb
deleted file mode 100644
index a3847e3..0000000
--- a/test/functional/sections_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class SectionsControllerTest < ActionController::TestCase
-=begin
- setup do
- @section = sections(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:sections)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create section" do
- assert_difference('Section.count') do
- post :create, section: { organisation_id: @section.organisation_id, description: @section.description, order: @section.order, title: @section.title, version_id: @section.version_id }
- end
-
- assert_redirected_to section_path(assigns(:section))
- end
-
- test "should show section" do
- get :show, id: @section
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @section
- assert_response :success
- end
-
- test "should update section" do
- put :update, id: @section, section: { organisation_id: @section.organisation_id, description: @section.description, order: @section.order, title: @section.title, version_id: @section.version_id }
- assert_redirected_to section_path(assigns(:section))
- end
-
- test "should destroy section" do
- assert_difference('Section.count', -1) do
- delete :destroy, id: @section
- end
-
- assert_redirected_to sections_path
- end
-=end
-end
diff --git a/test/functional/static_pages_controller_test.rb b/test/functional/static_pages_controller_test.rb
new file mode 100644
index 0000000..11efee1
--- /dev/null
+++ b/test/functional/static_pages_controller_test.rb
@@ -0,0 +1,64 @@
+class StaticPagesControllerTest < ActionDispatch::IntegrationTest
+
+ include Devise::Test::IntegrationHelpers
+
+ setup do
+ @public_project = Project.create!({title: 'Public Test Project',
+ dmptemplate: Dmptemplate.first,
+ organisation: Organisation.first,
+ visibility: :publicly_visible})
+ end
+
+ # ----------------------------------------------------------
+ test "should only return plans with public visibility" do
+ get public_plans_path(locale: I18n.locale)
+
+ assert_response :success
+ assert_not_nil assigns(:projects)
+
+ all_public = true
+
+ assigns(:projects).each do |project|
+ all_public = false unless project.publicly_visible?
+ end
+
+ assert all_public, "expected all of the plans to have public visibility!"
+ end
+
+ # ----------------------------------------------------------
+ test "should export the publicly available plan" do
+
+# get public_export_path(locale: I18n.locale, id: @project)
+
+ # Should be redirected to the plans controller's export function
+# assert_redirected_to "#{export_project_plan_path(@project, @project.plans.first)}", "expected to be redirected to the exported plan"
+# follow_redirect!
+
+# assert_redirected_to "blah"
+# assert_response :success
+# assert_equal Mime::PDF, response.content_type
+ end
+
+ # ----------------------------------------------------------
+ test "should NOT export a non-public plan to unauthorized users" do
+ # Set the is_public flag to false and try to access it when not logged in
+ @public_project.visibility = :privately_visible
+ @public_project.save!
+
+ get public_export_path(locale: I18n.locale, id: @public_project)
+
+ assert_redirected_to "#{public_plans_path}", "expected to be redirected to the home page!"
+ assert_equal I18n.t('helpers.settings.plans.errors.no_access_account'), flash[:notice], "Expected an unauthorized message when trying to export a plan (via the public_export route) when the plan is not actually public"
+
+ # Set the is_public flag to false and assign ownership to a different user and then try to access it as a non-owner
+ @public_project.assign_creator(User.last)
+ @public_project.save!
+
+ sign_in User.first
+
+ get public_export_path(locale: I18n.locale, id: @public_project)
+
+ assert_redirected_to "#{public_plans_path}", "expected to be redirected to the home page!"
+ assert_equal I18n.t('helpers.settings.plans.errors.no_access_account'), flash[:notice], "Expected an unauthorized message when trying to export a plan (via the public_export route) when the plan is not actually public"
+ end
+end
\ No newline at end of file
diff --git a/test/functional/themes_controller_test.rb b/test/functional/themes_controller_test.rb
deleted file mode 100644
index 3bae2d6..0000000
--- a/test/functional/themes_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class ThemesControllerTest < ActionController::TestCase
-=begin
- setup do
- @theme = themes(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:themes)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create theme" do
- assert_difference('Theme.count') do
- post :create, theme: { description: @theme.description, title: @theme.title }
- end
-
- assert_redirected_to theme_path(assigns(:theme))
- end
-
- test "should show theme" do
- get :show, id: @theme
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @theme
- assert_response :success
- end
-
- test "should update theme" do
- put :update, id: @theme, theme: { description: @theme.description, title: @theme.title }
- assert_redirected_to theme_path(assigns(:theme))
- end
-
- test "should destroy theme" do
- assert_difference('Theme.count', -1) do
- delete :destroy, id: @theme
- end
-
- assert_redirected_to themes_path
- end
-=end
-end
diff --git a/test/functional/user_org_roles_controller_test.rb b/test/functional/user_org_roles_controller_test.rb
deleted file mode 100644
index 8412e88..0000000
--- a/test/functional/user_org_roles_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class UserOrgRolesControllerTest < ActionController::TestCase
-=begin
- setup do
- @user_role = user_org_roles(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:user_org_roles)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create user_org_role" do
- assert_difference('UserOrgRole.count') do
- post :create, user_org_role: { organisation_id: @user_org_role.organisation_id, user_id: @user_org_role.user_id, user_role_type_id: @user_org_role.user_role_type_id }
- end
-
- assert_redirected_to user_org_role_path(assigns(:user_org_role))
- end
-
- test "should show user_org_role" do
- get :show, id: @user_org_role
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @user_org_role
- assert_response :success
- end
-
- test "should update user_org_role" do
- put :update, id: @user_org_role, user_org_role: { organisation_id: @user_org_role.organisation_id, user_id: @user_org_role.user_id, user_role_type_id: @user_org_role.user_role_type_id }
- assert_redirected_to user_org_role_path(assigns(:user_org_role))
- end
-
- test "should destroy user_org_role" do
- assert_difference('UserOrgRole.count', -1) do
- delete :destroy, id: @user_org_role
- end
-
- assert_redirected_to user_org_roles_path
- end
-=end
-end
diff --git a/test/functional/user_role_types_controller_test.rb b/test/functional/user_role_types_controller_test.rb
deleted file mode 100644
index 5686f79..0000000
--- a/test/functional/user_role_types_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class UserRoleTypesControllerTest < ActionController::TestCase
-=begin
- setup do
- @user_role_type = user_role_types(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:user_role_types)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create user_role_type" do
- assert_difference('UserRoleType.count') do
- post :create, user_role_type: { description: @user_role_type.description, name: @user_role_type.name }
- end
-
- assert_redirected_to user_role_type_path(assigns(:user_role_type))
- end
-
- test "should show user_role_type" do
- get :show, id: @user_role_type
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @user_role_type
- assert_response :success
- end
-
- test "should update user_role_type" do
- put :update, id: @user_role_type, user_role_type: { description: @user_role_type.description, name: @user_role_type.name }
- assert_redirected_to user_role_type_path(assigns(:user_role_type))
- end
-
- test "should destroy user_role_type" do
- assert_difference('UserRoleType.count', -1) do
- delete :destroy, id: @user_role_type
- end
-
- assert_redirected_to user_role_types_path
- end
-=end
-end
diff --git a/test/functional/user_statuses_controller_test.rb b/test/functional/user_statuses_controller_test.rb
deleted file mode 100644
index 7487419..0000000
--- a/test/functional/user_statuses_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class UserStatusesControllerTest < ActionController::TestCase
-=begin
- setup do
- @user_status = user_statuses(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:user_statuses)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create user_status" do
- assert_difference('UserStatus.count') do
- post :create, user_status: { description: @user_status.description, name: @user_status.name }
- end
-
- assert_redirected_to user_status_path(assigns(:user_status))
- end
-
- test "should show user_status" do
- get :show, id: @user_status
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @user_status
- assert_response :success
- end
-
- test "should update user_status" do
- put :update, id: @user_status, user_status: { description: @user_status.description, name: @user_status.name }
- assert_redirected_to user_status_path(assigns(:user_status))
- end
-
- test "should destroy user_status" do
- assert_difference('UserStatus.count', -1) do
- delete :destroy, id: @user_status
- end
-
- assert_redirected_to user_statuses_path
- end
-=end
-end
diff --git a/test/functional/user_types_controller_test.rb b/test/functional/user_types_controller_test.rb
deleted file mode 100644
index 267ef27..0000000
--- a/test/functional/user_types_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class UserTypesControllerTest < ActionController::TestCase
-=begin
- setup do
- @user_type = user_types(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:user_types)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create user_type" do
- assert_difference('UserType.count') do
- post :create, user_type: { description: @user_type.description, name: @user_type.name }
- end
-
- assert_redirected_to user_type_path(assigns(:user_type))
- end
-
- test "should show user_type" do
- get :show, id: @user_type
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @user_type
- assert_response :success
- end
-
- test "should update user_type" do
- put :update, id: @user_type, user_type: { description: @user_type.description, name: @user_type.name }
- assert_redirected_to user_type_path(assigns(:user_type))
- end
-
- test "should destroy user_type" do
- assert_difference('UserType.count', -1) do
- delete :destroy, id: @user_type
- end
-
- assert_redirected_to user_types_path
- end
-=end
-end
diff --git a/test/functional/users/omniauth_callbacks_controller_test.rb b/test/functional/users/omniauth_callbacks_controller_test.rb
new file mode 100644
index 0000000..0ea505a
--- /dev/null
+++ b/test/functional/users/omniauth_callbacks_controller_test.rb
@@ -0,0 +1,70 @@
+class OmniauthCallbacksControllerTest < ActionDispatch::IntegrationTest
+ include Devise::Test::IntegrationHelpers
+
+ setup do
+ @schemes = IdentifierScheme.all
+ @user = users(:cc_super)
+
+ @callback_uris = {}
+
+ # Stub out omniauth provider responses
+ OmniAuth.config.test_mode = true
+
+ @schemes.each do |scheme|
+ @callback_uris[scheme.name] = Rails.application.routes.url_helpers.send(
+ "user_#{scheme.name.downcase}_omniauth_callback_path")
+
+ OmniAuth.config.mock_auth[:"#{scheme.name.downcase}"] = OmniAuth::AuthHash.new({
+ :provider => "#{scheme.name.downcase}",
+ :uid => 'foo:bar'
+ })
+ end
+
+ end
+
+ # -------------------------------------------------------------
+ test "User is not signed in and valid OAuth2 response does not match a User record in DB: should redirect to registration page" do
+ @schemes.each do |scheme|
+ post @callback_uris[scheme.name]
+
+ assert_equal I18n.t('identifier_schemes.new_login_success'), flash[:notice], "Expected a success message when simulating a valid callback from #{scheme.name}"
+ assert_redirected_to "#{new_user_registration_url}?locale=#{I18n.locale}", "Expected a redirect to the registration page when the user is not logged in and we received a valid callback from #{scheme.name}"
+
+ # make sure that the omniauth identifier is a hidden field on the registration page
+ assert_not "#user_identifiers[#{scheme.name}]".nil?
+ end
+ end
+
+ # -------------------------------------------------------------
+ test "User is not signed in and valid OAuth2 login matches a User record in the DB: should auto-signin and redirect to root page" do
+
+ @schemes.each do |scheme|
+ @user.user_identifiers << UserIdentifier.new(identifier_scheme: scheme,
+ identifier: "foo:bar")
+ @user.save!
+
+ post @callback_uris[scheme.name]
+
+ assert_equal I18n.t('devise.omniauth_callbacks.success').gsub('%{kind}', scheme.name), flash[:notice], "Expected a success message when simulating a valid callback from #{scheme.name}"
+ assert_redirected_to "#{root_url}?locale=#{I18n.locale}", "Expected a redirect to the root page, #{projects_url}, when omniauth returns with a valid identifier!"
+ end
+ end
+
+ # -------------------------------------------------------------
+ test "User is signed in and valid OAuth2 login does not match the current user's record in the DB: should attach the identifier to the user and redirect to the edit profile page" do
+
+ @schemes.each do |scheme|
+ sign_in @user
+
+ post @callback_uris[scheme.name]
+
+ assert_equal I18n.t('identifier_schemes.connect_success').gsub('%{scheme}', scheme.name), flash[:notice], "Expected a success message when simulating a valid callback from #{scheme.name}"
+ assert_redirected_to "#{edit_user_registration_path}?locale=#{I18n.locale}", "Expected a redirect to the edit profile page, #{projects_url}, when omniauth returns with a valid identifier for a user that is already signed in!"
+
+ # reload the user record and make sure the omniauth value was attached to their record
+ usr = User.find(@user)
+ assert_equal usr.user_identifiers.find_by(identifier_scheme: scheme).identifier, 'foo:bar'
+ end
+ end
+
+end
diff --git a/test/functional/versions_controller_test.rb b/test/functional/versions_controller_test.rb
deleted file mode 100644
index a3c4be7..0000000
--- a/test/functional/versions_controller_test.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'test_helper'
-
-class VersionsControllerTest < ActionController::TestCase
-=begin
- setup do
- @version = versions(:one)
- end
-
- test "should get index" do
- get :index
- assert_response :success
- assert_not_nil assigns(:versions)
- end
-
- test "should get new" do
- get :new
- assert_response :success
- end
-
- test "should create version" do
- assert_difference('Version.count') do
- post :create, version: { description: @version.description, order: @version.order, published: @version.published, title: @version.title }
- end
-
- assert_redirected_to version_path(assigns(:version))
- end
-
- test "should show version" do
- get :show, id: @version
- assert_response :success
- end
-
- test "should get edit" do
- get :edit, id: @version
- assert_response :success
- end
-
- test "should update version" do
- put :update, id: @version, version: { description: @version.description, order: @version.order, published: @version.published, title: @version.title }
- assert_redirected_to version_path(assigns(:version))
- end
-
- test "should destroy version" do
- assert_difference('Version.count', -1) do
- delete :destroy, id: @version
- end
-
- assert_redirected_to versions_path
- end
-=end
-end
diff --git a/test/helpers/application_helper_test.rb b/test/helpers/application_helper_test.rb
new file mode 100644
index 0000000..0eb97aa
--- /dev/null
+++ b/test/helpers/application_helper_test.rb
@@ -0,0 +1,61 @@
+require 'test_helper'
+
+class ApplicationHelperTest < ActionView::TestCase
+
+ def setup
+ # initialize the ActionView Output so that we have access to its functions (e.g. content_for)
+ @view_flow = ActionView::OutputFlow.new
+
+ content_for(:head) do
+ "Testing".html_safe
+ end
+ end
+
+ # -----------------------------------------------------------------------
+ test "resource_name should return :user" do
+ assert_equal :user, resource_name
+ end
+
+ # -----------------------------------------------------------------------
+ test "resource should return contents of instance variable @resource OR a new User" do
+ # If @resource is not set then we should receive a new User
+ assert resource.is_a?(User), "Expected resource() to return a new User"
+ assert_equal nil, resource.id, "Expected resource() to return a User with an Id"
+
+ # If @resource is set then we should receive that object
+ @resource = Organisation.first
+ assert resource.is_a?(Organisation), "Expected resource() to return @resource"
+ assert_equal @resource.id, resource.id, "Expected resource() to return the first Organisation"
+ end
+
+ # -----------------------------------------------------------------------
+ test "devise_mapping should return the mappings registered for Devise" do
+ # If @devise_mappings is not set we should get the mappings for :user
+ assert_equal Devise.mappings[:user], devise_mapping, "Expected devise_mapping() to return the correct default"
+
+ # If @devise_mapping is set the we should receive it
+ @devise_mapping = {foo: 'bar'}
+ assert_equal @devise_mapping, devise_mapping, "Expected devise_mapping() to return @devise_mapping"
+ end
+
+ # -----------------------------------------------------------------------
+ test "javascript should add JS script tags to the HTML head content for each of the files provided" do
+ current = content_for(:head)
+
+ javascript('abc.js')
+ assert content_for(:head).include?("#{javascript_include_tag('abc.js')}"), "Expected the abc.js script to be added to the HTML head content but got: #{content_for(:head)}"
+
+ javascript('zyx.js', 'wvu.js')
+ assert content_for(:head).include?("#{javascript_include_tag('wvu.js')}"), "Expected the wvu.js script to be added to the HTML head content but got: #{content_for(:head)}"
+ assert content_for(:head).include?("#{javascript_include_tag('zyx.js')}"), "Expected the zyx.js script to be added to the HTML head content but got: #{content_for(:head)}"
+ end
+
+ # -----------------------------------------------------------------------
+ test "hash_to_js_json_variable should return valid JSON markup for the specified Hash object" do
+ actual = hash_to_js_json_variable('hasher', {foo: 'bar', abc: '123'})
+
+ assert actual.include?('script'), "Expected the result to be contained within a script tag but got: #{actual}"
+ assert actual.include?('var hasher = '), "Expected the hash to appear as a variable but got: #{actual}"
+ assert actual.include?('{"foo":"bar","abc":"123"}'), "Expected the hash contents to appear but got: #{actual}"
+ end
+end
\ No newline at end of file
diff --git a/test/integration/.gitkeep b/test/integration/.gitkeep
deleted file mode 100644
index e69de29..0000000
--- a/test/integration/.gitkeep
+++ /dev/null
diff --git a/test/integration/authentication_test.rb b/test/integration/authentication_test.rb
new file mode 100644
index 0000000..cdf5e98
--- /dev/null
+++ b/test/integration/authentication_test.rb
@@ -0,0 +1,80 @@
+require 'test_helper'
+
+class AuthenticationFlowTest < ActionDispatch::IntegrationTest
+ include Devise::Test::IntegrationHelpers
+
+ setup do
+ @user = User.first
+ end
+
+ # ----------------------------------------------------------
+ test 'can sign in with valid email and password' do
+ sign_in @user
+
+ get root_path
+
+ assert_authorized_redirect_to_plans_page
+ end
+
+ # ----------------------------------------------------------
+ test 'can sign in with shibboleth' do
+
+ end
+
+ # ----------------------------------------------------------
+ test 'can sign out' do
+ get root_path
+ assert_response :success
+
+ sign_in @user
+
+ delete destroy_user_session_path
+
+ assert_response :redirect
+ follow_redirect!
+
+ # Make sure that the user is sent to the page that lists their plans
+ assert_response :success
+ assert_select '.welcome-message h2', I18n.t('welcome_title')
+ end
+
+ # ----------------------------------------------------------
+ test 'can NOT sign in with an invalid email and/or password' do
+ get root_path
+ assert_response :success
+
+ users = [{email: @user.email, password: 'bAd_pas$word1', remember_me: true},
+ {email: 'unknown@institution.org', password: 'password123', remember_me: true}]
+
+ users.each do |params|
+ post user_session_path, user: params
+
+ assert_response :redirect
+ follow_redirect!
+
+ # Make sure that the user is sent to the page that lists their plans
+ assert_response :success
+ assert_select '.welcome-message h2', I18n.t('welcome_title')
+ end
+ end
+
+
+ private
+ # ----------------------------------------------------------
+=begin
+ def sign_in
+ post user_session_path, user: {
+ email: @user.email,
+ password: 'password123',
+ remember_me: false
+ }
+
+ # The Devise auth gem will end up performing 2 redirects while generating the user's
+ # session and sending them to the main landing page
+ 2.times do
+ assert_response :redirect
+ follow_redirect!
+ end
+ end
+=end
+end
diff --git a/test/routing_test.rb b/test/routing_test.rb
index 8ac04af..eeb10a6 100644
--- a/test/routing_test.rb
+++ b/test/routing_test.rb
@@ -14,26 +14,50 @@
# -------------------------------------------------------------------
test 'GET /about_us should resolve to StaticPagesController#about_us' do
target = {controller: "static_pages", action: "about_us", locale: "#{I18n.locale}"}
-
- assert_routing "/#{I18n.locale}/about_us", target
+ assert_routing about_us_path(locale: I18n.locale), target
end
test 'GET /help should resolve to StaticPagesController#help' do
target = {controller: "static_pages", action: "help", locale: "#{I18n.locale}"}
-
- assert_routing "/#{I18n.locale}/help", target
+ assert_routing help_path(locale: I18n.locale), target
end
test 'GET /roadmap should resolve to StaticPagesController#roadmap' do
target = {controller: "static_pages", action: "roadmap", locale: "#{I18n.locale}"}
-
- assert_routing "/#{I18n.locale}/roadmap", target
+ assert_routing roadmap_path(locale: I18n.locale), target
end
test 'GET /terms should resolve to StaticPagesController#terms' do
target = {controller: "static_pages", action: "termsuse", locale: "#{I18n.locale}"}
-
- assert_routing "/#{I18n.locale}/terms", target
+ assert_routing terms_path(locale: I18n.locale), target
+ end
+ test 'GET /public_plans should resolve to StaticPagesController#public_plans' do
+ target = {controller: "static_pages", action: "public_plans", locale: "#{I18n.locale}"}
+ assert_routing public_plans_path(locale: I18n.locale), target
+ end
+ test 'GET /public_export should resolve to StaticPagesController#public_export' do
+ project = Project.includes(:plans).where.not(plans: {id: nil}).first
+ target = {controller: "static_pages", action: "public_export", locale: "#{I18n.locale}", id: project.id.to_s}
+
+ assert_routing public_export_path(locale: I18n.locale, id: project), target
end
+ # OAuth - Based on providers identified in the en-UK locale file
+ # -------------------------------------------------------------------
+ test "GET /users/auth/[:provider] should resolve to OmniauthCallbackController#passthru" do
+ target = {controller: "users/omniauth_callbacks", action: "passthru"}
+
+ IdentifierScheme.all.each do |scheme|
+ assert_routing "/users/auth/#{scheme.name.downcase}", target
+ end
+ end
+
+ test "POST /auth/[:provider]/callback should resolve to OmniauthCallbackController#[:provider]" do
+ IdentifierScheme.all.each do |scheme|
+ target = {controller: "users/omniauth_callbacks", action: "#{scheme.name.downcase}"}
+ assert_routing "/users/auth/#{scheme.name.downcase}/callback", target
+ end
+ end
+
+
# Routing for Users (Some resolve to UsersController and others to Devise's
# RegistrationController)
# -------------------------------------------------------------------
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 8d1ce40..9b8050d 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -1,8 +1,12 @@
ENV["RAILS_ENV"] = "test"
+# Startup the simple coverage gem so that our test results are captured
+require 'simplecov'
+SimpleCov.start 'rails'
+
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
-
+require 'webmock/minitest'
require 'active_support/inflector' # For pluralization utility
class ActiveSupport::TestCase
@@ -15,16 +19,98 @@
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
- fixtures :all
+ #fixtures :all
+
+ # Use the db/seed.rb file to populate the test DB
+ require_relative '../db/seeds.rb'
# Add more helper methods to be used by all tests here...
-
+
# Convert Ruby Class Names into attribute names (e.g. MyClass --> my_class)
# ----------------------------------------------------------------------
def class_name_to_attribute_name(name)
name.gsub(/([a-z]+)([A-Z])/, '\1_\2').gsub('-', '_').downcase
end
+ # Scaffold a new Template with one Phase, one Section, and a Question for
+ # each of the possible Question Formats.
+ # ----------------------------------------------------------------------
+ def scaffold_template
+ template = Template.new(title: 'Test template', description: 'My test template',
+ published: true, org: Org.first, locale: nil, is_default: false,
+ version: 1, visibility: 0)
+
+ template.phases << Phase.new(title: 'Test phase', description: 'My test phase',
+ number: 1, modifiable: false)
+
+ section = Section.new(title: 'Test section', description: 'My test section',
+ number: 99, published: true, modifiable: false)
+
+ i = 1
+ # Add each type of Question to the new section
+ QuestionFormat.all.each do |frmt|
+ question = Question.new(text: "Test question - #{frmt.title}", number: i,
+ question_format: frmt)
+
+ if frmt.option_based?
+ 3.times do |j|
+ question.question_options << QuestionOption.new(text: "Option #{j}", number: j)
+ end
+ end
+
+ section.questions << question
+ i += 1
+ end
+
+ template.phases.first.sections << section
+
+ assert template.valid?, "unable to create new Template: #{template.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ template.save!
+
+ @template = template.reload
+ end
+
+ # Scaffold a new Plan based on the scaffolded Template
+ # ----------------------------------------------------------------------
+ def scaffold_plan
+ scaffold_template if @template.nil?
+
+ @plan = Plan.new(template: @template, title: 'Test Plan', grant_number: 'Grant-123',
+ principal_investigator: 'me', principal_investigator_identifier: 'me-1234',
+ description: "this is my plan's informative description",
+ identifier: '1234567890', data_contact: 'me@example.com', visibility: 0,
+ users: [User.last])
+
+ assert @plan.valid?, "unable to create new Plan: #{@plan.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ @plan.save!
+ end
+
+
+# FUNCTIONAL/INTEGRATION TEST HELPERS
+ # ----------------------------------------------------------------------
+ def assert_unauthorized_redirect_to_root_path
+ assert_response :redirect
+ assert_match "#{root_url}", @response.redirect_url
+
+ follow_redirect!
+ assert_response :success
+ assert_select '.welcome-message h2', I18n.t('welcome_title')
+ end
+
+ # ----------------------------------------------------------------------
+ def assert_authorized_redirect_to_plans_page
+ assert_response :redirect
+ assert_match "#{root_url}", @response.redirect_url
+
+ # Sometimes Devise has an intermediary step prior to sending the user to the final destination
+ while @response.status >= 300 && @response.status < 400
+ follow_redirect!
+ end
+
+ assert_response :success
+ assert_select '.main_page_content h1', I18n.t('helpers.project.projects_title')
+ end
+
# UNIT TEST HELPERS
# ----------------------------------------------------------------------
@@ -37,7 +123,7 @@
# Add another association for the object
object.send(rel) << new_association
object.save!
- assert_equal (initial_expected_count + 1), object.send(rel).count, "was expecting #{object.class.name} to have #{initial_expected_count + 1} #{rel} after adding a new one"
+ assert_equal (initial_expected_count + 1), object.send(rel).count, "was expecting #{object.class.name} to have #{initial_expected_count + 1} #{rel} after adding a new one - #{new_association.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
# Remove the newly added association
object.send(rel).delete(new_association)
@@ -59,4 +145,29 @@
parent.reload
assert_includes parent.send("#{chld.pluralize}"), child, "was expecting the #{prnt}.#{chld.pluralize} to contain the #{chld}"
end
+
+# STUBS FOR CALLS To EXTERNAL SITES
+ # ----------------------------------------------------------------------
+ def stub_blog_calls
+ blog_feed = "" +
+ "" +
+ "Testing" +
+ "http://www.example.com/stubbed/blog/feed" +
+ "" +
+ "Stub blog post" +
+ "http://www.example.com/stubbed/blog/articles/1" +
+ "This is a stuubed blog post" +
+ "Test" +
+ "Thu, 03 Nov 2016 12:38:17 +0000" +
+ "" +
+ "1 at http://www.example.com/stubbed/blog" +
+ "" +
+ ""
+
+ stub_request(:get, "http://www.dcc.ac.uk/news/dmponline-0/feed").
+ with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Faraday v0.9.2'}).
+ to_return(:status => 200, :body => blog_feed, :headers => {})
+ end
end
diff --git a/test/unit/admin_user_test.rb b/test/unit/admin_user_test.rb
deleted file mode 100644
index 23a3cc8..0000000
--- a/test/unit/admin_user_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class AdminUserTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
diff --git a/test/unit/answer_test.rb b/test/unit/answer_test.rb
index e2fad05..991ab88 100644
--- a/test/unit/answer_test.rb
+++ b/test/unit/answer_test.rb
@@ -1,7 +1,128 @@
require 'test_helper'
class AnswerTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
+
+ setup do
+ @user = User.last
+
+ scaffold_plan
+
+ q = @plan.template.questions.select{|q| !q.question_format.option_based }.last
+ q = Question.create(text: 'Answer Testing', number: 9,
+ section: @plan.template.phases.first.sections.first,
+ question_format: QuestionFormat.find_by(option_based: false))
+ @answer = Answer.create(user: @user, plan: @plan, question: q, text: 'Testing')
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not Answer.new.valid?
+
+ # Validate the creation of text based answers
+ QuestionFormat.where(option_based: false).each do |qf|
+ q = @plan.template.questions.select{|q| q.question_format == qf }.first
+
+ assert_not Answer.new(user: @user, question: q, text: 'Testing').valid?, "expected the 'plan' field to be required for a #{qf.title}"
+ assert_not Answer.new(plan: @plan, question: q, text: 'Testing').valid?, "expected the 'user' field to be required for a #{qf.title}"
+ assert_not Answer.new(user: @user, plan: @plan, text: 'Testing').valid?, "expected the 'question' field to be required for a #{qf.title}"
+ assert_not Answer.new(user: @user, question: q, plan: @plan).valid?, "expected the 'text' field to be required for a #{qf.title}"
+
+ # Ensure the bar minimum and complete versions are valid
+ a = Answer.new(user: @user, plan: @plan, question: q, text: 'Testing')
+ assert a.valid?, "expected the 'plan', 'user' and 'question' and 'text' fields to be enough to create an Answer for a #{qf.title}! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ end
+
+ # Validate the creation of option based answers (a selection is not required)
+ QuestionFormat.where(option_based: true).each do |qf|
+ q = @plan.template.questions.select{|q| q.question_format == qf }.first
+
+ assert_not Answer.new(user: @user, question: q, question_options: [q.question_options.first]).valid?, "expected the 'plan' field to be required for a #{qf.title}"
+ assert_not Answer.new(plan: @plan, question: q, question_options: [q.question_options.first]).valid?, "expected the 'user' field to be required for a #{qf.title}"
+ assert_not Answer.new(user: @user, plan: @plan, question_options: [q.question_options.first]).valid?, "expected the 'question' field to be required for a #{qf.title}"
+ assert_not Answer.new(user: @user, plan: @plan, question: q).valid?, "expected the 'question_options' field to be required for a #{qf.title}"
+
+ # Ensure the bar minimum and complete versions are valid
+ a = Answer.new(user: @user, plan: @plan, question: q, question_options: [q.question_options.first])
+ assert a.valid?, "expected the 'plan', 'user' and 'question' fields to be enough to create an Answer for a #{qf.title}! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ end
+
+ end
+
+ # ---------------------------------------------------
+ test "cannot have multiple answers to the same question within a plan" do
+ q = @plan.template.questions.select{|q| !q.question_format.option_based }.first
+ Answer.create(user: @user, plan: @plan, question: @plan.questions.first, text: 'Testing')
+
+ assert_not Answer.new(user: @user, plan: @plan, question: @plan.questions.first, text: 'Another answer to the same question!').valid?, "expected to NOT be able to add an answer to a question that already has an answer!"
+ end
+
+ # ---------------------------------------------------
+ test "answer's template must match the plan's template" do
+ plan = Plan.new(title: 'Wrong plan test', template: Template.where.not(id: @plan.template.id).first)
+ q = @plan.template.questions.select{|q| !q.question_format.option_based }.first
+
+ assert_not Answer.new(user: @user, plan: plan, question: @plan.questions.first,
+ text: 'Testing').valid?, "expected to only be able to add an answer if it belongs to the template associated with the plan"
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD answers for text based questions" do
+ QuestionFormat.where(option_based: false).each do |qf|
+ q = @plan.template.questions.select{|q| q.question_format == qf }.first
+
+ assert_not q.nil?, "expected the test template to have a question of type: #{qf.title}"
+
+ answr = Answer.create(user: @user, plan: @plan, question: q, text: 'Tested ABC')
+ assert_not answr.id.nil?, "was expecting to be able to create a new Answer for a #{qf.title} question: #{answr.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+
+ answr.text = 'Testing an update'
+ answr.save!
+ answr.reload
+ assert_equal 'Testing an update', answr.text, "Was expecting to be able to update the text of the Answer for a #{qf.title} question!"
+
+ assert answr.destroy!, "Was unable to delete the Answer for a #{qf.title} question!"
+ end
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD answers for option based questions" do
+ QuestionFormat.where(option_based: true).each do |qf|
+ q = @plan.template.questions.select{|q| q.question_format == qf }.first
+
+ assert_not q.nil?, "expected the test template to have a question of type: #{qf.title}"
+
+ answr = Answer.create(user: @user, plan: @plan, question: q, question_options: [q.question_options.first])
+ assert_not answr.id.nil?, "was expecting to be able to create a new Answer for a #{qf.title} question: #{answr.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+
+ answr.question_options = [q.question_options.last]
+ answr.save!
+ answr.reload
+ assert answr.question_options.include?(q.question_options.last), "Was expecting the answer to have the '#{q.question_options.last.text}' for a #{qf.title} question!"
+ assert_not answr.question_options.include?(q.question_options.first), "Was expecting the answer to no longer have the '#{q.question_options.first.text}' for a #{qf.title} question!"
+
+ assert answr.destroy!, "Was unable to delete the Answer for a #{qf.title} question!"
+ end
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with User" do
+ verify_belongs_to_relationship(@answer, User.last)
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with Plan" do
+ verify_belongs_to_relationship(@answer, @plan)
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with Question" do
+ q = @plan.template.phases.first.sections.first.questions.last
+ verify_belongs_to_relationship(@answer, q)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Notes" do
+ note = Note.new(text: 'Test Note', user: @user)
+ verify_has_many_relationship(@answer, note, @answer.notes.count)
+ end
end
diff --git a/test/unit/comment_test.rb b/test/unit/comment_test.rb
deleted file mode 100644
index 9575e6c..0000000
--- a/test/unit/comment_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class CommentTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
diff --git a/test/unit/dmptemplate_test.rb b/test/unit/dmptemplate_test.rb
deleted file mode 100644
index 805540a..0000000
--- a/test/unit/dmptemplate_test.rb
+++ /dev/null
@@ -1,279 +0,0 @@
-require 'test_helper'
-
-class DmptemplateTest < ActiveSupport::TestCase
-
- setup do
- @template = Dmptemplate.first
- end
-
- def settings(extras = {})
- {
- margin: (@margin || { top: 10, bottom: 10, left: 10, right: 10 }),
- font_face: (@font_face || Settings::Dmptemplate::VALID_FONT_FACES.first),
- font_size: (@font_size || 11)
- }.merge(extras)
- end
-
- def default_formatting
- Settings::Dmptemplate::DEFAULT_SETTINGS[:formatting]
- end
-
- # ---------- settings ----------
-
- test "settings should use defaults if none defined" do
- assert(!@template.settings(:export).value?)
- assert_equal(default_formatting, @template.settings(:export).formatting)
- end
-
- test "settings should use defined valid settings" do
- @template.settings(:export).formatting = settings
- @template.save!
-
- assert(@template.settings(:export).value?)
- assert_equal(settings, @template.settings(:export).formatting)
- assert_not_equal(default_formatting, @template.settings(:export).formatting)
- end
-
- test "setting negative margin should not be valid" do
- @margin = { top: -10, bottom: 10, left: 10, right: 10 }
-
- @template.settings(:export).formatting = settings
-
- assert(!@template.valid?)
- assert(!@template.save)
-
- assert_equal(I18n.t('helpers.settings.plans.errors.negative_margin'),
- @template.errors.messages[:'setting_objects.formatting'].first)
-
- @template.reload
- assert_equal(default_formatting, @template.settings(:export).formatting)
- end
-
- test "setting unknown margin should not be valid" do
- @margin = { top: 10, bottom: 10, left: 10, right: 10, top_left: 10 }
-
- @template.settings(:export).formatting = settings
-
- assert(!@template.valid?)
- assert(!@template.save)
-
- assert_equal(I18n.t('helpers.settings.plans.errors.unknown_margin'),
- @template.errors.messages[:'setting_objects.formatting'].first)
-
- @template.reload
- assert_equal(default_formatting, @template.settings(:export).formatting)
- end
-
- test "setting negative font-size should not be valid" do
- @font_size = -11
-
- @template.settings(:export).formatting = settings
-
- assert(!@template.valid?)
- assert(!@template.save)
-
- assert_equal(I18n.t('helpers.settings.plans.errors.invalid_font_size'),
- @template.errors.messages[:'setting_objects.formatting'].first)
-
- @template.reload
-
- assert_equal(default_formatting, @template.settings(:export).formatting)
- end
-
- test "setting unknown key should not be valid" do
- @template.settings(:export).formatting = settings(foo: :bar)
-
- assert(!@template.valid?)
- assert(!@template.save)
-
- assert_equal(I18n.t('helpers.settings.plans.errors.unknown_key'),
- @template.errors.messages[:'setting_objects.formatting'].first)
-
- @template.reload
-
- assert_equal(default_formatting, @template.settings(:export).formatting)
- end
-
- test "not setting font_face should not be valid" do
- @template.settings(:export).formatting = settings.reject {|k,v| k == :font_face }
-
- assert(!@template.valid?)
- assert(!@template.save)
-
- assert_equal(I18n.t('helpers.settings.plans.errors.missing_key'),
- @template.errors.messages[:'setting_objects.formatting'].first)
-
- @template.reload
-
- assert_equal(default_formatting, @template.settings(:export).formatting)
- end
-
- test "not setting font_size should not be valid" do
- @template.settings(:export).formatting = settings.reject {|k,v| k == :font_size }
-
- assert(!@template.valid?)
- assert(!@template.save)
-
- assert_equal(I18n.t('helpers.settings.plans.errors.missing_key'),
- @template.errors.messages[:'setting_objects.formatting'].first)
-
- @template.reload
-
- assert_equal(default_formatting, @template.settings(:export).formatting)
- end
-
- test "not setting margin should not be valid" do
- @template.settings(:export).formatting = settings.reject {|k,v| k == :margin }
-
- assert(!@template.valid?)
- assert(!@template.save)
-
- assert_equal(I18n.t('helpers.settings.plans.errors.missing_key'),
- @template.errors.messages[:'setting_objects.formatting'].first)
-
- @template.reload
-
- assert_equal(default_formatting, @template.settings(:export).formatting)
- end
-
- test "setting non-hash as margin should not be valid" do
- @margin = :foo
-
- @template.settings(:export).formatting = settings
-
- assert(!@template.valid?)
- assert(!@template.save)
-
- assert_equal(I18n.t('helpers.settings.plans.errors.invalid_margin'),
- @template.errors.messages[:'setting_objects.formatting'].first)
-
- @template.reload
-
- assert_equal(default_formatting, @template.settings(:export).formatting)
- end
-
- test "setting non-integer as font_size should not be valid" do
- @font_size = "foo"
-
- @template.settings(:export).formatting = settings
-
- assert(!@template.valid?)
- assert(!@template.save)
-
- assert_equal(I18n.t('helpers.settings.plans.errors.invalid_font_size'),
- @template.errors.messages[:'setting_objects.formatting'].first)
-
- @template.reload
-
- assert_equal(default_formatting, @template.settings(:export).formatting)
- end
-
- test "setting non-string as font_face should not be valid" do
- @font_face = 1
-
- @template.settings(:export).formatting = settings
-
- assert(!@template.valid?)
- assert(!@template.save)
-
- assert_equal(I18n.t('helpers.settings.plans.errors.invalid_font_face'),
- @template.errors.messages[:'setting_objects.formatting'].first)
-
- @template.reload
-
- assert_equal(default_formatting, @template.settings(:export).formatting)
- end
-
- test "setting unknown string as font_face should not be valid" do
- @font_face = 'Monaco, Monospace, Sans-Serif'
-
- @template.settings(:export).formatting = settings
-
- assert(!@template.valid?)
- assert(!@template.save)
-
- assert_equal(I18n.t('helpers.settings.plans.errors.invalid_font_face'),
- @template.errors.messages[:'setting_objects.formatting'].first)
-
- @template.reload
-
- assert_equal(default_formatting, @template.settings(:export).formatting)
- end
-
- # ---------- templates_org_type ----------
- test "templates_org_type returns all published" do
- OrganisationType.find_each do |org_type|
- result_templates = Dmptemplate.templates_org_type(org_type.name)
- my_list = Array.new
- org_type.organisations.each do |org|
- my_list += org.dmptemplates
- end
- my_list.each do |template|
- if template.published
- assert_includes(result_templates, template, "Template: #{template.title}} of type #{org_type.name}, not returned by templates_org_type")
- end
- end
- end
- end
-
- # ---------- funders_templates ----------
- test "funders_templates returns all funder organisation templates" do
- result_templates = Dmptemplate.funders_templates
- funder_templates = OrganisationType.first.organisations do |org|
- org.dmptemplates.each do |template|
- assert_includes( result_templates, template, "Funder Template: #{template.title} not included in result of funders_templates")
- end
- end
- end
-
- # ---------- own_institutional_templates ----------
- test "own_institutional_templates returns all templates belonging to given org_id" do
- Org.find_each do |org|
- result_templates = Dmptemplate.own_institutional_templates(org.id)
- org.dmptemplates.each do |template|
- assert_includes(result_templates, template, "Template: #{template.title} not returned by own_institutional_templates")
- end
- end
- end
-
- # ---------- funders_and_own_templates ----------
- test "funders_and_own_templates returns all funder and own given org_id templates" do
- Org.find_each do |org|
- result_templates = Dmptemplate.funders_and_own_templates(org.id)
- org.dmptemplates.each do |template|
- assert_includes(result_templates, template, "Template #{template.title} not returned by funders and own templates")
- end
- end
- funder_templates = OrganisationType.first.organisations do |org|
- org.dmptemplates.each do |template|
- assert_includes( result_templates, template, "Funder Template: #{template.title} not included in result of funders_and_own_templates")
- end
- end
- end
-
- # ---------- org_type ----------
- test "org_type properly returns the name of the template's organisation's type" do
- Dmptemplate.find_each do |template|
- assert_equal( template.org_type, template.organisation.organisation_type.name, "Template: #{template.title} returned #{template.org_type}, instead of #{template.organisation.organisation_type.name}")
- end
- end
-
- # ---------- has_customisations? ----------
- test "has_customisations? correctly identifies if a given org has customised the template" do
- # TODO: Impliment after understanding has_customisations
-
- end
-
- # ---------- has_published_versions? ----------
- test "has_published_versions? correctly identifies published versions" do
- Dmptemplate.find_each do |template|
- template.phases.each do |phase|
- unless phase.latest_published_version.nil?
- assert(template.has_published_versions? , "there was a published version of phase: #{phase.title}")
- end
- end
- end
- end
-
-
-end
diff --git a/test/unit/exported_plan_test.rb b/test/unit/exported_plan_test.rb
new file mode 100644
index 0000000..28bae85
--- /dev/null
+++ b/test/unit/exported_plan_test.rb
@@ -0,0 +1,62 @@
+require 'test_helper'
+
+class ExportedPlanTest < ActiveSupport::TestCase
+
+ setup do
+ @user = User.last
+
+ scaffold_plan
+
+ @exported = ExportedPlan.create(user: @user, plan: @plan,
+ format: ExportedPlan::VALID_FORMATS.first)
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not ExportedPlan.new.valid?
+ assert_not ExportedPlan.new(format: ExportedPlan::VALID_FORMATS.last).valid?, "expected the 'plan' field to be required"
+ assert_not ExportedPlan.new(plan: @plan).valid?, "expected the 'format' field to be required"
+
+ # Ensure the bar minimum and complete versions are valid
+ a = ExportedPlan.new(plan: @plan, format: ExportedPlan::VALID_FORMATS.last)
+ assert a.valid?, "expected the 'plan', 'user' and 'format' fields to be enough to create an ExportedPlan! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ end
+
+ # ---------------------------------------------------
+ test "as_csv" do
+
+ end
+
+ # ---------------------------------------------------
+ test "as_txt" do
+
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD ExportedPlan" do
+ ExportedPlan::VALID_FORMATS.each do |vf|
+ ep = ExportedPlan.create(user: @user, plan: @plan, format: vf)
+ assert_not ep.id.nil?, "was expecting to be able to create a new ExportedPlan: #{ep.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+
+ expected = (vf == ExportedPlan::VALID_FORMATS.last ? ExportedPlan::VALID_FORMATS.first : ExportedPlan::VALID_FORMATS.last)
+
+ ep.format = expected
+ ep.save!
+ ep.reload
+ assert_equal expected, ep.format, "Was expecting to be able to update the format of the ExportedPlan!"
+
+ assert ep.destroy!, "Was unable to delete the ExportedPlan!"
+ end
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with Plan" do
+ verify_belongs_to_relationship(@exported, Plan.last)
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with User" do
+ verify_belongs_to_relationship(@exported, User.last)
+ end
+
+end
diff --git a/test/unit/file_type_test.rb b/test/unit/file_type_test.rb
deleted file mode 100644
index 3f94955..0000000
--- a/test/unit/file_type_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class FileTypeTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
diff --git a/test/unit/file_upload_test.rb b/test/unit/file_upload_test.rb
deleted file mode 100644
index 900dac8..0000000
--- a/test/unit/file_upload_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class FileUploadTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
diff --git a/test/unit/guidance_group_test.rb b/test/unit/guidance_group_test.rb
index c5b4716..6019dce 100644
--- a/test/unit/guidance_group_test.rb
+++ b/test/unit/guidance_group_test.rb
@@ -1,177 +1,102 @@
require 'test_helper'
class GuidanceGroupTest < ActiveSupport::TestCase
+ include GlobalHelpers
setup do
- @user_one = User.first
- @user_two = User.order(surname: :desc).first
- @user_three = User.last
+ @user = User.first
+ @org = Org.last
- @org_type = OrganisationType.first
-
- @organisations = Org.all
+ @guidance_group = GuidanceGroup.create(name: 'Test Guidance Group', org: @org,
+ optional_subset: false, published: true)
end
- # ---------- can_view? ----------
- test "DCC guidance groups should be viewable" do
-# assert GuidanceGroup.can_view?(@user_one, guidance_groups(:dcc_guidance_group_1))
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not GuidanceGroup.new.valid?
+ assert_not GuidanceGroup.new(org: @org).valid?, "expected the 'name' field to be required"
+ assert_not GuidanceGroup.new(name: 'Tester').valid?, "expected the 'organisation' field to be required"
+
+ # Ensure the bar minimum and complete versions are valid
+ a = GuidanceGroup.new(name: 'Tester', org: @org)
+ assert a.valid?, "expected the 'name' and 'organisation' fields to be enough to create a GuidanceGroup! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ end
+
+ # ---------------------------------------------------
+ test "display_name returns organisation name and the guidance group name" do
+ assert_equal "#{@org.name}", @guidance_group.display_name, "Expected display_name to return the organisation name if there is only one GuidanceGroup"
+
+ GuidanceGroup.create(name: 'Second Test', org: @org)
+ assert_equal "#{@org.name}: #{@guidance_group.name}", @guidance_group.display_name, "Expected display_name to return the organisation name and guidance group name if there are more than one GuidanceGroup"
end
- test "Funder guidance groups should be viewable" do
-=begin
- @org_type.organisations.each do |org|
- org.guidance_groups.each do |funder_group|
- assert GuidanceGroup.can_view?(@user_one, funder_group)
- end
- end
-=end
+ # ---------------------------------------------------
+ test "guidance_groups_excluding does not return guidance groups for the current organisation" do
+ assert_not GuidanceGroup.guidance_groups_excluding([@org]).include?(@guidance_group)
end
- test "User's organisation groups should be viewable" do
-=begin
- assert GuidanceGroup.can_view?(@user_one, guidance_groups(:institution_guidance_group_1).id) , "user_one cannot view aru_institution_guidance"
-
- assert GuidanceGroup.can_view?(@user_two, guidance_groups(:institution_guidance_group_2).id), "user_two cannot view au_..._1"
-
- assert GuidanceGroup.can_view?(@user_three, guidance_groups(:institution_guidance_group_3).id), "user_three cannot view bu_..._1"
- assert GuidanceGroup.can_view?(@user_three, guidance_groups(:institution_guidance_group_4).id), "user_three cannot view bu_..._2"
-=end
+ # ---------------------------------------------------
+ test "user can view guidance_group if it belongs to their organisation" do
+ org = @user.org
+ gg = GuidanceGroup.create(name: 'User Test', org: org)
+
+ assert GuidanceGroup.can_view?(@user, gg.id)
end
- test "No other organisations's groups should be viewable" do
-=begin
- assert_not GuidanceGroup.can_view?(@user_one, guidance_groups(:institution_guidance_group_2).id)
- assert_not GuidanceGroup.can_view?(@user_one, guidance_groups(:institution_guidance_group_3).id)
- assert_not GuidanceGroup.can_view?(@user_one, guidance_groups(:institution_guidance_group_4).id)
-
- assert_not GuidanceGroup.can_view?(@user_two, guidance_groups(:institution_guidance_group_1).id)
- assert_not GuidanceGroup.can_view?(@user_two, guidance_groups(:institution_guidance_group_3).id)
- assert_not GuidanceGroup.can_view?(@user_two, guidance_groups(:institution_guidance_group_4).id)
-
- assert_not GuidanceGroup.can_view?(@user_three, guidance_groups(:institution_guidance_group_1).id)
- assert_not GuidanceGroup.can_view?(@user_three, guidance_groups(:institution_guidance_group_2).id)
-=end
+ # ---------------------------------------------------
+ test "user can view guidance_group if it belongs to a funder" do
+ gg = GuidanceGroup.create(name: 'Funder Test', org: Org.funders.first)
+
+ assert GuidanceGroup.can_view?(@user, gg.id)
+ end
+
+ # ---------------------------------------------------
+ test "user can view guidance_group if it belongs to the managing curation centre" do
+ gg = GuidanceGroup.create(name: 'Managing CC Test', org: Org.managing_orgs.first)
+
+ assert GuidanceGroup.can_view?(@user, gg.id)
end
+ # ---------------------------------------------------
+ test "user can view all oftheir organisations, funders, and the managing curation centre's guidance groups" do
+ @org.users << @user
+ @org.save
+ @org.reload
- # ---------- all_viewable ----------
- # ensure that the all_viewable function returns all viewable groups
- # should return true for groups owned by funders
- # should return true for groups owned by DCC
- # should return true for groups owned by the user's organisation
- # should not return true for an organisation outwith those above
- test "all_viewable returns all dcc groups" do
- all_viewable_groups = GuidanceGroup.all_viewable(@user_one)
- @organisations.first.guidance_groups.each do |group|
- assert_includes(all_viewable_groups, group)
+ ggs = [@guidance_group,
+ GuidanceGroup.create(name: 'User Test', org: @org),
+ GuidanceGroup.create(name: 'Funder Test', org: Org.funders.first),
+ GuidanceGroup.create(name: 'Managing CC Test', org: Org.managing_orgs.first)]
+
+ v = GuidanceGroup.all_viewable(@user)
+
+ ggs.each do |gg|
+ assert v.include?(gg), "expected Guidance Group: '#{gg.name}' to be viewable"
end
end
- test "all_viewable returns all funder groups" do
- all_viewable_groups = GuidanceGroup.all_viewable(@user_one)
- @org_type.organisations.each do |org|
- org.guidance_groups.each do |group|
- assert_includes(all_viewable_groups, group)
- end
- end
+ # ---------------------------------------------------
+ test "can CRUD GuidanceGroup" do
+ gg = GuidanceGroup.create(name: 'Tester', org: @org)
+ assert_not gg.id.nil?, "was expecting to be able to create a new GuidanceGroup!"
+
+ gg.name = 'Testing an update'
+ gg.save!
+ gg.reload
+ assert_equal 'Testing an update', gg.name, "Was expecting to be able to update the text of the GuidanceGroup!"
+
+ assert gg.destroy!, "Was unable to delete the GuidanceGroup!"
end
-
- test "all_viewable returns all of a user's organisations's guidances" do
- all_viewable_groups_one = GuidanceGroup.all_viewable(@user_one)
- @organisations.first.guidance_groups.each do |group|
- assert_includes(all_viewable_groups_one, group)
- end
-
- all_viewable_groups_two = GuidanceGroup.all_viewable(@user_two)
- @organisations[1].guidance_groups.each do |group|
- assert_includes(all_viewable_groups_two, group)
- end
-
- all_viewable_groups_three = GuidanceGroup.all_viewable(@user_three)
- @organisations.last.guidance_groups.each do |group|
- assert_includes(all_viewable_groups_three, group)
- end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Guidance" do
+ g = Guidance.new(text: 'Test Guidance')
+ verify_has_many_relationship(@guidance_group, g, @guidance_group.guidances.count)
end
-
- test "all_viewable does not return any other organisaition's guidance" do
-=begin
- all_viewable_groups = GuidanceGroup.all_viewable(@user_one)
- all_viewable_groups.delete_if do |group|
- if group.organisation.id == @organisation.id
- true
- elsif group.organisation.organisation_type.id == @org_type.id
- true
- elsif group.organisation.id == @user_one.organisation.id
- true
- else
- false
- end
- end
- assert_empty(all_viewable_groups)
-=end
- end
-
-
- # ---------- display_name ----------
- test "display_name should return an org name for an org with one guidance" do
-# assert_equal(guidance_groups(:funder_guidance_group_1).display_name, "Arts and Humanities Research Council", "result of display_name for an org with one group should be the org name")
- end
-
- test "display_name should return an org and group name for an org with more than one guidance" do
-# assert_equal(guidance_groups(:institution_guidance_group_4).display_name, "Bangor University: Bangor University guidance group 2", "result of display_name for an org with more than one group should be : ")
- end
-
- # ---------- self.guidance_groups_excluding ----------
- test "guidance_groups_excluding should not return a group belonging to specified single org" do
-=begin
- # generate a list
- excluding_list = GuidanceGroup.guidance_groups_excluding([@organisation])
- excluding_list.each do |group|
- refute_equal(group.organisation, @organisation, "#{group.name} is owned by dcc")
- end
-=end
- end
-
- test "guidance_groups_excluding should not return a group belonging to specified orgs" do
-=begin
- org_list = [organisations.first, organisations.last]
- excluding_list = GuidanceGroup.guidance_groups_excluding(org_list)
- excluding_list.each do |group|
- org_list.each do |org|
- refute_equal(group.organisation, org, "#{group.name} is owned by specified org: #{org.name}")
- end
- end
-=end
- end
-
- test "guidance_groups_excluding should return all groups not belonging to the specified org" do
-=begin
- excluding_list = GuidanceGroup.guidance_groups_excluding([@organisation])
- GuidanceGroup.all.each do |group|
- if group.organisation_id != @organisation.id
- assert_includes(excluding_list, group, "#{group.name} is not owned by dcc so should be included")
- end
- end
-=end
- end
-
- test "guidance_groups_excluding should return all groups not belonging to specified orgs" do
-=begin
- excluded =false
- org_list = [organisations.first, organisations.last]
- excluding_list = GuidanceGroup.guidance_groups_excluding(org_list)
- GuidanceGroup.all.each do |group|
- excluded = false
- org_list.each do |org|
- if group.organisation == org
- excluded = true
- end
- end
- unless excluded
- assert_includes(excluding_list, group, "#{group.name} is not owned by a specified org so should be included")
- end
- end
-=end
- end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with Org" do
+ verify_belongs_to_relationship(@guidance_group, @org)
+ end
end
diff --git a/test/unit/guidance_test.rb b/test/unit/guidance_test.rb
index 8157e60..878b953 100644
--- a/test/unit/guidance_test.rb
+++ b/test/unit/guidance_test.rb
@@ -1,201 +1,104 @@
-require 'test_helper'
-
-class GuidanceTest < ActiveSupport::TestCase
-
- setup do
- @user_one = User.first
- @user_two = User.order(surname: :desc).first
- @user_three = User.last
-
- @org_type = OrganisationType.first
-
- @organisations = Org.all
- end
-
- # ---------- can_view? ----------
- # ensure that the can_view? function returns true all viewable guidances
- # should return true for groups owned by funders
- # should return true for groups owned by DCC
- # should return true for groups owned by the user's organisation
- # should not return true for an organisation outwith those above
- test "DCC guidances should be viewable" do
-=begin
- guidance_groups(:dcc_guidance_group_1).guidances.each do |guidance|
- assert Guidance.can_view?(@user_one, guidance.id)
- end
-=end
- end
-
- test "Funder guidances should be viewable" do
-=begin
- assert Guidance.can_view?(@user_one, guidances(:ahrc_funder_guidance).id)
- assert Guidance.can_view?(@user_one, guidances(:bbsrc_funder_guidance).id)
-=end
- end
-
-
- test "User's organisation guidances should be viewable" do
-=begin
- assert Guidance.can_view?(@user_one, guidances(:aru_institution_guidance).id) , "user_one cannot view aru_institution_guidance"
-
- assert Guidance.can_view?(@user_two, guidances(:au_institution_guidance_1).id), "user_two cannot view au_..._1"
- assert Guidance.can_view?(@user_two, guidances(:au_institution_guidance_2).id), "user_two cannot view au_..._2"
-
- assert Guidance.can_view?(@user_three, guidances(:bu_institution_guidance_1).id), "user_three cannot view bu_..._1"
- assert Guidance.can_view?(@user_three, guidances(:bu_institution_guidance_2).id), "user_three cannot view bu_..._2"
-=end
- end
-
- test "No other organisations's guidances should be viewable" do
-=begin
- # TOOD: add more fixtures with new types of guidances(i.e. not institution)
- # and add test cases
- assert_not Guidance.can_view?(@user_one, guidances(:au_institution_guidance_1).id)
- assert_not Guidance.can_view?(@user_one, guidances(:au_institution_guidance_2).id)
- assert_not Guidance.can_view?(@user_one, guidances(:bu_institution_guidance_1).id)
- assert_not Guidance.can_view?(@user_one, guidances(:bu_institution_guidance_2).id)
-
- assert_not Guidance.can_view?(@user_two, guidances(:aru_institution_guidance).id)
- assert_not Guidance.can_view?(@user_two, guidances(:bu_institution_guidance_1).id)
- assert_not Guidance.can_view?(@user_two, guidances(:bu_institution_guidance_2).id)
-
- assert_not Guidance.can_view?(@user_three, guidances(:aru_institution_guidance).id)
- assert_not Guidance.can_view?(@user_three, guidances(:au_institution_guidance_1).id)
- assert_not Guidance.can_view?(@user_three, guidances(:au_institution_guidance_2).id)
-=end
- end
-
-# ---------- all_viewable ----------
- # ensure that the all_viewable function returns all viewable guidances
- # should return true for groups owned by funders
- # should return true for groups owned by DCC
- # should return true for groups owned by the user's organisation
- # should not return true for an organisation outwith those above
- test "all_viewable returns all DCC guidances" do
-=begin
- all_viewable_guidances = Guidance.all_viewable(@user_one)
- @organisations.first.guidance_groups.each do |group|
- group.guidances.each do |guidance|
- assert_includes(all_viewable_guidances, guidance)
- end
- end
-=end
- end
-
- test "all_viewable returns all funder guidances" do
-=begin
- all_viewable_guidances = Guidance.all_viewable(@user_one)
- guidance_groups(:funder_guidance_group_1).guidances.each do |guidance|
- assert_includes(all_viewable_guidances, guidance)
- end
- guidance_groups(:funder_guidance_group_2).guidances.each do |guidance|
- assert_includes(all_viewable_guidances, guidance)
- end
-=end
- end
-
- test "all_viewable returns all of a user's organisations's guidances" do
-=begin
- all_viewable_guidances_one = Guidance.all_viewable(@user_one)
- @organisations.first.guidance_groups.each do |group|
- group.guidances.each do |guidance|
- assert_includes(all_viewable_guidances_one, guidance)
- end
- end
-
- all_viewable_guidances_two = Guidance.all_viewable(@user_two)
- @organisations[1].guidance_groups.each do |group|
- group.guidances.each do |guidance|
- assert_includes(all_viewable_guidances_two, guidance)
- end
- end
-
- all_viewable_guidances_three = Guidance.all_viewable(@user_three)
- @organisations.last.guidance_groups.each do |group|
- group.guidances.each do |guidance|
- assert_includes(all_viewable_guidances_three, guidance)
- end
- end
-=end
- end
-
-
- test "all_viewable does not return any other organisation's guidance" do
-=begin
- # TODO: Add in a suitable test. should we check for non-institutions?
- all_viewable_guidances = Guidance.all_viewable(@user_one)
- # remove all of the user's organisation
- # remove all of each funder's organisations
- # remove each of the dcc's organisations
- # check if nill
- all_viewable_guidances.delete_if do |guidance|
- guidance.guidance_groups.each do |group|
- if group.organisation.id == organisations(:dcc).id
- true
- elsif group.organisation.organisation_type.id == organisation_types(:funder).id
- true
- elsif group.organisation.id == @user_one.organisations.first.id
- true
- else
- false
- end
- end
- end
- assert_empty(all_viewable_guidances, "there must not be any guidances which are not funders, DCC, or our own organisation")
-=end
- end
-
- # ---------- in_group_belonging_to? ----------
- test "in_group_belonging_to correctly identifies parent orgs" do
-=begin
- # test that the association works for all correct usages
- Guidance.all.each do |guidance|
- guidance.guidance_groups.each do |group|
- assert(guidance.in_group_belonging_to?(group.organisation.id), "Guidance: #{guidance.text} should belong to organisation #{group.organisation.name}")
- end
- end
-=end
- end
-
- test "in_group_belonging_to rejects non-parent orgs" do
-=begin
- # test that in_group_belonging_to rejects a few interesting organisation-guidance pairs
- assert_not(guidances(:related_policies).in_group_belonging_to?(organisations(:ahrc)), "Organisation ahrc does not own guidance: related policies")
- assert_not(guidances(:ahrc_funder_guidance).in_group_belonging_to?(organisations(:dcc)), "Organisation dcc does not own guidance: ahrc_funder_guidance")
-=end
- end
-
- # ---------- by_organisation ----------
- test "by_organisation correctly returns all guidance belonging to a given org" do
-=begin
- Org.all.each do |org|
- org_guidance = Guidance.by_organisation(org)
- org.guidance_groups.each do |group|
- group.guidances.each do |guidance|
- assert_includes(org_guidance, guidance, "Guidance #{guidance.text} should belong to organisation: #{org.name}")
- end
- end
- end
-=end
- end
-
- # ---------- get_guidance_group_templates ----------
- ## the main function is completely bugged, so ask to remove it
- # test "get_guidance_group_templates retuns all templates belonging to a guidance group" do
- # GuidanceGroup.all.each do |group|
- # group_templates = guidances(:related_policies).get_guidance_group_templates?(group)
- # group.dmptemplates.each do |template|
- # assert_includes(group_templates, template, "group #{group.name} should include template #{template.title}")
- # end
- # end
- # end
-
-end
-
-
-
-
-
-
-
-
+require 'test_helper'
+
+class GuidanceTest < ActiveSupport::TestCase
+
+ setup do
+ @user = User.first
+
+ @guidance_group = GuidanceGroup.create(name: 'Tester', org: @user.org)
+ @guidance = Guidance.create(text: 'Testing some new guidance')
+
+ @guidance_group.guidances << @guidance
+ @guidance_group.save!
+
+ @question = Question.first
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not Guidance.new.valid?
+ assert_not Guidance.new(guidance_group: GuidanceGroup.first).valid?, "expected the 'text' field to be required"
+
+ # Ensure the bar minimum and complete versions are valid
+ a = Guidance.new(text: 'Testing guidance')
+ assert a.valid?, "expected the 'text' field to be enough to create a Guidance! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ end
+
+ # ---------------------------------------------------
+ test "correctly identifies guidance as belonging to the org" do
+ assert @guidance.in_group_belonging_to?(@user.org.id), "expected the guidance to belong to the org"
+
+ @guidance.guidance_group = nil
+ @guidance.save!
+
+ assert_not @guidance.in_group_belonging_to?(@user.org), "expected the guidance to NOT belong to the org"
+ end
+
+ # ---------------------------------------------------
+ test "retrieves guidance by org" do
+ org = Org.create(name: 'Tester 123', abbreviation: 'TEST', org_type: 1)
+ assert Guidance.by_org(org.id).empty?, "expected the newly created org to have no guidance"
+
+ assert_not Guidance.by_org(@user.org.id).empty?, "expected the org to have guidance"
+ end
+
+ # ---------------------------------------------------
+ test "correctly identifies whether the user can view the guidance" do
+ g = Guidance.create(text: 'Unviewable guidance')
+
+ assert_not Guidance.can_view?(@user, g.id), "expected guidance that is not attached to a GuidanceGroup to be unviewable"
+
+ assert Guidance.can_view?(@user, @guidance.id), "expected the user to be able to view guidance belonging to their org"
+
+ @guidance_group.org = Org.managing_orgs.first
+ @guidance_group.save!
+ assert Guidance.can_view?(@user, @guidance.id), "expected the user to be able to view guidance belonging to the managing org"
+
+ @guidance_group.org = Org.funders.first
+ @guidance_group.save!
+ assert Guidance.can_view?(@user, @guidance.id), "expected the user to be able to view guidance belonging to a funder"
+ end
+
+ # ---------------------------------------------------
+ test "make sure a user can view all appropriate guidance" do
+ viewable = Guidance.all_viewable(@user)
+
+ assert viewable.include?(@guidance), "expected the user to be able to view guidance belonging to their org"
+
+ GuidanceGroup.create(name: 'managing guidance group test', org: Org.managing_orgs.first)
+ GuidanceGroup.create(name: 'funder guidance group test', org: Org.funders.first)
+
+ Org.managing_orgs.first.guidance_groups.first.guidances.each do |g|
+ assert viewable.include?(g), "expected the user to be able to view all managing org guidance"
+ end
+
+ Org.funders.first.guidance_groups.first.guidances.each do |g|
+ assert viewable.include?(g), "expected the user to be able to view all funder guidance"
+ end
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD Guidance" do
+ g = Guidance.create(text: 'Testing guidance')
+ assert_not g.id.nil?, "was expecting to be able to create a new Guidance!"
+
+ g.text = 'Testing an update'
+ g.save!
+ g.reload
+ assert_equal 'Testing an update', g.text, "Was expecting to be able to update the text of the Guidance!"
+
+ assert g.destroy!, "Was unable to delete the Guidance!"
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Theme" do
+ t = Theme.new(title: 'Test Theme')
+ verify_has_many_relationship(@guidance, t, @guidance.themes.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with GuidanceGroup" do
+ gg = GuidanceGroup.new(name: 'Test GuidanceGroup', org: Org.last, published: true)
+ verify_belongs_to_relationship(@guidance, gg)
+ end
+end
\ No newline at end of file
diff --git a/test/unit/helpers/answers_helper_test.rb b/test/unit/helpers/answers_helper_test.rb
deleted file mode 100644
index ba3e2d9..0000000
--- a/test/unit/helpers/answers_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class AnswersHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/dmptemplates_helper_test.rb b/test/unit/helpers/dmptemplates_helper_test.rb
deleted file mode 100644
index 7703fda..0000000
--- a/test/unit/helpers/dmptemplates_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class DmptemplatesHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/file_types_helper_test.rb b/test/unit/helpers/file_types_helper_test.rb
deleted file mode 100644
index 02fd16e..0000000
--- a/test/unit/helpers/file_types_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class FileTypesHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/file_uploads_helper_test.rb b/test/unit/helpers/file_uploads_helper_test.rb
deleted file mode 100644
index d6bb15e..0000000
--- a/test/unit/helpers/file_uploads_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class FileUploadsHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/guidances_helper_test.rb b/test/unit/helpers/guidances_helper_test.rb
deleted file mode 100644
index 397b066..0000000
--- a/test/unit/helpers/guidances_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class GuidancesHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/home_helper_test.rb b/test/unit/helpers/home_helper_test.rb
deleted file mode 100644
index 4e72d63..0000000
--- a/test/unit/helpers/home_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class HomeHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/organisation_types_helper_test.rb b/test/unit/helpers/organisation_types_helper_test.rb
deleted file mode 100644
index e355bde..0000000
--- a/test/unit/helpers/organisation_types_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class OrganisationTypesHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/organisations_helper_test.rb b/test/unit/helpers/organisations_helper_test.rb
deleted file mode 100644
index ba9c1df..0000000
--- a/test/unit/helpers/organisations_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class OrganisationsHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/pages_helper_test.rb b/test/unit/helpers/pages_helper_test.rb
deleted file mode 100644
index ec7d95a..0000000
--- a/test/unit/helpers/pages_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class PagesHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/phases_helper_test.rb b/test/unit/helpers/phases_helper_test.rb
deleted file mode 100644
index 5ea83b2..0000000
--- a/test/unit/helpers/phases_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class PhasesHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/plan_sections_helper_test.rb b/test/unit/helpers/plan_sections_helper_test.rb
deleted file mode 100644
index b196349..0000000
--- a/test/unit/helpers/plan_sections_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class PlanSectionsHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/plans_helper_test.rb b/test/unit/helpers/plans_helper_test.rb
deleted file mode 100644
index e440041..0000000
--- a/test/unit/helpers/plans_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class PlansHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/project_groups_helper_test.rb b/test/unit/helpers/project_groups_helper_test.rb
deleted file mode 100644
index 00536a7..0000000
--- a/test/unit/helpers/project_groups_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class ProjectGroupsHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/project_partners_helper_test.rb b/test/unit/helpers/project_partners_helper_test.rb
deleted file mode 100644
index e34ac3f..0000000
--- a/test/unit/helpers/project_partners_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class ProjectPartnersHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/projects_helper_test.rb b/test/unit/helpers/projects_helper_test.rb
deleted file mode 100644
index 2e6d5a7..0000000
--- a/test/unit/helpers/projects_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class ProjectsHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/question_themes_helper_test.rb b/test/unit/helpers/question_themes_helper_test.rb
deleted file mode 100644
index 96a1dc7..0000000
--- a/test/unit/helpers/question_themes_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class QuestionThemesHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/questions_helper_test.rb b/test/unit/helpers/questions_helper_test.rb
deleted file mode 100644
index 0c122f5..0000000
--- a/test/unit/helpers/questions_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class QuestionsHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/sections_helper_test.rb b/test/unit/helpers/sections_helper_test.rb
deleted file mode 100644
index aff16de..0000000
--- a/test/unit/helpers/sections_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class SectionsHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/themes_helper_test.rb b/test/unit/helpers/themes_helper_test.rb
deleted file mode 100644
index 0a5c987..0000000
--- a/test/unit/helpers/themes_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class ThemesHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/user_org_roles_helper_test.rb b/test/unit/helpers/user_org_roles_helper_test.rb
deleted file mode 100644
index c02d2f2..0000000
--- a/test/unit/helpers/user_org_roles_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class UserOrgRolesHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/user_role_types_helper_test.rb b/test/unit/helpers/user_role_types_helper_test.rb
deleted file mode 100644
index a1c8e04..0000000
--- a/test/unit/helpers/user_role_types_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class UserRoleTypesHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/user_statuses_helper_test.rb b/test/unit/helpers/user_statuses_helper_test.rb
deleted file mode 100644
index 3d39852..0000000
--- a/test/unit/helpers/user_statuses_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class UserStatusesHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/user_types_helper_test.rb b/test/unit/helpers/user_types_helper_test.rb
deleted file mode 100644
index 7460858..0000000
--- a/test/unit/helpers/user_types_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class UserTypesHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/users_helper_test.rb b/test/unit/helpers/users_helper_test.rb
deleted file mode 100644
index c77b035..0000000
--- a/test/unit/helpers/users_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class UsersHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/helpers/versions_helper_test.rb b/test/unit/helpers/versions_helper_test.rb
deleted file mode 100644
index f12ea8a..0000000
--- a/test/unit/helpers/versions_helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class VersionsHelperTest < ActionView::TestCase
-end
diff --git a/test/unit/identifier_schemes_test.rb b/test/unit/identifier_schemes_test.rb
new file mode 100644
index 0000000..8ed4485
--- /dev/null
+++ b/test/unit/identifier_schemes_test.rb
@@ -0,0 +1,45 @@
+require 'test_helper'
+
+class IdentifierSchemesTest < ActiveSupport::TestCase
+
+ def setup
+ @scheme = IdentifierScheme.first
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not IdentifierScheme.new.valid?
+ assert_not IdentifierScheme.new(description: 'we are testing').valid?
+
+ # Ensure that the bare minimum of fields is still valid
+ assert IdentifierScheme.new(name: 'testing').valid?
+ end
+
+ # ---------------------------------------------------
+ test "name must be unique" do
+ assert_not IdentifierScheme.new(name: @scheme.name).valid?
+
+ # Ensure that the bare minimum of fields is still valid
+ assert IdentifierScheme.new(name: 'testing').valid?
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD" do
+ is = IdentifierScheme.create(name: 'testing')
+ assert_not is.id.nil?, "was expecting to be able to create a new IdentifierScheme: #{is.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+
+ is.description = 'Testing It Out'
+ is.save!
+ is.reload
+ assert_equal 'Testing It Out', is.description, "Was expecting to be able to update the api_key of the IdentifierScheme!"
+
+ assert is.destroy!, "Was unable to delete the IdentifierScheme!"
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with UserIdentifiers" do
+ ui = UserIdentifier.new(user: User.first, identifier: 'tester')
+ verify_has_many_relationship(@scheme, ui, @scheme.users.count)
+ end
+
+end
diff --git a/test/unit/language_test.rb b/test/unit/language_test.rb
new file mode 100644
index 0000000..8447bbb
--- /dev/null
+++ b/test/unit/language_test.rb
@@ -0,0 +1,49 @@
+require 'test_helper'
+
+class LanguageTest < ActiveSupport::TestCase
+
+ def setup
+ @lang = Language.find_by(abbreviation: I18n.locale)
+ @user = User.first
+ @org = @user.org
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not Language.new.valid?
+ assert_not Language.new(name: 'Klingon').valid?
+ assert_not Language.new(name: 'Klingon', description: 'Klingon', default_language: true).valid?
+
+ assert Language.new(abbreviation: 'klgn').valid?
+ assert Language.new(abbreviation: 'klgn', name: 'Klingon', description: 'Klingon', default_language: true).valid?
+ end
+
+ # ---------------------------------------------------
+ test "abbreviation must be unique" do
+ assert_not Language.new(abbreviation: Language.first.abbreviation).valid?
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD" do
+ lang = Language.create(abbreviation: 'kg', name: 'Klingon')
+ assert_not lang.id.nil?, "was expecting to be able to create a new Language : #{lang.errors.collect{ |e| e }.join(', ')}"
+
+ lang.name = 'Imperial Klingon'
+ lang.save!
+ assert_equal 'Imperial Klingon', lang.reload.name, "was expecting the name to have been updated!"
+
+ assert lang.destroy!, "Was unable to delete the Language!"
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Users" do
+ verify_has_many_relationship(Language.last, User.last, Language.last.users.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Organisations" do
+ org = Org.create(name: 'testing', abbreviation: "TEST")
+ verify_has_many_relationship(Language.last, org, Language.last.orgs.count)
+ end
+
+end
\ No newline at end of file
diff --git a/test/unit/note_test.rb b/test/unit/note_test.rb
new file mode 100644
index 0000000..911adfe
--- /dev/null
+++ b/test/unit/note_test.rb
@@ -0,0 +1,51 @@
+require 'test_helper'
+
+class NoteTest < ActiveSupport::TestCase
+
+ setup do
+ @user = User.last
+
+ scaffold_plan
+
+ q = @plan.template.questions.select{|q| !q.question_format.option_based }.first
+ @answer = Answer.create(user: @user, plan: @plan, question: q, text: 'Testing')
+
+ @note = Note.create(answer: @answer, user: @user, text: 'Test Note', archived: true,
+ archived_by: User.last)
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not Note.new.valid?
+ assert_not Note.new(user: @user, answer: @answer).valid?, "expected the 'text' field to be required"
+ assert_not Note.new(answer: @answer, text: 'Testing').valid?, "expected the 'user' field to be required"
+ assert_not Note.new(user: @user, text: 'Testing').valid?, "expected the 'answer' field to be required"
+
+ # Ensure the bar minimum and complete versions are valid
+ a = Note.new(user: @user, answer: @answer, text: 'Testing')
+ assert a.valid?, "expected the 'text', 'answer' and 'user' fields to be enough to create an Note! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD Note" do
+ obj = Note.create(user: @user, answer: @answer, text: 'Tested ABC')
+ assert_not obj.id.nil?, "was expecting to be able to create a new Note: #{obj.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+
+ obj.text = 'Testing an update'
+ obj.save!
+ obj.reload
+ assert_equal 'Testing an update', obj.text, "Was expecting to be able to update the text of the Note!"
+
+ assert obj.destroy!, "Was unable to delete the Note!"
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with Answer" do
+ verify_belongs_to_relationship(@note, @answer)
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with User" do
+ verify_belongs_to_relationship(@note, @user)
+ end
+end
diff --git a/test/unit/option_warning_test.rb b/test/unit/option_warning_test.rb
new file mode 100644
index 0000000..e682774
--- /dev/null
+++ b/test/unit/option_warning_test.rb
@@ -0,0 +1,49 @@
+require 'test_helper'
+
+class OptionWarningTest < ActiveSupport::TestCase
+ include GlobalHelpers
+
+ setup do
+ @option = Option.first
+ @organisation = Organisation.first
+
+ @option_warning = OptionWarning.create(organisation: @organisation, option: @option, text: 'Testing')
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not OptionWarning.new.valid?
+ assert_not OptionWarning.new(option: @option, organisation: @organisation).valid?, "expected the 'text' field to be required"
+
+ # Ensure the bare minimum and complete versions are valid
+ assert OptionWarning.new(text: 'Test', organisation: @organisation, option: @option).valid?, "expected the 'text', 'option' and 'organisation' fields to be enough to create an OptionWarning!"
+ end
+
+ # ---------------------------------------------------
+ test "to_s returns the text of the option warning" do
+ assert_equal @option_warning.text, @option_warning.to_s, "expected the to_s method to return the text field"
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD Guidance" do
+ obj = OptionWarning.create(organisation: @organisation, option: @option, text: 'Testing option warnings')
+ assert_not obj.id.nil?, "was expecting to be able to create a new OptionWarning!"
+
+ obj.text = 'Testing an update'
+ obj.save!
+ obj.reload
+ assert_equal 'Testing an update', obj.text, "Was expecting to be able to update the text of the OptionWarning!"
+
+ assert obj.destroy!, "Was unable to delete the OptionWarning!"
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with Organisation" do
+ verify_belongs_to_relationship(@option_warning, @organisation)
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with Option" do
+ verify_belongs_to_relationship(@option_warning, @option)
+ end
+end
\ No newline at end of file
diff --git a/test/unit/org_test.rb b/test/unit/org_test.rb
new file mode 100644
index 0000000..b249f88
--- /dev/null
+++ b/test/unit/org_test.rb
@@ -0,0 +1,135 @@
+require 'test_helper'
+
+class OrgTest < ActiveSupport::TestCase
+ setup do
+ @org = Org.first
+
+ @language = Language.find_by(abbreviation: I18n.default_locale)
+ end
+
+ # ---------- required fields are required ------------
+ test "required fields should be required" do
+ org = Org.new
+ assert_not(org.valid?)
+
+ org.name = 'ABCD'
+ assert(org.valid?)
+ end
+
+ # ---------- short_name ----------
+ test "short_name should return the abbreviation if it exists" do
+ assert_equal(@org.abbreviation, @org.short_name)
+ end
+
+ test "short_name should return the name if no abbreviation exists" do
+ @org.abbreviation = nil
+ assert_equal(@org.name, @org.short_name)
+ end
+
+ # ---------------------------------------------------
+ test "to_s returns the name" do
+ assert_equal @org.name, @org.to_s
+ end
+
+ # ---------------------------------------------------
+ test "only accepts valid contact_email addresses" do
+ assert @org.valid?
+
+ @org.contact_email = 'testing'
+ assert_not @org.valid?
+ @org.contact_email = 'testing.tester.org'
+ assert_not @org.valid?
+ @org.contact_email = 'testing@tester'
+ assert_not @org.valid?
+
+ @org.contact_email = 'testing@tester.org'
+ assert @org.valid?
+ end
+
+ # ---------------------------------------------------
+ test "should resize logo to a height of 100" do
+ ['logo.jpg', # this one is at 160x160
+ 'logo_300x300.jpg',
+ 'logo_100x100.jpg'].each do |file|
+
+ path = File.expand_path("../../assets/#{file}", __FILE__)
+ @org.logo = Dragonfly.app.fetch_file("#{path}")
+
+ assert @org.valid?, "expected the logo to have been attached to the org"
+ assert_equal 100, @org.logo.height, "expected the logo to have been resized properly"
+ end
+ end
+
+ # ---------------------------------------------------
+ test "should remove all associated User's api tokens if no TokenPermissionTypes are present" do
+ @org.token_permission_types << TokenPermissionType.first
+ usr = User.new(email: 'tester@testing.org', password: 'testing123')
+ usr.keep_or_generate_token!
+
+ original = usr.api_token
+ @org.users << usr
+
+ # Make sure that the user's API token was saved
+ @org.save!
+ usr = @org.reload.users.find_by(email: 'tester@testing.org')
+ assert_equal original, usr.api_token
+
+ # TODO: Determine if this should just be removed or if it should still be removing these
+ # Make sure that the user's API token is cleared out when all API permissions
+ # for the org have been removed
+ #@org.token_permission_types.clear
+ #@org.save!
+ #usr = @org.reload.users.find_by(email: 'tester@testing.org')
+ #assert_equal nil, usr.api_token
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD" do
+ org = Org.create(name: 'testing')
+ assert_not org.id.nil?, "was expecting to be able to create a new Org: #{org.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+
+ org.abbreviation = 'TEST'
+ org.save!
+ org.reload
+ assert_equal 'TEST', org.abbreviation, "Was expecting to be able to update the abbreviation of the Org!"
+
+ assert org.destroy!, "Was unable to delete the Org!"
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Users" do
+ usr = User.create(email: 'test@testing.org', password: 'testing1234')
+ verify_has_many_relationship(@org, usr, @org.users.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Dmptemplates" do
+ tmplt = Template.new(title: 'Added through test')
+ verify_has_many_relationship(@org, tmplt, @org.templates.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Customisations" do
+ tmplt = Template.new(title: 'Testing template')
+ verify_has_many_relationship(@org, tmplt, @org.templates.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with GuidanceGroups" do
+ gg = GuidanceGroup.new(name: 'Tester')
+ verify_has_many_relationship(@org, gg, @org.guidance_groups.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with SuggestedAnswers" do
+ sa = SuggestedAnswer.new(question: Question.first, text: 'Test Suggested Answer')
+ verify_has_many_relationship(@org, sa, @org.suggested_answers.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with TokenPermissionTypes" do
+ tpt = TokenPermissionType.new(token_type: 'testing')
+ verify_has_many_relationship(@org, tpt, @org.token_permission_types.count)
+ end
+
+end
diff --git a/test/unit/organisation_test.rb b/test/unit/organisation_test.rb
deleted file mode 100644
index 4ef761a..0000000
--- a/test/unit/organisation_test.rb
+++ /dev/null
@@ -1,143 +0,0 @@
-require 'test_helper'
-
-class OrganisationTest < ActiveSupport::TestCase
- setup do
- @org = organisations(:curation_center)
-
- @org_type = OrganisationType.last
- @language = languages(I18n.default_locale)
- end
-
- # ---------- required fields are required ------------
- test "required fields should be required" do
- org = Org.new
- assert_not(org.valid?)
-
- org.name = 'ABCD'
- assert(org.valid?)
- end
-
- # ---------- short_name ----------
- test "short_name should return the abbreviation if it exists" do
- assert_equal(@org.abbreviation, @org.short_name)
- end
-
- test "short_name should return the name if no abbreviation exists" do
- @org.abbreviation = nil
- assert_equal(@org.name, @org.short_name)
- end
-
- # ---------------------------------------------------
- test "to_s returns the name" do
- assert_equal @org.name, @org.to_s
- end
-
- # ---------------------------------------------------
- test "only accepts valid contact_email addresses" do
- assert @org.valid?
-
- @org.contact_email = 'testing'
- assert_not @org.valid?
- @org.contact_email = 'testing.tester.org'
- assert_not @org.valid?
- @org.contact_email = 'testing@tester'
- assert_not @org.valid?
-
- @org.contact_email = 'testing@tester.org'
- assert @org.valid?
- end
-
- # ---------------------------------------------------
- test "should resize logo to a height of 100" do
- ['logo.jpg', # this one is at 160x160
- 'logo_300x300.jpg',
- 'logo_100x100.jpg'].each do |file|
-
- path = File.expand_path("../../assets/#{file}", __FILE__)
- @org.logo = Dragonfly.app.fetch_file("#{path}")
-
- assert @org.valid?, "expected the logo to have been attached to the organisation"
- assert_equal 100, @org.logo.height, "expected the logo to have been resized properly"
- end
- end
-
- # ---------------------------------------------------
- test "should remove all associated User's api tokens if no TokenPermissionTypes are present" do
- @org.token_permission_types << token_permission_types(:plans_token_type)
- usr = User.new(email: 'tester@testing.org', password: 'testing123')
- usr.keep_or_generate_token!
-
- original = usr.api_token
- @org.users << usr
-
- # Make sure that the user's API token was saved
- @org.save!
- usr = @org.reload.users.find_by(email: 'tester@testing.org')
- assert_equal original, usr.api_token
-
- # TODO: Determine if this should just be removed or if it should still be removing these
- # Make sure that the user's API token is cleared out when all API permissions
- # for the organisation have been removed
- #@org.token_permission_types.clear
- #@org.save!
- #usr = @org.reload.users.find_by(email: 'tester@testing.org')
- #assert_equal nil, usr.api_token
- end
-
- # ---------------------------------------------------
- test "can CRUD" do
- org = Org.create(name: 'testing')
- assert_not org.id.nil?, "was expecting to be able to create a new Organisation: #{org.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
-
- org.abbreviation = 'TEST'
- org.save!
- org.reload
- assert_equal 'TEST', org.abbreviation, "Was expecting to be able to update the abbreviation of the Organisation!"
-
- assert org.destroy!, "Was unable to delete the Organisation!"
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with Users" do
- usr = User.create(email: 'test@testing.org', password: 'testing1234')
- verify_has_many_relationship(@org, usr, @org.users.count)
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with Dmptemplates" do
- tmplt = Dmptemplate.new(title: 'Added through test')
- verify_has_many_relationship(@org, tmplt, @org.dmptemplates.count)
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with Customisations" do
-
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with GuidanceGroups" do
-
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with OptionWarnings" do
-
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with SuggestedAnswers" do
-
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with TokenPermissionTypes" do
- tpt = TokenPermissionType.new(token_type: 'testing')
- verify_has_many_relationship(@org, tpt, @org.token_permission_types.count)
- end
-
- # ---------------------------------------------------
- test "can manage belongs_to relationship with OrganisationType" do
- verify_belongs_to_relationship(@org, @org_type)
- end
-
-end
diff --git a/test/unit/organisation_type_test.rb b/test/unit/organisation_type_test.rb
deleted file mode 100644
index 95f968a..0000000
--- a/test/unit/organisation_type_test.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-require 'test_helper'
-
-class OrganisationTypeTest < ActiveSupport::TestCase
- def setup
- # OrganisationTypes MUST match those defined in the locale's magic strings file
- @organisation_type = organisation_types(I18n.t("magic_strings.organisation_types").first[0])
- end
-
- # ---------------------------------------------------
- test "required fields are required" do
- assert_not OrganisationType.new.valid?
- assert_not OrganisationType.new(description: 'testing').valid?
-
- assert OrganisationType.new(name: 'test').valid?
- assert OrganisationType.new(name: 'test', description: 'testing').valid?
- end
-
- # ---------------------------------------------------
- test "name must be unique" do
- assert_not OrganisationType.new(name: @organisation_type.name).valid?
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with Organisations" do
- organisation = Org.new(name: 'test')
- verify_has_many_relationship(@organisation_type, organisation,
- @organisation_type.organisations.count)
- end
-
- # ---------------------------------------------------
- test "can CRUD" do
- ot = OrganisationType.create(name: 'test', description: 'testing')
- assert_not ot.id.nil?, "was expecting to be able to create a new OrganisationType"
-
- ot.description = 'testing 2'
- ot.save!
- ot.reload
- assert_equal 'testing 2', ot.description, "Was expecting to be able to update the description of the OrganisationType!"
-
- assert ot.destroy!, "Was unable to delete the OrganisationType!"
- end
-
- # ---------------------------------------------------
- test "magic strings match the values in the database/fixtures" do
- I18n.t("magic_strings.organisation_types").each do |k,v|
- assert_not OrganisationType.find_by(name: v).nil?, "An OrganisationType called #{v} is defined in the magic strings section of the locale file, but no matching value exists in the datbase/fixtures!"
- end
- end
-end
\ No newline at end of file
diff --git a/test/unit/page_test.rb b/test/unit/page_test.rb
deleted file mode 100644
index ff943a7..0000000
--- a/test/unit/page_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class PageTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
diff --git a/test/unit/perm_test.rb b/test/unit/perm_test.rb
new file mode 100644
index 0000000..a40c704
--- /dev/null
+++ b/test/unit/perm_test.rb
@@ -0,0 +1,43 @@
+require 'test_helper'
+
+class PermTest < ActiveSupport::TestCase
+
+ setup do
+ @user = User.last
+
+ @perm = Perm.create(name: 'testing')
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not Perm.new.valid?
+
+ # Ensure the bare minimum and complete versions are valid
+ a = Perm.new(name: 'Testing 2')
+ assert a.valid?, "expected the 'name' field to be enough to create an Perm! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ end
+
+ # ---------------------------------------------------
+ test "name field must be unique" do
+ assert_not Perm.new(name: 'testing').valid?
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD Perm" do
+ obj = Perm.create(name: 'Tested ABC')
+ assert_not obj.id.nil?, "was expecting to be able to create a new Perm: #{obj.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+
+ obj.name = 'Testing an update'
+ obj.save!
+ obj.reload
+ assert_equal 'Testing an update', obj.name, "Was expecting to be able to update the name of the Perm!"
+
+ assert obj.destroy!, "Was unable to delete the Perm!"
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with User" do
+ verify_has_many_relationship(@perm, @user, @perm.users.count)
+ end
+
+end
diff --git a/test/unit/phase_test.rb b/test/unit/phase_test.rb
index 65ecf3d..40670fb 100644
--- a/test/unit/phase_test.rb
+++ b/test/unit/phase_test.rb
@@ -1,7 +1,63 @@
-require 'test_helper'
-
-class PhaseTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
+require 'test_helper'
+
+class PhaseTest < ActiveSupport::TestCase
+
+ setup do
+ @org = Org.first
+ @template = Template.first
+ @phase = Phase.create(title: 'Test Phase 1', number: 1, template: @template)
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not Phase.new.valid?
+ assert_not Phase.new(title: 'Testing', number: 1).valid?, "expected the dmptemplate field to be required"
+ assert_not Phase.new(number: 2, template: @template).valid?, "expected the title field to be required"
+ assert_not Phase.new(title: 'Testing', template: @template).valid?, "expected the number field to be required"
+
+ # Ensure the bar minimum and complete versions are valid
+ a = Phase.new(title: 'Testing', template: @template, number: 2)
+ assert a.valid?, "expected the 'title', 'number' and 'template' fields to be enough to create an Phase! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ end
+
+ # ---------------------------------------------------
+ test "a slug is properly generated when creating a record" do
+ a = Phase.create(title: 'Testing 123', template: @template, number: 2)
+ assert_equal "testing-123", a.slug
+ end
+
+ # ---------------------------------------------------
+ test "to_s returns the title" do
+ assert_equal @phase.title, @phase.to_s
+ end
+
+ # ---------------------------------------------------
+ test "has_sections returns false if there are NO published versions with sections" do
+ # TODO: build out this test if the has_sections method is actually necessary
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD Phase" do
+ obj = Phase.create(title: 'Testing CRUD', template: @template, number: 4)
+ assert_not obj.id.nil?, "was expecting to be able to create a new Phase! - #{obj.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+
+ obj.title = 'Testing an update'
+ obj.save!
+ obj.reload
+ assert_equal 'Testing an update', obj.title, "Was expecting to be able to update the title of the Phase!"
+
+ assert obj.destroy!, "Was unable to delete the Phase!"
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Sections" do
+ s = Section.new(title: 'Test Section', number: 2)
+ verify_has_many_relationship(@phase, s, @phase.sections.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with Template" do
+ tmplt = Template.create(org: @org, title: 'Testing relationship')
+ verify_belongs_to_relationship(@phase, tmplt)
+ end
+end
diff --git a/test/unit/plan_section_test.rb b/test/unit/plan_section_test.rb
deleted file mode 100644
index 68788db..0000000
--- a/test/unit/plan_section_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class PlanSectionTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
diff --git a/test/unit/plan_test.rb b/test/unit/plan_test.rb
index 2cbd092..1275ab6 100644
--- a/test/unit/plan_test.rb
+++ b/test/unit/plan_test.rb
@@ -1,87 +1,76 @@
-require 'test_helper'
-
-class PlanTest < ActiveSupport::TestCase
-=begin
- def setup
- @plan = Plan.new.tap do |p|
- p.project = Project.new
- end
- end
-
- def settings(extras = {})
- {
- margin: (@margin || { top: 10, bottom: 10, left: 10, right: 10 }),
- font_face: (@font_face || Settings::Dmptemplate::VALID_FONT_FACES.first),
- font_size: (@font_size || 11)
- }.merge(extras)
- end
-
- # settings
-
- test "no explicit settings should be Settings::Dmptemplate::DEFAULT_SETTINGS" do
- assert(!@plan.settings(:export).value?)
- assert_equal(Settings::Dmptemplate::DEFAULT_SETTINGS[:formatting], @plan.settings(:export).formatting)
- end
-
- test "no explicit settings with template settings should use template settings" do
- template = dmptemplates(:ahrc_template)
- template.settings(:export).update_attributes(formatting: settings)
-
- @plan.project.dmptemplate = template
-
- assert(!@plan.super_settings(:export).value?)
- assert(template.settings(:export).value?)
-
- assert_equal(settings, template.settings(:export).formatting)
- assert_equal(settings, @plan.settings(:export).formatting)
- end
-
- test "explicit settings with template settings should use plan settings" do
- template_settings = settings
- plan_settings = settings(font_size: 14)
-
- template = dmptemplates(:ahrc_template)
- template.settings(:export).update_attributes(formatting: template_settings)
-
- @plan.project.dmptemplate = template
- @plan.super_settings(:export).formatting = plan_settings
- @plan.save!
- @plan.reload
-
- assert(@plan.super_settings(:export).value?)
- assert(@plan.settings(:export).value?)
- assert(template.settings(:export).value?)
-
- assert_not_equal(plan_settings, template_settings)
- assert_equal(template_settings, template.settings(:export).formatting)
- assert_equal(plan_settings, @plan.settings(:export).formatting)
- end
-
- test "explicit settings should not affect other plans with same template" do
- template_settings = settings
- plan_settings = settings(font_size: 14)
-
- template = dmptemplates(:ahrc_template)
- template.settings(:export).update_attributes(formatting: template_settings)
-
- @plan.project.dmptemplate = template
- @plan.super_settings(:export).formatting = plan_settings
- @plan.save!
- @plan.reload
-
- other_plan = Plan.new.tap do |plan|
- plan.project = Project.new.tap {|p| p.dmptemplate = template }
- end
-
- other_plan.save!
- other_plan.reload
-
- assert(@plan.super_settings(:export).value?)
- assert(@plan.settings(:export).value?)
- assert(template.settings(:export).value?)
-
- assert_not_equal(plan_settings, other_plan.settings(:export).formatting)
- assert_equal(template_settings, other_plan.settings(:export).formatting)
- end
-=end
-end
+require 'test_helper'
+
+class PlanTest < ActiveSupport::TestCase
+
+ setup do
+ @org = Org.first
+ @template = Template.first
+ @plan = Plan.create(title: 'Test Plan', template: @template, grant_number: 'Plan12345',
+ identifier: '000912', description: 'This is a test plan',
+ principal_investigator: 'John Doe', principal_investigator_identifier: 'ABC',
+ data_contact: 'john.doe@example.com', visibility: 1, users: [User.last])
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not Plan.new.valid?
+ assert_not Plan.new(users: [User.last], title: 'Testing').valid?, "expected the template field to be required"
+ assert_not Plan.new(template: @template, title: 'Testing').valid?, "expected at least one user to be required"
+
+ # Make sure that the Settings gem is defaulting the title for us
+ assert Plan.new(users: [User.last], template: @template).valid?, "expected the title field to have been set by default by the Settings gem"
+
+ # Ensure the bare minimum and complete versions are valid
+ a = Plan.new(title: 'Testing', template: @template, users: [User.last])
+ assert a.valid?, "expected the 'title', 'template' and at least one 'user' fields to be enough to create an Plan! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ end
+
+ # ---------------------------------------------------
+ test "a slug is properly generated when creating a record" do
+ #p = Plan.create(title: 'Testing 123', template: @template, users: [User.last])
+ #assert_equal "testing-123", p.slug
+ end
+
+ # ---------------------------------------------------
+ test "has_sections returns false if there are NO published versions with sections" do
+ # TODO: build out this test if the has_sections method is actually necessary
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD Plan" do
+ obj = Plan.create(title: 'Testing CRUD', template: Template.where.not(id: @template.id).first,
+ users: [User.last], description: "should change")
+ assert_not obj.id.nil?, "was expecting to be able to create a new Plan! - #{obj.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+
+ obj.description = 'changed'
+ obj.save!
+ obj.reload
+ assert_equal 'changed', obj.description, "Was expecting to be able to update the title of the Plan!"
+
+ assert obj.destroy!, "Was unable to delete the Plan!"
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Answers" do
+ a = Answer.new(user: User.last, plan: @plan, question: @plan.questions.first, text: 'Test!')
+ verify_has_many_relationship(@plan, a, @plan.answers.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Users" do
+ verify_has_many_relationship(@plan, User.first, @plan.users.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with ExportedPlan" do
+ ep = ExportedPlan.create(format: ExportedPlan::VALID_FORMATS.last)
+ verify_has_many_relationship(@plan, ep, @plan.exported_plans.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with Template" do
+ tmplt = Template.create(org: @org, title: 'Testing relationship')
+ verify_belongs_to_relationship(@plan, tmplt)
+ end
+
+end
diff --git a/test/unit/project_group_test.rb b/test/unit/project_group_test.rb
deleted file mode 100644
index 891b697..0000000
--- a/test/unit/project_group_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class ProjectGroupTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
diff --git a/test/unit/project_partner_test.rb b/test/unit/project_partner_test.rb
deleted file mode 100644
index 7324b6c..0000000
--- a/test/unit/project_partner_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class ProjectPartnerTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
diff --git a/test/unit/project_test.rb b/test/unit/project_test.rb
deleted file mode 100644
index 74dcab5..0000000
--- a/test/unit/project_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class ProjectTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
diff --git a/test/unit/question_format_test.rb b/test/unit/question_format_test.rb
new file mode 100644
index 0000000..d936205
--- /dev/null
+++ b/test/unit/question_format_test.rb
@@ -0,0 +1,41 @@
+require 'test_helper'
+
+class QuestionFormatTest < ActiveSupport::TestCase
+
+ def setup
+ @question = Question.first
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not QuestionFormat.new.valid?
+ assert_not QuestionFormat.new(description: 'Random Number').valid?
+
+ assert QuestionFormat.new(title: 'Random').valid?
+ assert QuestionFormat.new(title: 'Random', description: 'Random Number').valid?
+ end
+
+ # ---------------------------------------------------
+ test "abbreviation must be unique" do
+ assert_not QuestionFormat.new(title: QuestionFormat.first.title).valid?
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD" do
+ qf = QuestionFormat.create(title: 'Random', description: 'Random Number')
+ assert_not qf.id.nil?, "was expecting to be able to create a new QuestionFormat : #{qf.errors.collect{ |e| e }.join(', ')}"
+
+ qf.description = 'Random String'
+ qf.save!
+ assert_equal 'Random String', qf.reload.description, "was expecting the description to have been updated!"
+
+ assert qf.destroy!, "Was unable to delete the QuestionFormat!"
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Questions" do
+ qf = QuestionFormat.new(title: 'Random', description: 'Random Number')
+ verify_has_many_relationship(qf, @question, qf.questions.count)
+ end
+
+end
\ No newline at end of file
diff --git a/test/unit/question_option_test.rb b/test/unit/question_option_test.rb
new file mode 100644
index 0000000..52b7674
--- /dev/null
+++ b/test/unit/question_option_test.rb
@@ -0,0 +1,53 @@
+require 'test_helper'
+
+class QuestionQuestionOptionTest < ActiveSupport::TestCase
+ include GlobalHelpers
+
+ setup do
+ @user = User.first
+
+ @question = QuestionFormat.find_by(option_based: true).questions.first
+
+ @plan = Plan.create(title: 'Test Plan', template: @question.section.phase.template)
+
+ @option = QuestionOption.create(question: @question, text: 'Test QuestionOption', number: 1)
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not QuestionOption.new.valid?
+ assert_not QuestionOption.new(question: @question, text: 'Test').valid?, "expected the 'number' field to be required"
+ assert_not QuestionOption.new(question: @question, number: 1).valid?, "expected the 'text' and 'number' field to be required"
+ assert_not QuestionOption.new(text: 'Test', number: 1).valid?, "expected the 'question' and 'number' field to be required"
+
+ # Ensure the bare minimum and complete versions are valid
+ a = QuestionOption.new(question: @question, text: 'Test', number: 1)
+ assert a.valid?, "expected the 'text', 'question' and 'number fields to be enough to create an QuestionOption! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD Guidance" do
+ obj = QuestionOption.create(question: @question, text: 'Test', number: 1)
+ assert_not obj.id.nil?, "was expecting to be able to create a new QuestionOption! #{obj.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+
+ obj.text = 'Testing an update'
+ obj.save!
+ obj.reload
+ assert_equal 'Testing an update', obj.text, "Was expecting to be able to update the text of the QuestionOption!"
+
+ assert obj.destroy!, "Was unable to delete the QuestionOption!"
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with Question" do
+ question = Question.new(text: 'Testing 123', section: Section.first, question_format: QuestionFormat.find_by(option_based: true))
+ verify_belongs_to_relationship(@option, question)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Answers" do
+ answer = Answer.new(user: @user, plan: @plan, question: @question, text: 'Testing new answer',
+ question_options: [@question.question_options.first])
+ verify_has_many_relationship(@option, answer, @option.answers.count)
+ end
+end
\ No newline at end of file
diff --git a/test/unit/question_test.rb b/test/unit/question_test.rb
index f54eeaa..f5f3d4d 100644
--- a/test/unit/question_test.rb
+++ b/test/unit/question_test.rb
@@ -1,7 +1,138 @@
-require 'test_helper'
-
-class QuestionTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
+require 'test_helper'
+
+class QuestionTest < ActiveSupport::TestCase
+
+ setup do
+ @user = User.last
+
+ scaffold_template
+
+ @section = @template.phases.first.sections.first
+
+ @question = Question.create(text: 'Test question', default_value: 'ABCD', guidance: 'Hello',
+ number: 999, section: @section,
+ question_format: QuestionFormat.where(option_based: false).first,
+ option_comment_display: true, modifiable: true)
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not Question.new.valid?
+ assert_not Question.new(section: @section, number: 7).valid?, "expected the 'text' field to be required"
+ assert_not Question.new(number: 7, text: 'Testing').valid?, "expected the 'section' field to be required"
+ assert_not Question.new(section: @section, text: 'Testing').valid?, "expected the 'number' field to be required"
+
+ # Ensure the bar minimum and complete versions are valid
+ a = Question.new(section: @section, text: 'Testing', number: 7)
+ assert a.valid?, "expected the 'text', 'section' and 'number' fields to be enough to create an Question! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ end
+
+ # ---------------------------------------------------
+ test "to_s returns the Question text" do
+ assert_equal @question.text, @question.to_s
+ end
+
+ # ---------------------------------------------------
+ test "returns the correct themed guidance for the org" do
+ all = Theme.first.guidances + Theme.last.guidances
+
+ # Attach 2 themes to the question
+ @question.themes = [Theme.first, Theme.last]
+ @question.save!
+
+ # Attach the first theme's first gudiance's group to the org
+ @user.org.guidance_groups << Theme.first.guidances.first.guidance_group
+ @user.save!
+
+ assert_not @question.guidance_for_org(@user.org).empty?, "expected guidance to be returned"
+
+ assert @question.guidance_for_org(@user.org).first.first.include?(Theme.first.title), "expected the theme.title"
+ assert @question.guidance_for_org(@user.org).first.first.include?(Theme.first.guidances.first.guidance_group.name), "expected the guidance_group.name"
+ assert_equal Theme.first.guidances.first, @question.guidance_for_org(@user.org).first.last, "expected the guidance object to be returned"
+ end
+
+ # ---------------------------------------------------
+ test "returns the correct suggested answer for the org" do
+ @question.suggested_answers = [SuggestedAnswer.new(org: @user.org, text: 'Test 1', is_example: false),
+ SuggestedAnswer.new(org: Org.first, text: 'Test 2', is_example: false)]
+ @question.save!
+
+ assert_equal 'Test 1', @question.get_suggested_answer(@user.org.id).text, "expected the correct suggested answer"
+ assert_equal 'Test 2', @question.get_suggested_answer(Org.first.id).text, "expected the correct suggested answer"
+
+ org = Org.create(name: 'New One')
+ assert_equal nil, @question.get_suggested_answer(org.id), "expected no suggested answer for a new org"
+ end
+
+ # ---------------------------------------------------
+# TODO: amoeba gem doesn't seem to be in play anymore
+=begin
+ test "should be able to clone a Question (should include its question_options, themes suggested_answers)" do
+ Question.all.each do |question|
+puts question.inspect
+ q = question.amoeba_dup
+
+ assert_equal question.text, q.text, "expected the 'text' field to match"
+ assert_equal question.default_value, q.default_value, "expected the 'default_value' field to match"
+ assert_equal question.guidance, q.guidance, "expected the 'guidance' field to match"
+ assert_equal question.number, q.number, "expected the 'number' field to match"
+ assert_equal question.section, q.section, "expected the 'section' field to match"
+ assert_equal question.question_format, q.question_format, "expected the 'question_format' field to match"
+ assert_equal question.option_comment_display, q.option_comment_display, "expected the 'option_comment_display' field to match"
+ assert_equal question.modifiable, q.modifiable, "expected the 'modifiable' field to match"
+
+ assert q.question_options.eql?(question.question_options), "expected the clone to carry over all of the question_options instead got: original - #{question.question_options.count}, clone - #{q.question_options.count}"
+ assert q.suggested_answers.eql?(question.suggested_answers), "expected the clone to carry over all of the suggested_answers instead got: original - #{question.suggested_answers.count}, clone - #{q.suggested_answers.count}"
+ assert q.themes.eql?(question.themes), "expected the clone to carry over all of the suggested_answers instead got: original - #{question.themes.count}, clone - #{q.themes.count}"
+ end
+ end
+=end
+
+ # ---------------------------------------------------
+ test "can CRUD Question" do
+ obj = Question.create(section: @section, text: 'Test ABC', number: 7)
+ assert_not obj.id.nil?, "was expecting to be able to create a new Question: #{obj.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+
+ obj.text = 'Testing an update'
+ obj.save!
+ obj.reload
+ assert_equal 'Testing an update', obj.text, "Was expecting to be able to update the text of the Question!"
+
+ assert obj.destroy!, "Was unable to delete the Question!"
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with Section" do
+ verify_belongs_to_relationship(@question, @template.phases.first.sections.last)
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with QuestionFormat" do
+ verify_belongs_to_relationship(@question, QuestionFormat.where(option_based: false).last)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Answer" do
+ scaffold_plan
+ a = Answer.new(user: @user, plan: @plan, text: 'Test Answer')
+ verify_has_many_relationship(@question, a, @question.answers.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with QuestionOption" do
+ qo = QuestionOption.new(text: 'Test', number: 9)
+ verify_has_many_relationship(@question, qo, @question.question_options.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with SuggestedAnswer" do
+ sa = SuggestedAnswer.new(text: 'Suggested Answer', org: @user.org)
+ verify_has_many_relationship(@question, sa, @question.suggested_answers.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Themes" do
+ t = Theme.new(title: 'Test Theme')
+ verify_has_many_relationship(@question, t, @question.themes.count)
+ end
+end
diff --git a/test/unit/region_test.rb b/test/unit/region_test.rb
new file mode 100644
index 0000000..422f8fd
--- /dev/null
+++ b/test/unit/region_test.rb
@@ -0,0 +1,55 @@
+require 'test_helper'
+
+class RegionTest < ActiveSupport::TestCase
+
+ setup do
+ @region = Region.create(name: 'Test Super Region', abbreviation: 'TSR', description: 'Testing')
+
+ @region.sub_regions = [Region.new(name: 'Test Sub Region 1'), Region.new(name: 'Test Sub Region 2')]
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not Region.new.valid?
+
+ # Ensure the bar minimum and complete versions are valid
+ a = Region.new(name: 'Test Region')
+ assert a.valid?, "expected the 'name' field to be enough to create an Region! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ end
+
+ # ---------------------------------------------------
+ test "name and abbreviation should be unique" do
+ assert_not Region.new(name: 'Test Super Region').valid?, "expected that 'name' must be unique"
+ assert_not Region.new(abbreviation: 'TSR').valid?, "expected that 'abbreviation' must be unique"
+
+ assert_not Region.new(name: 'Test Super Region', abbreviation: '123').valid?, "expected that 'name' must be unique even if abbreviation is unique"
+ assert_not Region.new(abbreviation: 'TSR', name: 'test super').valid?, "expected that 'abbreviation' must be unique even if name is unique"
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD Region" do
+ obj = Region.create(name: 'Test Region')
+ assert_not obj.id.nil?, "was expecting to be able to create a new Region: #{obj.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+
+ obj.abbreviation = 'ABC'
+ obj.save!
+ obj.reload
+ assert_equal 'ABC', obj.abbreviation, "Was expecting to be able to update the text of the Region!"
+
+ assert obj.destroy!, "Was unable to delete the Region!"
+ end
+
+ # Need to roll our own here because of the name of the relationship attributes
+ # ---------------------------------------------------
+ test "can manage has_and_belongs_to_many relationship with Region" do
+ count = Region.first.sub_regions.count
+
+ @region.super_region = Region.first
+ @region.save!
+
+ # Search the parent for the child
+ assert Region.first.sub_regions.include?(@region), "was expecting the Region.sub_regions to contain the test region"
+ assert_equal (count + 1), Region.first.sub_regions.count
+ end
+
+end
\ No newline at end of file
diff --git a/test/unit/section_test.rb b/test/unit/section_test.rb
deleted file mode 100644
index f21fdcf..0000000
--- a/test/unit/section_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class SectionTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
diff --git a/test/unit/template_test.rb b/test/unit/template_test.rb
new file mode 100644
index 0000000..0db44c4
--- /dev/null
+++ b/test/unit/template_test.rb
@@ -0,0 +1,347 @@
+require 'test_helper'
+
+class TemplateTest < ActiveSupport::TestCase
+
+ setup do
+ @template = Dmptemplate.first
+
+ @organisation = Organisation.first
+ end
+
+ def settings(extras = {})
+ {margin: (@margin || { top: 10, bottom: 10, left: 10, right: 10 }),
+ font_face: (@font_face || Settings::Dmptemplate::VALID_FONT_FACES.first),
+ font_size: (@font_size || 11)
+ }.merge(extras)
+ end
+
+ def default_formatting
+ Settings::Dmptemplate::DEFAULT_SETTINGS[:formatting]
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not Dmptemplate.new.valid?
+ assert_not Dmptemplate.new(title: 'Testing tmeplate').valid?, "expected the 'organisation' field to be required"
+ assert_not Dmptemplate.new(organisation: @organisation).valid?, "expected the 'title' field to be required"
+
+ # Ensure the bar minimum and complete versions are valid
+ a = Dmptemplate.new(organisation: @organisation, title: 'Testing tmeplate')
+ assert a.valid?, "expected the 'title' and 'organisation' fields to be enough to create an Dmptemplate! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ end
+
+ # ---------------------------------------------------
+ test "to_s method returns the title" do
+ assert_equal @template.title, @template.to_s
+ end
+
+
+ # ---------- settings ----------
+ # ---------------------------------------------------
+ test "settings should use defaults if none are defined" do
+ assert(!@template.settings(:export).value?)
+ assert_equal(default_formatting, @template.settings(:export).formatting)
+ end
+
+ # ---------------------------------------------------
+ test "settings should use defined valid settings" do
+ @template.settings(:export).formatting = settings
+ @template.save!
+
+ assert(@template.settings(:export).value?)
+ assert_equal(settings, @template.settings(:export).formatting)
+ assert_not_equal(default_formatting, @template.settings(:export).formatting)
+ end
+
+ # ---------------------------------------------------
+ test "setting negative margin should not be valid" do
+ @margin = { top: -10, bottom: 10, left: 10, right: 10 }
+
+ @template.settings(:export).formatting = settings
+
+ assert(!@template.valid?)
+ assert(!@template.save)
+
+ assert_equal(I18n.t('helpers.settings.plans.errors.negative_margin'),
+ @template.errors.messages[:'setting_objects.formatting'].first)
+
+ @template.reload
+ assert_equal(default_formatting, @template.settings(:export).formatting)
+ end
+
+ # ---------------------------------------------------
+ test "setting unknown margin should not be valid" do
+ @margin = { top: 10, bottom: 10, left: 10, right: 10, top_left: 10 }
+
+ @template.settings(:export).formatting = settings
+
+ assert(!@template.valid?)
+ assert(!@template.save)
+
+ assert_equal(I18n.t('helpers.settings.plans.errors.unknown_margin'),
+ @template.errors.messages[:'setting_objects.formatting'].first)
+
+ @template.reload
+ assert_equal(default_formatting, @template.settings(:export).formatting)
+ end
+
+ # ---------------------------------------------------
+ test "setting negative font-size should not be valid" do
+ @font_size = -11
+
+ @template.settings(:export).formatting = settings
+
+ assert(!@template.valid?)
+ assert(!@template.save)
+
+ assert_equal(I18n.t('helpers.settings.plans.errors.invalid_font_size'),
+ @template.errors.messages[:'setting_objects.formatting'].first)
+
+ @template.reload
+
+ assert_equal(default_formatting, @template.settings(:export).formatting)
+ end
+
+ # ---------------------------------------------------
+ test "setting unknown key should not be valid" do
+ @template.settings(:export).formatting = settings(foo: :bar)
+
+ assert(!@template.valid?)
+ assert(!@template.save)
+
+ assert_equal(I18n.t('helpers.settings.plans.errors.unknown_key'),
+ @template.errors.messages[:'setting_objects.formatting'].first)
+
+ @template.reload
+
+ assert_equal(default_formatting, @template.settings(:export).formatting)
+ end
+
+ # ---------------------------------------------------
+ test "not setting font_face should not be valid" do
+ @template.settings(:export).formatting = settings.reject {|k,v| k == :font_face }
+
+ assert(!@template.valid?)
+ assert(!@template.save)
+
+ assert_equal(I18n.t('helpers.settings.plans.errors.missing_key'),
+ @template.errors.messages[:'setting_objects.formatting'].first)
+
+ @template.reload
+
+ assert_equal(default_formatting, @template.settings(:export).formatting)
+ end
+
+ # ---------------------------------------------------
+ test "not setting font_size should not be valid" do
+ @template.settings(:export).formatting = settings.reject {|k,v| k == :font_size }
+
+ assert(!@template.valid?)
+ assert(!@template.save)
+
+ assert_equal(I18n.t('helpers.settings.plans.errors.missing_key'),
+ @template.errors.messages[:'setting_objects.formatting'].first)
+
+ @template.reload
+
+ assert_equal(default_formatting, @template.settings(:export).formatting)
+ end
+
+ # ---------------------------------------------------
+ test "not setting margin should not be valid" do
+ @template.settings(:export).formatting = settings.reject {|k,v| k == :margin }
+
+ assert(!@template.valid?)
+ assert(!@template.save)
+
+ assert_equal(I18n.t('helpers.settings.plans.errors.missing_key'),
+ @template.errors.messages[:'setting_objects.formatting'].first)
+
+ @template.reload
+
+ assert_equal(default_formatting, @template.settings(:export).formatting)
+ end
+
+ # ---------------------------------------------------
+ test "setting non-hash as margin should not be valid" do
+ @margin = :foo
+
+ @template.settings(:export).formatting = settings
+
+ assert(!@template.valid?)
+ assert(!@template.save)
+
+ assert_equal(I18n.t('helpers.settings.plans.errors.invalid_margin'),
+ @template.errors.messages[:'setting_objects.formatting'].first)
+
+ @template.reload
+
+ assert_equal(default_formatting, @template.settings(:export).formatting)
+ end
+
+ # ---------------------------------------------------
+ test "setting non-integer as font_size should not be valid" do
+ @font_size = "foo"
+
+ @template.settings(:export).formatting = settings
+
+ assert(!@template.valid?)
+ assert(!@template.save)
+
+ assert_equal(I18n.t('helpers.settings.plans.errors.invalid_font_size'),
+ @template.errors.messages[:'setting_objects.formatting'].first)
+
+ @template.reload
+
+ assert_equal(default_formatting, @template.settings(:export).formatting)
+ end
+
+ # ---------------------------------------------------
+ test "setting non-string as font_face should not be valid" do
+ @font_face = 1
+
+ @template.settings(:export).formatting = settings
+
+ assert(!@template.valid?)
+ assert(!@template.save)
+
+ assert_equal(I18n.t('helpers.settings.plans.errors.invalid_font_face'),
+ @template.errors.messages[:'setting_objects.formatting'].first)
+
+ @template.reload
+
+ assert_equal(default_formatting, @template.settings(:export).formatting)
+ end
+
+ # ---------------------------------------------------
+ test "setting unknown string as font_face should not be valid" do
+ @font_face = 'Monaco, Monospace, Sans-Serif'
+
+ @template.settings(:export).formatting = settings
+
+ assert(!@template.valid?)
+ assert(!@template.save)
+
+ assert_equal(I18n.t('helpers.settings.plans.errors.invalid_font_face'),
+ @template.errors.messages[:'setting_objects.formatting'].first)
+
+ @template.reload
+
+ assert_equal(default_formatting, @template.settings(:export).formatting)
+ end
+
+<<<<<<< HEAD
+=======
+ # ---------- templates_org_type ----------
+ test "templates_org_type returns all published" do
+ OrganisationType.find_each do |org_type|
+ result_templates = Dmptemplate.templates_org_type(org_type.name)
+ my_list = Array.new
+ org_type.organisations.each do |org|
+ my_list += org.dmptemplates
+ end
+ my_list.each do |template|
+ if template.published
+ assert_includes(result_templates, template, "Template: #{template.title}} of type #{org_type.name}, not returned by templates_org_type")
+ end
+ end
+ end
+ end
+
+ # ---------- funders_templates ----------
+ test "funders_templates returns all funder organisation templates" do
+ result_templates = Dmptemplate.funders_templates
+ funder_templates = OrganisationType.first.organisations do |org|
+ org.dmptemplates.each do |template|
+ assert_includes( result_templates, template, "Funder Template: #{template.title} not included in result of funders_templates")
+ end
+ end
+ end
+
+ # ---------- own_institutional_templates ----------
+ test "own_institutional_templates returns all templates belonging to given org_id" do
+ Org.find_each do |org|
+ result_templates = Dmptemplate.own_institutional_templates(org.id)
+ org.dmptemplates.each do |template|
+ assert_includes(result_templates, template, "Template: #{template.title} not returned by own_institutional_templates")
+ end
+ end
+ end
+
+ # ---------- funders_and_own_templates ----------
+ test "funders_and_own_templates returns all funder and own given org_id templates" do
+ Org.find_each do |org|
+ result_templates = Dmptemplate.funders_and_own_templates(org.id)
+ org.dmptemplates.each do |template|
+ assert_includes(result_templates, template, "Template #{template.title} not returned by funders and own templates")
+ end
+ end
+ funder_templates = OrganisationType.first.organisations do |org|
+ org.dmptemplates.each do |template|
+ assert_includes( result_templates, template, "Funder Template: #{template.title} not included in result of funders_and_own_templates")
+ end
+ end
+ end
+
+ # ---------- org_type ----------
+ test "org_type properly returns the name of the template's organisation's type" do
+ Dmptemplate.find_each do |template|
+ assert_equal( template.org_type, template.organisation.organisation_type.name, "Template: #{template.title} returned #{template.org_type}, instead of #{template.organisation.organisation_type.name}")
+ end
+ end
+
+>>>>>>> final_schema
+ # ---------- has_customisations? ----------
+ test "has_customisations? correctly identifies if a given org has customised the template" do
+ # TODO: Impliment after understanding has_customisations
+
+ end
+
+ # ---------- has_published_versions? ----------
+ test "has_published_versions? correctly identifies published versions" do
+ Dmptemplate.find_each do |template|
+ template.phases.each do |phase|
+ unless phase.latest_published_version.nil?
+ assert(template.has_published_versions? , "there was a published version of phase: #{phase.title}")
+ end
+ end
+ end
+ end
+
+ # ---------------------------------------------------
+ test "can CRUD Template" do
+ tmplt = Dmptemplate.create(organisation: @organisation, title: 'Testing tmeplate')
+ assert_not tmplt.id.nil?, "was expecting to be able to create a new Dmptemplate!"
+
+ tmplt.description = 'Testing an update'
+ tmplt.save!
+ tmplt.reload
+ assert_equal 'Testing an update', tmplt.description, "Was expecting to be able to update the description of the Dmptemplate!"
+
+ assert tmplt.destroy!, "Was unable to delete the Dmptemplate!"
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Phase" do
+ phase = Phase.new(title: 'Test Phase', number: 2)
+ verify_has_many_relationship(@template, phase, @template.phases.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with Project" do
+ project = Project.new(title: 'Test Project', organisation: @organisation)
+ verify_has_many_relationship(@template, project, @template.projects.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage has_many relationship with GuidanceGroup" do
+ grp = GuidanceGroup.new(name: 'Test Group', organisation: @organisation)
+ verify_has_many_relationship(@template, grp, @template.guidance_groups.count)
+ end
+
+ # ---------------------------------------------------
+ test "can manage belongs_to relationship with Organisation" do
+ verify_belongs_to_relationship(@template, @organisation)
+ end
+
+end
diff --git a/test/unit/theme_test.rb b/test/unit/theme_test.rb
deleted file mode 100644
index c61fe99..0000000
--- a/test/unit/theme_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class ThemeTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
diff --git a/test/unit/token_permission_type_test.rb b/test/unit/token_permission_type_test.rb
index c09aa85..58820ba 100644
--- a/test/unit/token_permission_type_test.rb
+++ b/test/unit/token_permission_type_test.rb
@@ -31,8 +31,13 @@
end
# ---------------------------------------------------
+<<<<<<< HEAD
+ test "can manage has_many relationship with Organisation" do
+ org = Organisation.new(name: 'Testing')
+=======
test "can manage has_many relationship with OrgTokenPermissions" do
org = Org.new(name: 'Testing')
+>>>>>>> final_schema
verify_has_many_relationship(@tpt, org, @tpt.organisations.count)
end
diff --git a/test/unit/user_identifier_test.rb b/test/unit/user_identifier_test.rb
new file mode 100644
index 0000000..007059a
--- /dev/null
+++ b/test/unit/user_identifier_test.rb
@@ -0,0 +1,33 @@
+require 'test_helper'
+
+class UserIdentifierTest < ActiveSupport::TestCase
+
+ def setup
+ @user = User.first
+ @scheme = IdentifierScheme.first
+ end
+
+ # ---------------------------------------------------
+ test "required fields are required" do
+ assert_not UserIdentifier.new.valid?
+ assert_not UserIdentifier.new(user: @user).valid?
+ assert_not UserIdentifier.new(identifier_scheme: @scheme).valid?
+ assert_not UserIdentifier.new(identifier: 'TEST').valid?
+ assert_not UserIdentifier.new(user: @user, identifier_scheme: @scheme).valid?
+ assert_not UserIdentifier.new(user: @user, identifier: 'TEST').valid?
+ assert_not UserIdentifier.new(identifier_scheme: @scheme, identifier: 'TEST').valid?
+
+ assert UserIdentifier.new(user: @user, identifier_scheme: @scheme, identifier: 'TEST').valid?
+ end
+
+ # ---------------------------------------------------
+ test "can only have one identifier per User/IdentifierScheme" do
+ ui = UserIdentifier.create(user: @user, identifier_scheme: @scheme, identifier: 'TEST')
+
+ @user.user_identifiers << UserIdentifier.new(identifier_scheme: @scheme, identifier: 'abc')
+
+ assert_not @user.valid?, "Expected to NOT be able to add more than one identifier for the same user/scheme"
+ assert_equal ui.identifier, @user.user_identifiers.select{ |i| i.identifier_scheme == @scheme }.first.identifier, "Expected the initial identifier to have been retained"
+ end
+
+end
\ No newline at end of file
diff --git a/test/unit/user_role_type_test.rb b/test/unit/user_role_type_test.rb
deleted file mode 100644
index eca639c..0000000
--- a/test/unit/user_role_type_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class UserRoleTypeTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end
diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb
index 65dc38b..194cd8b 100644
--- a/test/unit/user_test.rb
+++ b/test/unit/user_test.rb
@@ -135,6 +135,22 @@
end
# ---------------------------------------------------
+ test "can only have one identifier per IdentifierScheme" do
+ @scheme = IdentifierScheme.first
+
+ count = @super.user_identifiers.count
+ @super.user_identifiers << UserIdentifier.new(identifier_scheme: @scheme, identifier: 'abc')
+ @super.save!
+ @super.reload
+
+ assert_equal (count + 1), @super.user_identifiers.count, "Expected the initial identifier to be saved"
+
+ @super.user_identifiers << UserIdentifier.new(identifier_scheme: @scheme, identifier: 'abc')
+ assert_not @super.valid?, "Expected to NOT be able to add more than one identifier for the same scheme"
+ assert_equal (count + 1), @super.user_identifiers.count, "Expected the initial identifier to be saved"
+ end
+
+ # ---------------------------------------------------
test "can CRUD" do
usr = User.create(email: 'test@testing.org', password: 'testing1234')
assert_not usr.id.nil?, "was expecting to be able to create a new User: #{usr.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
@@ -154,6 +170,12 @@
end
# ---------------------------------------------------
+ test "can manage has_many relationship with UserIdentifiers" do
+ id = UserIdentifier.new(identifier_scheme: IdentifierScheme.first, identifier: 'tester')
+ verify_has_many_relationship(@super, id, @super.user_identifiers.count)
+ end
+
+ # ---------------------------------------------------
test "can manage has_many relationship with Projects" do
# TODO: need to change dmptemplate_id to dmptemplate after refactor of Project
project = Project.new(title: 'Test Project', dmptemplate_id: @dmptemplate.id)
@@ -166,7 +188,7 @@
project = Project.new(title: 'Test Project', dmptemplate_id: @dmptemplate.id)
plan = Plan.new(project: project)
question = Question.new(text: 'testing question')
- answer = Answer.new(plan: plan, question: question)
+ answer = Answer.new(plan: plan, question: question, text: "Here's my answer")
verify_has_many_relationship(@super, answer, @super.answers.count)
end
diff --git a/test/unit/version_test.rb b/test/unit/version_test.rb
deleted file mode 100644
index a1a033c..0000000
--- a/test/unit/version_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class VersionTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
-end