diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml
index 79ecfeb7a9..af1fab23a8 100644
--- a/.github/workflows/eslint.yml
+++ b/.github/workflows/eslint.yml
@@ -9,6 +9,9 @@ jobs:
steps:
- uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 16
- name: Install modules
run: yarn
- name: Run ESLint
diff --git a/.github/workflows/mysql.yml b/.github/workflows/mysql.yml
index 418354b21d..ec194cad36 100644
--- a/.github/workflows/mysql.yml
+++ b/.github/workflows/mysql.yml
@@ -1,6 +1,6 @@
name: Tests - MySQL
-on: [pull_request]
+on: [push, pull_request]
jobs:
mysql:
@@ -16,6 +16,9 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 1
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 16
- name: 'Install MySQL Packages'
run: |
@@ -62,7 +65,7 @@ jobs:
# generate a default credential file and key
EDITOR='echo "$(cat config/credentials.yml.example)" >' bundle exec rails credentials:edit
- # Try to retrieve the yarn JS dependencies from the cache
+ # # Try to retrieve the yarn JS dependencies from the cache
- name: 'Cache Yarn Packages'
uses: actions/cache@v2.1.5
with:
@@ -97,6 +100,7 @@ jobs:
bin/rails webpacker:compile
bin/rails assets:precompile
+ # Note V3.1.0 DMPTool commented out Karma tests and will move this part to rspec
- name: 'Run Karma Tests'
run: yarn test
diff --git a/.github/workflows/postgres.yml b/.github/workflows/postgres.yml
index 3d340eefda..1a5d3852f3 100644
--- a/.github/workflows/postgres.yml
+++ b/.github/workflows/postgres.yml
@@ -32,6 +32,9 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 1
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 16
- name: 'Install Postgresql Packages'
run: |
diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml
index e736a45646..f650d13435 100644
--- a/.github/workflows/ruby.yml
+++ b/.github/workflows/ruby.yml
@@ -27,6 +27,9 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 1
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 16
- name: 'Install MySQL Packages'
run: |
diff --git a/.gitignore b/.gitignore
index 4e4f391fcc..f9b1418bbf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,6 +50,8 @@ coverage
# config/branding.yml
# Ignore some of the initializers
+# 3.1.0
+config/initializers/wicked_pdf.rb
config/initializers/fingerprint.rb
# Ignore enviroments settings
@@ -86,7 +88,8 @@ yarn-error.log
yarn-debug.log*
.env
-.env-working
+# integration
+.env-working
package-lock.json
node_modules
/public/packs
@@ -110,3 +113,6 @@ yarn-debug.log*
/yarn-error.log
yarn-debug.log*
.yarn-integrity
+
+# Ignore staging files in db folder since they can be auto-generated
+/db/seeds/staging
\ No newline at end of file
diff --git a/.rubocop.yml b/.rubocop.yml
index af6bbac1ba..66853ae6ff 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,179 +1,195 @@
+# ----------------
+# - INSTRUCTIONS -
+# ----------------
+# The DMPRoadmap codebase tries to follow the latest Ruby/Rails style guidelines as defined
+# by the community via the Rubocop gem.
+#
+# Before submitting a PR, please run `bin/rubocop` from the project root.
+# Note that you can specify individual files or folders e.g.: `bin/rubocop app/mailers`
+# Note you can let Rubocop auto-correct many issues with the `-a` flag
+#
+# New versions of Rubocop typically include new Cops (Cops are inidivual Rubocop rules).
+# If you see a message like the following when you run `bin/rubocop`:
+#
+# "The following cops were added to RuboCop, but are not configured. Please set Enabled
+# to either `true` or `false` in your `.rubocop.yml` file."
+#
+# You should copy and paste the specified Cops into this file. You can review what the
+# Cop will do by Googling the name of the rule e.g.: "rubocop Layout/SpaceBeforeBrackets"
+#
+# After you review the rule, you can either Enable it or Disable it in this file. The
+# Rubocop documentation for the Cop may also give you additional options that can be
+# configured.
+#
+# Try to place any new Cops under their relevant section and in alphabetical order
+
AllCops:
- # Cache the results for faster processing
- UseCache: true
# Show the name of the cops being voilated in the feedback
DisplayCopNames: true
DisplayStyleGuide: true
+
+ # Rubocop will skip checking the following directories
Exclude:
- 'bin/**/*'
- 'db/**/*'
- 'vendor/**/*'
- 'node_modules/**/*'
- - 'test/**/*'
- - 'lib/tasks/*'
+ - 'scripts/**/*'
-# Force no empty lines at the start or end of a block's body. Ignore specs, since this
-# improves readability within the RSpec blocks.
-Layout/EmptyLinesAroundBlockBody:
- Exclude:
- - 'spec/**/*'
+ # Automatically add any new Cops to this file and enable them
+ NewCops: enable
-# Force a single blank line around a class's body. Adding this whitespace makes code
-# a bit easier to read.
-Layout/EmptyLinesAroundClassBody:
- Enabled: true
- EnforcedStyle: empty_lines
-
-# Force a single blank line around a module's body. Adding this whitespace makes code
-# a bit easier to read.
-Layout/EmptyLinesAroundModuleBody:
- Enabled: true
- EnforcedStyle: empty_lines
+ # Cache the results for faster processing
+ UseCache: true
-# Ignore this cop. The Rubocop default is sensible, but the rubocop-rails gem modifies
-# this to position end keywords awkwardly.
-Layout/EndAlignment:
+# -----------
+# - GEMSPEC -
+# -----------
+Gemspec/DeprecatedAttributeAssignment:
Enabled: true
- EnforcedStyleAlignWith: keyword
-
-# The difference between `rails` and `normal` is that the `rails` style
-# prescribes that in classes and modules the `protected` and `private`
-# modifier keywords shall be indented the same as public methods and that
-# protected and private members shall be indented one step more than the
-# modifiers. Other than that, both styles mean that entities on the same
-# logical depth shall have the same indentation.
-Layout/IndentationConsistency:
- Description: 'Keep indentation straight.'
- StyleGuide: '#spaces-indentation'
- Enabled: true
- EnforcedStyle: normal
-Layout/IndentationWidth:
- Description: 'Use 2 spaces for indentation.'
- StyleGuide: '#spaces-indentation'
+# ----------
+# - LAYOUT -
+# ----------
+Layout/LineEndStringConcatenationIndentation: # new in 1.18
Enabled: true
-
-# Restrict the length of each line of code to 90 characters. Enforcing this is important
-# as many developers are working on smaller screens, or split screens. Having to scroll
-# to read a full line of code makes code harder to read and more frustrating to work with.
-Layout/LineLength:
- # I've found that 90 is a suitable limit. Many developers balk at the 80 character
- # default.
- Max: 100
-
-Layout/EmptyLinesAroundAttributeAccessor:
+Layout/SpaceBeforeBrackets: # new in 1.7
Enabled: true
-Layout/SpaceAroundMethodCallOperator:
+# --------
+# - LINT -
+# --------
+Lint/AmbiguousAssignment: # new in 1.7
Enabled: true
-
-# Enforce this in the main code but ignore it in specs since the Rspec core methods
-# are defined as potentially ambiguous blocks
Lint/AmbiguousBlockAssociation:
Exclude:
- 'spec/**/*'
-
-Lint/DeprecatedOpenSSLConstant:
+Lint/AmbiguousOperatorPrecedence: # new in 1.21
Enabled: true
-
-Lint/MixedRegexpCaptureTypes:
+Lint/AmbiguousRange: # new in 1.19
Enabled: true
-
-Lint/RaiseException:
+Lint/DeprecatedConstants: # new in 1.8
Enabled: true
-
-Lint/StructNewOverride:
+Lint/DuplicateBranch: # new in 1.3
+ Enabled: true
+Lint/DuplicateRegexpCharacterClassElement: # new in 1.1
+ Enabled: true
+Lint/EmptyBlock: # new in 1.1
+ Enabled: true
+Lint/EmptyClass: # new in 1.3
+ Enabled: true
+Lint/EmptyInPattern: # new in 1.16
+ Enabled: true
+Lint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21
+ Enabled: true
+Lint/LambdaWithoutLiteralBlock: # new in 1.8
+ Enabled: true
+Lint/NoReturnInBeginEndBlocks: # new in 1.2
+ Enabled: true
+Lint/NumberedParameterAssignment: # new in 1.9
+ Enabled: true
+Lint/OrAssignmentToConstant: # new in 1.9
+ Enabled: true
+Lint/RedundantDirGlobSort: # new in 1.8
+ Enabled: true
+Lint/RequireRelativeSelfPath: # new in 1.22
+ Enabled: true
+Lint/SymbolConversion: # new in 1.9
+ Enabled: true
+Lint/ToEnumArguments: # new in 1.1
+ Enabled: true
+Lint/TripleQuotes: # new in 1.9
+ Enabled: true
+Lint/UnexpectedBlockArity: # new in 1.5
+ Enabled: true
+Lint/UnmodifiedReduceAccumulator: # new in 1.1
+ Enabled: true
+Lint/Debugger: # new in 1.45.0
+ Description: 'Check for debugger calls.'
Enabled: true
-
-# Bumping the default AbcSize so we don't need to refactor everything
-Metrics/AbcSize:
- Max: 25
-
-# Restrict the number of lines of code that may be within a block of code. This should
-# force developers to break their code into smaller discrete methods or objects.
-Metrics/BlockLength:
- # Exclude specs, since those are defined as large blocks of code
Exclude:
- - 'spec/**/*'
-
-# Bumping the default ClassLength so we don't need to refactor everything
+ - 'lib/tasks/**/*'
+
+# -----------
+# - METRICS -
+# -----------
+# briley Oct. 4th 2021
+# Default is 100 lines. Most of our controllers, models, etc. violate this
+# Cop, so setting it to 300 since we do not have time to refactor everything
Metrics/ClassLength:
Max: 300
-
-# Bumping the default CyclomaticComplexity so we don't need to refactor everything
-Metrics/CyclomaticComplexity:
- Max: 25
-
-# Bumping the default MethodLength so we don't need to refactor everything
+# briley Oct. 4th 2021
+# Default is 10 lines which feels very restrictive but would also require us to do
+# too much refactoring at this point.
Metrics/MethodLength:
- Max: 25
-
-# Bumping the default PerceivedComplexity so we don't need to refactor everything
-Metrics/PerceivedComplexity:
- Max: 25
+ Max: 20
-# This cop enforces the use of boolean and/or "&&" and "||" over "and" "or".
-# Sometimes using "and"/"or" is preferrable, when these are used as control flow.
-#
-# For example:
-#
-# render text: "Hello world" and return
-#
-Style/AndOr:
- Enabled: false
-
-# This cop enforces how modules and classes are nested within another module or class.
-# In Rails code (e.g. models and controllers) nesting with a colon is preferrable (e.g.
-# User::Session).
-Style/ClassAndModuleChildren:
+# mnicholson Oct. 6th 2021
+# Default lenght for block is 25 lines, which it would be very restrictive for
+# the Rspec views methods. So I'll just exclude some files.
+Metrics/BlockLength:
Exclude:
- - 'app/**/*'
+ - 'lib/tasks/*.rake'
+ - 'lib/tasks/utils/*.rake'
+ - 'spec/**/*'
-# This cop enforces each class to have documentation at the top. That's not always
-# practical or necessary in Rails apps (e.g. the purpose of helpers is self evident).
-Style/Documentation:
- Enabled: false
-
-# Enforce empty methods to be written across two lines, like any normal method would be.
-# This allows for easy modification of the method in future.
-Style/EmptyMethod:
+ AllowedMethods: ['describe', 'context', 'task', 'namespace']
+# ------------
+# - SECURITY -
+# ------------
+Security/IoMethods: # new in 1.22
Enabled: true
- EnforcedStyle: expanded
-
-# Leave the string formatting style as `"some text %{value}" % { value: "text" }`
-# since we're uncertain what effect `format` and `sprintf` may have on the Fastgetext
-# markup `_("text")`
-Style/FormatString:
- EnforcedStyle: percent
-# Prefer the use of `"some %{token} text"` instead of `some %
-[![Alliance](Alliance_logo.jpg)](https://alliancecan.ca)
\ No newline at end of file
+[![Alliance](Alliance_logo.jpg)](https://alliancecan.ca)
diff --git a/README.rdoc b/README.rdoc
deleted file mode 100644
index 8f67343403..0000000000
--- a/README.rdoc
+++ /dev/null
@@ -1,36 +0,0 @@
-= DMPRoadmap
-
-Roadmap is a data management planning tool, available at https://github.com/DMPRoadmap/roadmap
-
-Development of the Roadmap is provided by the Digital Curation Centre and the University of California Curation Center.
-
-The tool has four main functions
-1. To help create and maintain different versions of Data Management Plans;
-2. To provide useful guidance on data management issues and how to meet research funders' requirements;
-3. To export attractive and useful plans in a variety of formats;
-4. To allow collaborative work when creating Data Management Plans.
-
-== Documentation & Support
-
-* You can contact us by email, roadmap-l@listserv.ucop.edu, but we can only provide limited support for your installation
-
-== Bugs & Feature Requests
-
-* Bug Reports & Feature Requests: https://github.com/DMPRoadmap/roadmap/issues
-* Please prefix your request with either: 'Bug:' or 'Feature:'
-
-== Prerequisites
-
-Roadmap 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, http://rubyonrails.org
-
-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/
-
-
-== Copyright
-
-The Roadmap project uses an MIT License. The full text of the license can be found at: https://github.com/DMPRoadmap/roadmap/blob/master/LICENSE.md
diff --git a/Rakefile b/Rakefile
index 700a8a33cf..42f9525d64 100755
--- a/Rakefile
+++ b/Rakefile
@@ -10,7 +10,7 @@
# task default: :test
-require_relative "config/application"
+require_relative 'config/application'
DMPRoadmap::Application.load_tasks
diff --git a/app/assets/images/favicon.ico b/app/assets/images/favicon.ico
index 40ade36c75..4ddb00d5f7 100644
Binary files a/app/assets/images/favicon.ico and b/app/assets/images/favicon.ico differ
diff --git a/app/assets/images/logo.png b/app/assets/images/logo.png
new file mode 100644
index 0000000000..e4cc2dcfcd
Binary files /dev/null and b/app/assets/images/logo.png differ
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 35268bdad4..4e5640a461 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -11,7 +11,7 @@
// Pull in the webapcker managed copy of JQuery-UI Stylesheets
// we are using the Datepicker and Sortable at the very least
-// @import "../../../node_modules/jquery-ui-sass/assets/sass/jquery-ui.scss";
+@import "../../../node_modules/jquery-ui-sass/assets/sass/jquery-ui.scss";
@import "font-awesome-sprockets";
@import "font-awesome";
diff --git a/app/assets/stylesheets/blocks/_modal_search.scss b/app/assets/stylesheets/blocks/_modal_search.scss
new file mode 100644
index 0000000000..75e87c828e
--- /dev/null
+++ b/app/assets/stylesheets/blocks/_modal_search.scss
@@ -0,0 +1,75 @@
+.modal-search-block {
+ border: 1px solid $color-grey;
+ margin-bottom: 10px;
+ padding: 10px 5px;
+}
+
+.modal-search .modal-dialog {
+ /* Make the dialog 80% of the screen height/width */
+ width: 80%;
+ // height: 80%;
+}
+.modal-search .modal-body {
+ /* 100% = dialog height, 50px = header (27.5px) + footer (21px) */
+ // max-height: calc(80% - 50px);
+ max-height: 450px;
+ overflow-y: scroll;
+}
+
+.modal-search-results-pagination {
+ margin-bottom: 10px;
+}
+
+.modal-search-result {
+ margin-top: 5px;
+ padding-bottom: 5px;
+
+ .modal-search-result-label {
+ font-size: 1.6rem;
+ font-weight: 500;
+ }
+
+ .tags > .tag {
+ display: inline-block;
+ margin: 5px 2px;
+ }
+ .tags .facet {
+ border: 1px solid $color-blue;
+ border-radius: 25px;
+ padding: 2px 5px;
+ }
+
+ div {
+ margin-bottom: 5px;
+ }
+
+ dl {
+ margin-left: 20px;
+
+ dd {
+ margin-bottom: 5px;
+ }
+ }
+}
+
+.modal-search-results .modal-search-result {
+ border-bottom: 1px solid $color-grey;
+}
+
+/* the 'Select' button displayed in the modal dialog */
+.modal-search-result .modal-search-result-selector,
+.modal-search-result .modal-search-result-unselector {
+ display: inline-block;
+ background-color: $color-white;
+ border-radius: 25px;
+ padding: 2px 5px;
+ font-size: 1.3rem;
+}
+.modal-search-result .modal-search-result-selector {
+ background-color: $color-green;
+ color: $color-white;
+}
+.modal-search-result .modal-search-result-unselector {
+ border: 1px solid $color-red;
+ color: $color-red;
+}
diff --git a/app/assets/stylesheets/blocks/_question_form.scss b/app/assets/stylesheets/blocks/_question_form.scss
new file mode 100644
index 0000000000..165223aca6
--- /dev/null
+++ b/app/assets/stylesheets/blocks/_question_form.scss
@@ -0,0 +1,35 @@
+.question-body {
+ display: flex;
+ padding: 15px 0;
+ .question-section {
+ flex: 8;
+ position: relative;
+ .toggle-guidance-section {
+ position: absolute;
+ top: 0;
+ right: 0;
+ background-color: $color-portage-blue;
+ color: $color-white;
+ padding: 10px 5px;
+ cursor: pointer;
+
+ text-orientation: mixed;
+ writing-mode: vertical-rl;
+ &.disabled {
+ background-color: $color-muted;
+ cursor: not-allowed;
+ }
+ }
+ .question-form {
+ padding-right: 50px;
+ padding-top: 10px;
+ }
+ }
+
+ .guidance-section {
+ flex: 4;
+ border-left: 5px solid $color-portage-blue;
+ padding-left: 5px;
+ }
+
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/variables/_colours.scss b/app/assets/stylesheets/variables/_colours.scss
index 5ee371630d..d3e9bdec71 100644
--- a/app/assets/stylesheets/variables/_colours.scss
+++ b/app/assets/stylesheets/variables/_colours.scss
@@ -5,6 +5,7 @@
$color-black: #000;
$color-white: #FFF;
$color-red: #b94a48;
+$color-green: #4c8d3f;
$color-grey: #4F5253;
$color-grey-darkest: #222;
$color-grey-darker: #333;
diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb
index fa6ee697da..9aec230539 100644
--- a/app/channels/application_cable/channel.rb
+++ b/app/channels/application_cable/channel.rb
@@ -1,9 +1,6 @@
# frozen_string_literal: true
module ApplicationCable
-
class Channel < ActionCable::Channel::Base
-
end
-
end
diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb
index b08f85080a..8d6c2a1bf4 100644
--- a/app/channels/application_cable/connection.rb
+++ b/app/channels/application_cable/connection.rb
@@ -1,9 +1,6 @@
# frozen_string_literal: true
module ApplicationCable
-
class Connection < ActionCable::Connection::Base
-
end
-
end
diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb
index 48980290bf..83ef83fe6e 100644
--- a/app/controllers/answers_controller.rb
+++ b/app/controllers/answers_controller.rb
@@ -1,7 +1,9 @@
# frozen_string_literal: true
-class AnswersController < ApplicationController
+# 3.1.0: all changes here are 3.1.0 updates. Keep them
+# Controller that handles Answers to DMP questions
+class AnswersController < ApplicationController
respond_to :html
include ConditionsHelper
@@ -12,6 +14,7 @@ class AnswersController < ApplicationController
# `remote: true` in the
The following %{object_types} will be moved over to '%{org_name}':
") % { - object_types: entries.first.class.name.pluralize, - org_name: to_org_name - } + html = format(_("The following %{object_types} will be moved over to '%{org_name}':
"), + object_types: entries.first.class.name.pluralize, org_name: to_org_name) html + column_content(entries: entries, orcid: orcid) end - end - end - end diff --git a/app/helpers/template_helper.rb b/app/helpers/template_helper.rb index e40a27c36b..807e6c4559 100644 --- a/app/helpers/template_helper.rb +++ b/app/helpers/template_helper.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true +# Helper methods for Templates module TemplateHelper - def template_details_path(template) if template_modifiable?(template) edit_org_admin_template_path(template) @@ -22,7 +22,7 @@ def template_modifiable?(template) template.org_id = current_user.org.id end - def links_to_a_elements(links, separator = ", ") + def links_to_a_elements(links, separator = ', ') a = links.map do |l| "#{l['text']}" end @@ -34,34 +34,26 @@ def links_to_a_elements(links, separator = ", ") # @param hidden [Boolean] should the link be hidden? # @param text [String] text for the link # @param id [String] id for the link element - def direct_link(template, hidden = false, text = nil, id = nil, protocol = 'http') + # rubocop:disable Style/OptionalBooleanParameter + # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + def direct_link(template, hidden = false, text = nil, id = nil) params = { org: { id: "{ \"id\": #{current_user&.org&.id}, \"name\": \"#{current_user&.org&.name}\" }" }, funder: { id: "{ \"id\": #{template.org&.id}, \"name\": \"#{template.org&.name}\" }" }, template_id: template.id } - cls = text.nil? ? "direct-link" : "direct-link btn btn-default" - style = hidden ? "display: none" : "" + cls = text.nil? ? 'direct-link' : 'direct-link btn btn-default' + style = hidden ? 'display: none' : '' - link_to(plans_url(plan: params, protocol: protocol), method: :post, title: _("Create plan"), + link_to(plans_url(plan: params), method: :post, title: _('Create plan'), class: cls, id: id, style: style) do if text.nil? - "".html_safe + ''.html_safe else text.html_safe end end end - - def visibility_description(val) - case val - when 'organisationally_visible' - _('Organisation: anyone at my organisation can view.') - when 'publicly_visible' - _('Public: anyone can view.') - else - _('N/A') - end - end - + # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + # rubocop:enable Style/OptionalBooleanParameter end diff --git a/app/helpers/usage_helper.rb b/app/helpers/usage_helper.rb index 673f61dbcb..6748ede7ab 100644 --- a/app/helpers/usage_helper.rb +++ b/app/helpers/usage_helper.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true +# Helper methods for Usage dashboard module UsageHelper - def prep_data_for_yearly_users_chart(data:) default_chart_prep(data: data) end @@ -14,39 +14,39 @@ def prep_data_for_yearly_plans_chart(data:) # for each point on the Y axis (date) so we need to format the information # appropriately by passing along the labels for the Y axis and the datasets # for the X axis - # rubocop:disable Metrics/AbcSize - def prep_data_for_template_plans_chart(data:, subset: "by_template") - last_month = Date.today.last_month.end_of_month.strftime("%b-%y") + # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + def prep_data_for_template_plans_chart(data:, subset: 'by_template') + last_month = Date.today.last_month.end_of_month.strftime('%b-%y') return { labels: [last_month], datasets: [] }.to_json if data.blank? || data.empty? datasets = {} # Sort this chart's date by date desacending data = data.map { |hash| JSON.parse(hash) } - .sort { |a, b| b["date"] <=> a["date"] } + .sort { |a, b| b['date'] <=> a['date'] } # Extract all of the dates as month abbreviation - year (e.g. Dec-19) - labels = data.map { |rec| prep_date_for_charts(date: rec["date"]) } - + labels = data.map { |rec| prep_date_for_charts(date: rec['date']) } # Loop through the data and organize the datasets by template instead of date data.each do |rec| - date = prep_date_for_charts(date: rec["date"]) + date = prep_date_for_charts(date: rec['date']) rec[subset].each do |template| # We need a placeholder for each month/year - template combo. The # default is to assume that there are zero plans for that month/year + template dflt = { - label: template["name"], + label: template['name'], backgroundColor: random_rgb, data: labels.map { |lbl| { x: 0, y: lbl } } } - template_hash = datasets.fetch(template["name"], dflt) + template_hash = datasets.fetch(template['name'], dflt) # Replace any of the month/year plan counts for this template IF it has # any plans defined template_hash[:data] = template_hash[:data].map do |dat| - dat[:y] == date ? { x: template["count"] + dat[:x], y: dat[:y] } : dat + dat[:y] == date ? { x: template['count'] + dat[:x], y: dat[:y] } : dat end - datasets[template["name"]] = template_hash + datasets[template['name']] = template_hash end end @@ -56,33 +56,35 @@ def prep_data_for_template_plans_chart(data:, subset: "by_template") labels: labels }.to_json end - # rubocop:enable Metrics/AbcSize + # rubocop:enable Metrics/AbcSize, Metrics/MethodLength + # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + # rubocop:disable Metrics/AbcSize def plans_per_template_ranges [ - [_("Last month"), Date.today.last_month.end_of_month], - [_("Last 3 months"), Date.today.months_ago(3).end_of_month], - [_("Last 6 months"), Date.today.months_ago(6).end_of_month], - [_("Last 9 months"), Date.today.months_ago(9).end_of_month], - [_("Last 12 months"), Date.today.months_ago(12).end_of_month] + [_('Last month'), Date.today.last_month.end_of_month], + [_('Last 3 months'), Date.today.months_ago(3).end_of_month], + [_('Last 6 months'), Date.today.months_ago(6).end_of_month], + [_('Last 9 months'), Date.today.months_ago(9).end_of_month], + [_('Last 12 months'), Date.today.months_ago(12).end_of_month] ] end + # rubocop:enable Metrics/AbcSize def default_chart_prep(data:) hash = {} data.map { |rec| JSON.parse(rec) }.each do |rec| - date = prep_date_for_charts(date: rec["date"]) - hash[date] = hash.fetch(date, 0) + rec["count"].to_i + date = prep_date_for_charts(date: rec['date']) + hash[date] = hash.fetch(date, 0) + rec['count'].to_i end hash end def prep_date_for_charts(date:) - date.is_a?(Date) ? date.strftime("%b-%y") : Date.parse(date).strftime("%b-%y") + date.is_a?(Date) ? date.strftime('%b-%y') : Date.parse(date).strftime('%b-%y') end def random_rgb "rgb(#{rand(256)},#{rand(256)},#{rand(256)})" end - end diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index 1c83822daa..f61459d552 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -26,6 +26,7 @@ import 'bootstrap-select'; import '../src/utils/accordion'; import '../src/utils/autoComplete'; import '../src/utils/externalLink'; +import '../src/utils/modalSearch'; import '../src/utils/outOfFocus'; import '../src/utils/paginable'; import '../src/utils/panelHeading'; @@ -58,6 +59,7 @@ import '../src/plans/index.js.erb'; import '../src/plans/new'; import '../src/plans/share'; import '../src/publicTemplates/show'; +import '../src/researchOutputs/form'; import '../src/roles/edit'; import '../src/shared/createAccountForm'; import '../src/shared/signInForm'; diff --git a/app/javascript/src/answers/edit.js b/app/javascript/src/answers/edit.js index a0fd8d589a..766ccc9386 100644 --- a/app/javascript/src/answers/edit.js +++ b/app/javascript/src/answers/edit.js @@ -185,4 +185,13 @@ $(() => { } datePicker(); + + // Clicking the 'Comments & Guidance' div should toggle the guidance & comments section + $(document).on('click', '.toggle-guidance-section', (e) => { + const target = $(e.currentTarget); + target.parents('.question-body').find('.guidance-section').toggle(); + target.find('span.fa-chevron-right, span.fa-chevron-left') + .toggleClass('fa-chevron-right') + .toggleClass('fa-chevron-left'); + }); }); diff --git a/app/javascript/src/orgs/adminEdit.js b/app/javascript/src/orgs/adminEdit.js index d26c57ba45..c393c39c27 100644 --- a/app/javascript/src/orgs/adminEdit.js +++ b/app/javascript/src/orgs/adminEdit.js @@ -1,7 +1,5 @@ -// TODO: we need to be able to swap in the appropriate locale here +// TODO: we need to be able to swap in the appropriate locale here import 'number-to-text/converters/en-us'; -// XXX: Check TODO and add way of adding locale change -// import 'number-to-text/converters/fr-ca'; import { isObject } from '../utils/isType'; import { Tinymce } from '../utils/tinymce.js.erb'; import { eachLinks } from '../utils/links'; diff --git a/app/javascript/src/researchOutputs/form.js b/app/javascript/src/researchOutputs/form.js new file mode 100644 index 0000000000..b454b9eb3d --- /dev/null +++ b/app/javascript/src/researchOutputs/form.js @@ -0,0 +1,45 @@ +import getConstant from '../utils/constants'; +import { isUndefined, isObject } from '../utils/isType'; +import { Tinymce } from '../utils/tinymce.js.erb'; + +$(() => { + const form = $('.research_output_form'); + + if (!isUndefined(form) && isObject(form)) { + Tinymce.init({ selector: '#research_output_description' }); + } + + // Expands/Collapses the search results 'More info'/'Less info' section + $('body').on('click', '.modal-search-result .more-info a.more-info-link', (e) => { + e.preventDefault(); + const link = $(e.target); + + if (link.length > 0) { + const info = $(link).siblings('div.info'); + + if (info.length > 0) { + if (info.hasClass('hidden')) { + info.removeClass('hidden'); + link.text(`${getConstant('LESS_INFO')}`); + } else { + info.addClass('hidden'); + link.text(`${getConstant('MORE_INFO')}`); + } + } + } + }); + + // Put the facet text into the modal search window's search box when the user + // clicks on one + $('body').on('click', '.modal-search-result a.facet', (e) => { + const link = $(e.target); + + if (link.length > 0) { + const textField = link.closest('.modal-body').find('input.autocomplete'); + + if (textField.length > 0) { + textField.val(link.text()); + } + } + }); +}); diff --git a/app/javascript/src/utils/links.js b/app/javascript/src/utils/links.js index 900564a51a..b4b8f77721 100644 --- a/app/javascript/src/utils/links.js +++ b/app/javascript/src/utils/links.js @@ -1,4 +1,7 @@ -import writtenNumber from 'written-number'; +// 3.1.0: /* global i18nLocale */... part is confirmed to be removed + +import 'number-to-text/converters/en-us'; +import { convertToText } from 'number-to-text/index'; import { isFunction } from './isType'; const getLinks = (elem) => $(elem).find('.link').map((i, el) => { @@ -88,10 +91,7 @@ $(() => { $('.links').find('.max-number-links').each((i, el) => { const target = $(el); const max = target.closest('.links').attr('data-max-number-links'); - /* global i18nLocale */ - // defined in application.html.erb - const language = i18nLocale.split('-')[0]; - target.text(writtenNumber(max, { lang: language })); + target.text(convertToText(max).toLowerCase()); }); }); diff --git a/app/javascript/src/utils/modalSearch.js b/app/javascript/src/utils/modalSearch.js new file mode 100644 index 0000000000..2bc8bf1888 --- /dev/null +++ b/app/javascript/src/utils/modalSearch.js @@ -0,0 +1,39 @@ +$(() => { + // Add the selected item to the selections section + $('body').on('click', 'a.modal-search-result-selector', (e) => { + e.preventDefault(); + const link = $(e.target); + + if (link.length > 0) { + const selectedBlock = $(e.target).closest('.modal-search-result'); + const resultsBlock = $(e.target).closest('.modal-search-results'); + + if (resultsBlock.length > 0 && selectedBlock.length > 0) { + const selectionsBlockId = resultsBlock.attr('id').replace('-results', '-selections'); + + if (selectionsBlockId !== undefined) { + const selectionsBlock = $(`#${selectionsBlockId}`); + + if (selectionsBlock.length > 0) { + const clone = selectedBlock.clone(); + clone.find('.modal-search-result-selector').addClass('hidden'); + clone.find('.modal-search-result-unselector').removeClass('hidden'); + clone.find('.tags').remove(); + selectionsBlock.append(clone); + selectedBlock.remove(); + } + } + } + } + }); + + // Remove the selected item + $('body').on('click', 'a.modal-search-result-unselector', (e) => { + e.preventDefault(); + const selection = $(e.target).closest('.modal-search-result'); + + if (selection.length > 0) { + selection.remove(); + } + }); +}); diff --git a/app/javascript/src/utils/tinymce.js.erb b/app/javascript/src/utils/tinymce.js.erb index 63c73717a6..cff2bfccca 100644 --- a/app/javascript/src/utils/tinymce.js.erb +++ b/app/javascript/src/utils/tinymce.js.erb @@ -9,8 +9,6 @@ import 'tinymce/plugins/autoresize'; import 'tinymce/plugins/link'; import 'tinymce/plugins/paste'; import 'tinymce/plugins/advlist'; -import 'tinymce-i18n/langs/en_CA'; -import 'tinymce-i18n/langs/fr_FR'; // Other dependencies import { isObject, isString } from './isType'; @@ -31,7 +29,7 @@ export const defaultOptions = { target_list: false, elementpath: false, resize: true, - min_height: 230, + autoresize_min_height: 230, autoresize_bottom_margin: 10, branding: false, extended_valid_elements: 'iframe[tooltip] , a[href|target=_blank]', @@ -48,7 +46,6 @@ export const defaultOptions = { // editorManager.baseURL is not resolved properly for IE since document.currentScript // is not supported, see issue https://github.com/tinymce/tinymce/issues/358 skin_url: '/tinymce/skins/lightgray', - // content_css: '/tinymce/skins/lightgray/content.min.css' content_css: ['/tinymce/tinymce.css'], }; /* @@ -108,9 +105,9 @@ export const Tinymce = { let myDefaultOptions = $.extend(true, {language: tinymceLocale}, defaultOptions) if (isObject(options)) { - tinymce.init($.extend(true, myDefaultOptions, options)).then(resizeEditors); + tinymce.init($.extend(true, defaultOptions, options)).then(resizeEditors); } else { - tinymce.init(myDefaultOptions).then(resizeEditors); + tinymce.init(defaultOptions).then(resizeEditors); } // Connect the label to the Tinymce iframe diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index db81880938..d92ffddcb5 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true class ApplicationJob < ActiveJob::Base - end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index be1df3b698..56267ee547 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true +# Mailer methods for all emails class UserMailer < ActionMailer::Base - - prepend_view_path "app/views/branded/" + prepend_view_path 'app/views/branded/' include MailerHelper helper MailerHelper @@ -10,23 +10,24 @@ class UserMailer < ActionMailer::Base default from: Rails.configuration.x.organisation.email + # rubocop:disable Metrics/AbcSize def welcome_notification(user) @user = user @username = @user.name - @email_subject = _("Query or feedback related to %{tool_name}") % { tool_name: tool_name } + @email_subject = format(_('Query or feedback related to %{tool_name}'), tool_name: tool_name) # Override the default Rails route helper for the contact_us page IF an alternate contact_us # url was defined in the dmproadmap.rb initializer file @contact_us = Rails.application.config.x.organisation.contact_us_url || contact_us_url + @helpdesk_email = helpdesk_email(org: @user.org) I18n.with_locale I18n.default_locale do mail(to: @user.email, - subject: _("Welcome to %{tool_name}") % - { - tool_name: tool_name - }) + subject: format(_('Welcome to %{tool_name}'), tool_name: tool_name)) end end + # rubocop:enable Metrics/AbcSize + # rubocop:disable Metrics/AbcSize def question_answered(data, user, answer, _options_string) @user = user @username = @user.name @@ -35,15 +36,17 @@ def question_answered(data, user, answer, _options_string) @plan_title = @answer.plan.title.to_s @template_title = @answer.plan.template.title.to_s @data = data - @recipient_name = @data["name"].to_s - @message = @data["message"].to_s + @recipient_name = @data['name'].to_s + @message = @data['message'].to_s @answer_text = @options_string.to_s + @helpdesk_email = helpdesk_email(org: @user.org) I18n.with_locale I18n.default_locale do - mail(to: data["email"], - subject: data["subject"]) + mail(to: data['email'], + subject: data['subject']) end end + # rubocop:enable Metrics/AbcSize def sharing_notification(role, user, inviter:) @role = role @@ -51,14 +54,13 @@ def sharing_notification(role, user, inviter:) @user_email = @user.email @username = @user.name @inviter = inviter - @link = url_for(action: "show", controller: "plans", id: @role.plan.id) + @link = url_for(action: 'show', controller: 'plans', id: @role.plan.id) + @helpdesk_email = helpdesk_email(org: @inviter.org) I18n.with_locale I18n.default_locale do mail(to: @role.user.email, - subject: _("A Data Management Plan in %{tool_name} has been shared with you") % - { - tool_name: tool_name - }) + subject: format(_('A Data Management Plan in %{tool_name} has been shared with you'), + tool_name: tool_name)) end end @@ -68,15 +70,14 @@ def permissions_change_notification(role, user) @role = role @plan_title = @role.plan.title @user = user - @username = @user.name - @messaging = role_text(@role) + @recepient = @role.user + @messaging = role_text(@role) + @helpdesk_email = helpdesk_email(org: @user.org) I18n.with_locale I18n.default_locale do - mail(to: @role.user.email, - subject: _("Changed permissions on a Data Management Plan in %{tool_name}") % - { - tool_name: tool_name - }) + mail(to: @recepient.email, + subject: format(_('Changed permissions on a Data Management Plan in %{tool_name}'), + tool_name: tool_name)) end end @@ -86,13 +87,12 @@ def plan_access_removed(user, plan, current_user) @user = user @plan = plan @current_user = current_user + @helpdesk_email = helpdesk_email(org: @plan.org) I18n.with_locale I18n.default_locale do mail(to: @user.email, - subject: _("Permissions removed on a DMP in %{tool_name}") % - { - tool_name: tool_name - }) + subject: format(_('Permissions removed on a DMP in %{tool_name}'), + tool_name: tool_name)) end end @@ -105,16 +105,16 @@ def feedback_notification(recipient, plan, requestor) @recipient_name = @recipient.name(false) @requestor_name = @user.name(false) @plan_name = @plan.title - + @helpdesk_email = helpdesk_email(org: @plan.org) + I18n.with_locale I18n.default_locale do mail(to: @recipient.email, - subject: _("%{user_name} has requested feedback on a %{tool_name} plan") % - { - tool_name: tool_name, user_name: @user.name(false) - }) + subject: format(_('%{user_name} has requested feedback on a %{tool_name} plan'), + tool_name: tool_name, user_name: @user.name(false))) end end + # rubocop:disable Metrics/AbcSize def feedback_complete(recipient, plan, requestor) return unless recipient.active? @@ -124,6 +124,7 @@ def feedback_complete(recipient, plan, requestor) @plan = plan @phase = @plan.phases.first @plan_name = @plan.title + @helpdesk_email = helpdesk_email(org: @plan.org) I18n.with_locale I18n.default_locale do sender = Rails.configuration.x.organisation.do_not_reply_email || @@ -131,12 +132,11 @@ def feedback_complete(recipient, plan, requestor) mail(to: recipient.email, from: sender, - subject: _("%{tool_name}: Expert feedback has been provided for %{plan_title}") % - { - tool_name: tool_name, plan_title: @plan.title - }) + subject: format(_('%{tool_name}: Expert feedback has been provided for %{plan_title}'), + tool_name: tool_name, plan_title: @plan.title)) end end + # rubocop:enable Metrics/AbcSize def plan_visibility(user, plan) return unless user.active? @@ -146,13 +146,11 @@ def plan_visibility(user, plan) @plan = plan @plan_title = @plan.title @plan_visibility = Plan::VISIBILITY_MESSAGE[@plan.visibility.to_sym] + @helpdesk_email = helpdesk_email(org: @plan.org) I18n.with_locale I18n.default_locale do mail(to: @user.email, - subject: _("DMP Visibility Changed: %{plan_title}") % - { - plan_title: @plan.title - }) + subject: format(_('DMP Visibility Changed: %{plan_title}'), plan_title: @plan.title)) end end @@ -176,15 +174,13 @@ def new_comment(commenter, plan, answer) @question_number = @question.number @section_title = @question.section.title @phase_id = @question.section.phase.id - @phase_link = url_for(action: "edit", controller: "plans", id: @plan.id, phase_id: @phase_id) + @phase_link = url_for(action: 'edit', controller: 'plans', id: @plan.id, phase_id: @phase_id) + @helpdesk_email = helpdesk_email(org: @plan.org) I18n.with_locale I18n.default_locale do mail(to: @plan.owner.email, - subject: _("%{tool_name}: A new comment was added to %{plan_title}") % - { - tool_name: tool_name, - plan_title: @plan.title - }) + subject: format(_('%{tool_name}: A new comment was added to %{plan_title}'), + tool_name: tool_name, plan_title: @plan.title)) end end # rubocop:enable Metrics/AbcSize @@ -195,16 +191,16 @@ def admin_privileges(user) @user = user @username = @user.name @ul_list = privileges_list(@user) + @helpdesk_email = helpdesk_email(org: @user.org) I18n.with_locale I18n.default_locale do mail(to: user.email, - subject: _("Administrator privileges granted in %{tool_name}") % - { - tool_name: tool_name - }) + subject: format(_('Administrator privileges granted in %{tool_name}'), + tool_name: tool_name)) end end + # rubocop:disable Metrics/AbcSize def api_credentials(api_client) @api_client = api_client return unless @api_client.contact_email.present? @@ -213,13 +209,12 @@ def api_credentials(api_client) @name = @api_client.contact_name.present? ? @api_client.contact_name : @api_client.contact_email + @helpdesk_email = helpdesk_email(org: @api_client.org) + I18n.with_locale I18n.default_locale do mail(to: @api_client.contact_email, - subject: _("%{tool_name} API changes") % - { - tool_name: tool_name - }) + subject: format(_('%{tool_name} API changes'), tool_name: tool_name)) end end - + # rubocop:enable Metrics/AbcSize end diff --git a/app/models/annotation.rb b/app/models/annotation.rb index 2043e1f0a6..d5799565b4 100644 --- a/app/models/annotation.rb +++ b/app/models/annotation.rb @@ -25,8 +25,8 @@ # fk_rails_... (question_id => questions.id) # +# Object that represents Question level guidance or example answers class Annotation < ApplicationRecord - include VersionableModel ## @@ -85,5 +85,4 @@ def deep_copy(**options) copy.question_id = options.fetch(:question_id, nil) copy end - end diff --git a/app/models/answer.rb b/app/models/answer.rb index c994391b04..d1ff70e9b3 100644 --- a/app/models/answer.rb +++ b/app/models/answer.rb @@ -28,8 +28,8 @@ # fk_rails_... (user_id => users.id) # +# Object that represents an Answer to a Plan question class Answer < ApplicationRecord - # ================ # = Associations = # ================ @@ -42,7 +42,7 @@ class Answer < ApplicationRecord has_many :notes, dependent: :destroy - has_and_belongs_to_many :question_options, join_table: "answers_question_options" + has_and_belongs_to_many :question_options, join_table: 'answers_question_options' has_many :notes @@ -96,7 +96,7 @@ def answered? # If the question is option based then see if any options were selected return question_options.any? if question.question_format.option_based? # Strip out any white space and see if the text is empty - return !text.gsub(%r{?p>}, "").gsub(%r{The Access to Biological Collections Data (ABCD) Schema
", + # "keywords": [ + # "http://vocabularies.unesco.org/thesaurus/concept4011", + # "http://vocabularies.unesco.org/thesaurus/concept230", + # "http://rdamsc.bath.ac.uk/thesaurus/subdomain235", + # "http://vocabularies.unesco.org/thesaurus/concept223", + # "http://vocabularies.unesco.org/thesaurus/concept159", + # "http://vocabularies.unesco.org/thesaurus/concept162", + # "http://vocabularies.unesco.org/thesaurus/concept235" + # ], + # "locations": [ + # { "type": "document", "url": "http://www.tdwg.org/standards/115/" }, + # { "type": "website", "url": "http://wiki.tdwg.org/ABCD" } + # ], + # "mscid": "msc:m1", + # "relatedEntities": [ + # { "id": "msc:m42", "role": "child scheme" }, + # { "id": "msc:m43", "role": "child scheme" }, + # { "id": "msc:m64", "role": "child scheme" }, + # { "id": "msc:c1", "role": "input to mapping" }, + # { "id": "msc:c3", "role": "output from mapping" }, + # { "id": "msc:c14", "role": "output from mapping" }, + # { "id": "msc:c18", "role": "output from mapping" }, + # { "id": "msc:c23", "role": "output from mapping" }, + # { "id": "msc:g11", "role": "user" }, + # { "id": "msc:g44", "role": "user" }, + # { "id": "msc:g45", "role": "user" } + # ], + # "slug": "abcd-access-biological-collection-data", + # "title": "ABCD (Access to Biological Collection Data)", + # "uri": "https://rdamsc.bath.ac.uk/api2/m1" + # } + # ] + # } + # } + def query_schemes(path:) + json = query_api(path: path) + return false unless json.present? + + process_scheme_entries(json: json) + return true unless json.fetch('data', {})['nextLink'].present? + + query_schemes(path: json['data']['nextLink']) + end + + def query_api(path:) + return nil unless path.present? + + # Call the API and log any errors + resp = http_get(uri: "#{api_base_url}#{path}", additional_headers: {}, debug: false) + unless resp.present? && resp.code == 200 + handle_http_failure(method: "RDAMSC API query - path: '#{path}' -- ", http_response: resp) + return nil + end + + JSON.parse(resp.body) + rescue JSON::ParserError => e + log_error(method: "RDAMSC API query - path: '#{path}' -- ", error: e) + nil + end + + # rubocop:disable Metrics/AbcSize + def process_scheme_entries(json:) + return false unless json.is_a?(Hash) + + json = json.with_indifferent_access + return false unless json['data'].present? && json['data'].fetch('items', []).any? + + json['data']['items'].each do |item| + standard = MetadataStandard.find_or_create_by(uri: item['uri'], title: item['title']) + standard.update(description: item['description'], locations: item['locations'], + related_entities: item['relatedEntities'], rdamsc_id: item['mscid']) + end + end + # rubocop:enable Metrics/AbcSize + end + end +end diff --git a/app/services/external_apis/re3data_service.rb b/app/services/external_apis/re3data_service.rb new file mode 100644 index 0000000000..35337e4e70 --- /dev/null +++ b/app/services/external_apis/re3data_service.rb @@ -0,0 +1,153 @@ +# frozen_string_literal: true + +module ExternalApis + # This service provides an interface to the Registry of Research Data + # Repositories (re3data.org) API. + # For more information: https://www.re3data.org/api/doc + class Re3dataService < BaseService + class << self + # Retrieve the config settings from the initializer + def landing_page_url + Rails.configuration.x.re3data&.landing_page_url || super + end + + def api_base_url + Rails.configuration.x.re3data&.api_base_url || super + end + + def max_pages + Rails.configuration.x.re3data&.max_pages || super + end + + def max_results_per_page + Rails.configuration.x.re3data&.max_results_per_page || super + end + + def max_redirects + Rails.configuration.x.re3data&.max_redirects || super + end + + def active? + Rails.configuration.x.re3data&.active || super + end + + def list_path + Rails.configuration.x.re3data&.list_path + end + + def repository_path + Rails.configuration.x.re3data&.repository_path + end + + # Retrieves the full list of repositories from the re3data API as XML. + # For example: + #<%= _("Welcome to %{application_name}") % {application_name: ApplicationService.application_name} %>, <%= @email %>!
+<% I18n.with_locale I18n.default_locale do %> +<%= _("Welcome to %{application_name}") % {application_name: ApplicationService.application_name} %>, <%= @email %>!
-<%= _("Thank you for registering. Please confirm your email address") %>:
+<%= _("Thank you for registering. Please confirm your email address") %>:
-<%= link_to _("Click here to confirm your account"), confirmation_url(@resource, :confirmation_token => @token) %> (<%= _("or copy") %> <%= confirmation_url(@resource, :confirmation_token => @token) %> <%= _("into your browser") %>).
+<%= link_to _("Click here to confirm your account"), confirmation_url(@resource, :confirmation_token => @token) %> (<%= _("or copy") %> <%= confirmation_url(@resource, :confirmation_token => @token) %> <%= _("into your browser") %>).
+<% end %> diff --git a/app/views/devise/mailer/invitation_instructions.html.erb b/app/views/devise/mailer/invitation_instructions.html.erb index 874fd9bc9d..1e1af1af3e 100644 --- a/app/views/devise/mailer/invitation_instructions.html.erb +++ b/app/views/devise/mailer/invitation_instructions.html.erb @@ -1,14 +1,21 @@ <% tool_name = ApplicationService.application_name link = accept_invitation_url(@resource, :invitation_token => @token) - helpdesk_email = Rails.configuration.x.organisation.helpdesk_email contact_us = (Rails.configuration.x.organisation.contact_us_url || contact_us_url) email_subject = _('Query or feedback related to %{tool_name}') %{ :tool_name => tool_name } user_name = User.find_by(email: @resource.email).nil? ? @resource.email : User.find_by(email: @resource.email).name(false) - inviter_name = @resource.invited_by.name + inviter = @resource.invited_by + inviter_name = inviter.name + helpdesk_email = inviter.org&.helpdesk_email || + Rails.configuration.x.organisation.helpdesk_email %> +<% I18n.with_locale I18n.default_locale do %> ++ + +
- <%= _('Hello %{user_name}') %{ :user_name => user_name } %> + <%= _("Hello %{user_name}") %{ :user_name => user_name } %>
<%= _("Your colleague %{inviter_name} has invited you to contribute to "\ @@ -28,9 +35,11 @@ <%= _('The %{tool_name} team') %{:tool_name => tool_name} %>
+ <%= _('Please do not reply to this email.') %> <%= sanitize(_('If you have any questions or need help, please contact us at %{helpdesk_email} or visit %{contact_us_url}') % { helpdesk_email: mail_to(helpdesk_email, helpdesk_email, subject: email_subject), contact_us_url: link_to(contact_us, contact_us) }) %>
+<% end %> diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb index a35b4811c7..b5c41e5b85 100644 --- a/app/views/devise/mailer/reset_password_instructions.html.erb +++ b/app/views/devise/mailer/reset_password_instructions.html.erb @@ -3,21 +3,25 @@ helpdesk_email = Rails.configuration.x.organisation.helpdesk_email contact_us = Rails.configuration.x.organisation.contact_us_url || contact_us_url email_subject = _('Query or feedback related to %{tool_name}') %{ :tool_name => tool_name } + user = User.find_by(email: @resource.email) + helpdesk_email = user.org&.helpdesk_email || + Rails.configuration.x.organisation.helpdesk_email %> - -- <%= _('Hello %{user_email}') %{ :user_email => @resource.email } %> -
-- <%= _('Someone has requested a link to change your %{tool_name} password. You can do this through the link below.') %{ :tool_name => tool_name } %> -
-<%= link_to _('Change my password'), edit_password_url(@resource, :reset_password_token => @token) %>
-<%= _("If you didn't request this, please ignore this email.") %>
-
- <%= _('All the best') %>
-
- <%= _('The %{tool_name} team') %{:tool_name => tool_name} %>
-
- <%= sanitize(_('If you have any questions or need help, please contact us at %{helpdesk_email} or visit %{contact_us}') %{ :helpdesk_email => mail_to(helpdesk_email, helpdesk_email, subject: email_subject), :contact_us => link_to(contact_us, contact_us) }) %> -
+<% I18n.with_locale I18n.default_locale do %> ++ <%= _('Hello %{user_email}') %{ :user_email => @resource.email } %> +
++ <%= _('Someone has requested a link to change your %{tool_name} password. You can do this through the link below.') %{ :tool_name => tool_name } %> +
+<%= link_to _('Change my password'), edit_password_url(@resource, :reset_password_token => @token) %>
+<%= _("If you didn't request this, please ignore this email.") %>
+
+ <%= _('All the best') %>
+
+ <%= _('The %{tool_name} team') %{:tool_name => tool_name} %>
+
+ <%= _('Please do not reply to this email.') %> <%= sanitize(_('If you have any questions or need help, please contact us at %{helpdesk_email} or visit %{contact_us}') %{ :helpdesk_email => mail_to(helpdesk_email, helpdesk_email, subject: email_subject), :contact_us => link_to(contact_us, contact_us) }) %> +
+<% end %> diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb index a7d19a5569..d536f0d174 100644 --- a/app/views/devise/mailer/unlock_instructions.html.erb +++ b/app/views/devise/mailer/unlock_instructions.html.erb @@ -1,9 +1,9 @@ +<% I18n.with_locale I18n.default_locale do %> +<%= _("Hello") %> <%= @resource.email %>!
-<%= _("Hello") %> <%= @resource.email %>!
+<%= _("Your") %> <%= link_to ApplicationService.application_name, root_url %> <%= _("account has been locked due to an excessive number of unsuccessful sign in attempts.") %>
-<%= _("Your") %> <%= link_to ApplicationService.application_name, root_url %> <%= _("account has been locked due to an excessive number of unsuccessful sign in attempts.") %>
- -<%= _("Click the link below to unlock your account") %>:
- -<%= link_to _("Unlock my account"), unlock_url(@resource, :unlock_token => @token) %>
+<%= _("Click the link below to unlock your account") %>:
+<%= link_to _("Unlock my account"), unlock_url(@resource, :unlock_token => @token) %>
+<% end %> diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb index a1db6c29f8..b658a735bd 100644 --- a/app/views/devise/passwords/edit.html.erb +++ b/app/views/devise/passwords/edit.html.erb @@ -11,19 +11,19 @@ <%= devise_error_messages! %> <%= f.hidden_field :reset_password_token %> -<%= _("There is no organisational guidance related to the themes associated with this question.") %>
<% end %>