Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Changelog

- Redesigned plan-creation page to enforce template access rules and simplify UI [#3534](https://github.com/DMPRoadmap/roadmap/issues/3534)

## v5.0.2
- Bump Ruby to v3.1.4 and use `.ruby-version` in CI
- [#3566](https://github.com/DMPRoadmap/roadmap/pull/3566)
Expand Down
52 changes: 43 additions & 9 deletions app/assets/stylesheets/blocks/_forms.scss
Original file line number Diff line number Diff line change
@@ -1,21 +1,55 @@
@use '../variables/colours' as *;

.form-control {
border: 0px;
}

.form-control input, .form-control textarea, .form-control select{
border: 2px solid $color-border-light;

.form-control input,
.form-control textarea,
.form-control select {
border: 2px solid $color-border-light;
}

.form-check {
padding-left: 0rem;
padding-left: 0rem;
}

.form-inline{
margin-bottom: 5px;
.form-inline {
margin-bottom: 5px;
}

.form-check-label {
padding-left: 5px;
padding-left: 5px;
}

// Added for new plan create page app/views/plans/new.html.erb
.roadmap-form {
margin-bottom: 1rem;

legend {
padding-inline: 2px;
float: none;
width: auto;
padding: 0.5rem;
font-size: 1rem;
background-color: $color-primary-background;
color: $color-primary-text;
}

fieldset {
border: 2px solid #555555;
padding: 1rem;
margin-bottom: 1rem;
}

.form-row {
margin-bottom: 1rem;
}

.form-row:last-child {
margin-bottom: 0;
}

.form-check .form-check-input {
float: left;
margin-left: 0.5rem;
}
}
93 changes: 74 additions & 19 deletions app/controllers/plans_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,15 @@ def index
# rubocop:enable Metrics/AbcSize

# GET /plans/new
# rubocop:disable Metrics/AbcSize
def new
@plan = Plan.new
authorize @plan
org_id = current_user.org&.id

# Get all of the available funders and non-funder orgs
@funders = Org.funder
.includes(identifiers: :identifier_scheme)
.joins(:templates)
.where(templates: { published: true }).uniq.sort_by(&:name)
@orgs = (Org.includes(identifiers: :identifier_scheme).organisation +
Org.includes(identifiers: :identifier_scheme).institution +
Org.includes(identifiers: :identifier_scheme).default_orgs)
@orgs = @orgs.flatten.uniq.sort_by(&:name)

@plan.org_id = current_user.org&.id

# TODO: is this still used? We cannot switch this to use the :plan_params
# strong params because any calls that do not include `plan` in the
# query string will fail
flash[:notice] = "#{_('This is a')} <strong>#{_('test plan')}</strong>" if params.key?(:test)
@is_test = params[:test] ||= false
# Get templates grouped hash
@templates_grouped = templates_available_to_org_user(org_id)
respond_to :html
end
# rubocop:enable Metrics/AbcSize

# POST /plans
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
Expand All @@ -71,6 +55,15 @@ def create
format.html { redirect_to new_plan_path }
end
else
template_id = plan_params[:template_id].to_i
unless validate_template_available_to_org_user?(template_id, current_user.org_id)
respond_to do |format|
flash[:alert] = _('The selected template is not available to your organisation.')
format.html { redirect_to new_plan_path }
end
return
end

@plan.visibility = if plan_params['visibility'].blank?
Rails.configuration.x.plans.default_visibility
else
Expand Down Expand Up @@ -537,5 +530,67 @@ def render_phases_edit(plan, phase, guidance_groups)
guidance_presenter: GuidancePresenter.new(plan)
})
end

# Get templates available to org users
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def templates_available_to_org_user(org_id)
# looks into the list of families of templates
customizations = Template.latest_customized_version_per_org(org_id)
customization_ids = customizations.select(&:published?).collect(&:customization_of)

# get templates of user's own org
user_org_own_templates = Template.organisationally_visible
.where(org_id: org_id, customization_of: nil)
.published
.uniq.sort_by(&:title)

# get templates of user's customised org
user_org_custom_templates = Template.latest_customized_version_per_org(org_id)
.published
.uniq.sort_by(&:title)

# get funder templates no customised templates
funder_non_customised_templates = Template.published
.joins(:org)
.where(orgs: { org_type: Org.org_type_values_for(:funder) })
# The next line removes templates that belong to a family that
# has customised templates
.where.not(family_id: customization_ids)
.uniq.sort_by(&:title)

# get global templates
global_templates = Template.published
.where(is_default: true)
# The next line removes templates that belong to a family that
# has customised templates
.where.not(family_id: customization_ids)
.uniq.sort_by(&:title)

# create templates-grouped hash
@templates_grouped = {
_("Your Organisation's Templates:") => user_org_own_templates.map do |t|
[t.title, t.id]
end,
_("Your Organisation's Customised Templates:") => user_org_custom_templates.map do |t|
[t.title, t.id]
end,
_('Global Templates:') => global_templates.map do |t|
[t.title, t.id]
end,
_('Funder Templates:') => funder_non_customised_templates.map do |t|
[t.title, t.id]
end
}.reject { |_, val| val.empty? }
end
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

# Validate that a template_id is available to the org user
def validate_template_available_to_org_user?(template_id, org_id)
return false if template_id.blank? || org_id.blank?

available_templates = templates_available_to_org_user(org_id)
available_template_ids = available_templates.values.flat_map { |group| group.map(&:last) }
available_template_ids.include?(template_id.to_i)
end
end
# rubocop:enable Metrics/ClassLength
Loading