Skip to content

Commit

Permalink
VULCAN-528: Fix component admin on component cards (#588)
Browse files Browse the repository at this point in the history
* Fixing the logic for ensuring current user has permission on project or component when creating new membership on component level

Signed-off-by: Vanessa Fotso <[email protected]>

* Setup component PoC on component creation & clarify on the UI what the admin name represents

Signed-off-by: Vanessa Fotso <[email protected]>

* Enable editing the component PoC & display the PoC details on the component details

Signed-off-by: Vanessa Fotso <[email protected]>

* Enable selecting the PoC on component creation

Signed-off-by: Vanessa Fotso <[email protected]>

* Updated the poc list on edit to be all component members

Signed-off-by: Vanessa Fotso <[email protected]>

---------

Signed-off-by: Vanessa Fotso <[email protected]>
  • Loading branch information
vanessuniq authored Jul 14, 2023
1 parent 29f7349 commit bea8ab8
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 110 deletions.
10 changes: 8 additions & 2 deletions app/controllers/components_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def show
@component_json = if @effective_permissions
@component.to_json(
methods: %i[histories memberships metadata inherited_memberships available_members rules
reviews]
reviews admins all_users]
)
else
@component.to_json(methods: %i[rules reviews])
Expand All @@ -69,6 +69,8 @@ def create
# save, this makes sure those errors are shown and not overwritten by the
# component validators.
if component.errors.empty? && component.save
component.admin_name = component_create_params[:admin_name].presence || current_user.name
component.admin_email = component_create_params[:admin_email].presence || current_user.email
component.duplicate_reviews_and_history(component_create_params[:id])
component.create_rule_satisfactions if component_create_params[:file]
component.rules_count = component.rules.where(deleted_at: nil).size
Expand Down Expand Up @@ -351,7 +353,7 @@ def set_project
end

def check_permission_to_update_slackchannel
return if component_update_params[:component_metadata_attributes][:data]['Slack Channel ID'].blank?
return if component_update_params[:component_metadata_attributes]&.dig('data')&.dig('Slack Channel ID').blank?

authorize_admin_component
end
Expand All @@ -365,6 +367,8 @@ def component_update_params
:title,
:prefix,
:description,
:admin_name,
:admin_email,
:advanced_fields,
additional_questions_attributes: [:id, :name, :question_type, :_destroy, { options: [] }],
component_metadata_attributes: { data: {} }
Expand All @@ -385,6 +389,8 @@ def component_create_params
:release,
:title,
:description,
:admin_name,
:admin_email,
:file,
:slack_channel_id,
file: {}
Expand Down
17 changes: 7 additions & 10 deletions app/controllers/memberships_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,13 @@ class MembershipsController < ApplicationController

def create
# Ensure the current_user has permissions on the Project or component
current_user_effective_role = if current_user.admin
'admin'
else
Membership.where(
membership_type: membership_create_params[:membership_type],
membership_id: membership_create_params[:membership_id],
user_id: current_user.id
).pick(:role)
end
unless current_user_effective_role == 'admin'
project_or_component = if membership_create_params[:membership_type] == 'Project'
Project.find_by(id: membership_create_params[:membership_id])
else
Component.find_by(id: membership_create_params[:membership_id])
end

unless current_user.admin || current_user.effective_permissions(project_or_component) == 'admin'
raise(
NotAuthorizedError,
"You are not authorized to manage permissions on this #{membership_create_params[:membership_type]}"
Expand Down
6 changes: 4 additions & 2 deletions app/controllers/projects_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def show
# projects that a user has permissions to access
@project.current_user = current_user
@project_json = @project.to_json(
methods: %i[histories memberships metadata components available_components available_members details]
methods: %i[histories memberships metadata components available_components available_members details users]
)
respond_to do |format|
format.html
Expand Down Expand Up @@ -171,7 +171,9 @@ def project_params
end

def check_permission_to_update_slackchannel
authorize_admin_project if project_params[:project_metadata_attributes][:data]['Slack Channel ID'].present?
return if project_params[:project_metadata_attributes]&.dig('data')&.dig('Slack Channel ID').blank?

authorize_admin_project
end

def project_name_changed?(current_project_name, project_params)
Expand Down
182 changes: 88 additions & 94 deletions app/javascript/components/components/ComponentCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,119 +32,113 @@
<b-card-sub-title v-if="component.description" class="my-2">
{{ component.description }}
</b-card-sub-title>
<p>
<p class="mt-4">
<span v-if="component.admin_name">
{{ component.admin_name }}
PoC: {{ component.admin_name }}
{{ component.admin_email ? `(${component.admin_email})` : "" }}
</span>
<em v-else>No Component Admin</em>

<!-- Component actions -->
<span>
<!-- Open component -->
<a :href="`/components/${component.id}`" target="_blank" class="text-body">
<i
v-b-tooltip.hover
class="mdi mdi-open-in-new float-right h5 clickable"
aria-hidden="true"
title="Open Component"
/>
</a>

<!-- Remove component -->
</p>
<!-- Component actions -->
<p>
<!-- Open component -->
<a :href="`/components/${component.id}`" target="_blank" class="text-body">
<i
v-if="actionable && component.id && effectivePermissions == 'admin'"
v-b-tooltip.hover
class="mdi mdi-delete float-right h5 clickable mr-2"
class="mdi mdi-open-in-new float-right h5 clickable"
aria-hidden="true"
title="Remove Component"
@click="showDeleteConfirmation = !showDeleteConfirmation"
title="Open Component"
/>
</a>

<!-- Duplicate component -->
<span v-if="actionable && effectivePermissions == 'admin'" class="float-right mr-2">
<NewComponentModal
:component_to_duplicate="component.id"
:project_id="component.project_id"
:predetermined_prefix="component.prefix"
:predetermined_security_requirements_guide_id="
component.security_requirements_guide_id
"
@projectUpdated="$emit('projectUpdated')"
>
<template #opener>
<i
v-if="component.id"
v-b-tooltip.hover
class="mdi mdi-content-copy h5 clickable"
aria-hidden="true"
title="Duplicate component and create a new version"
/>
</template>
</NewComponentModal>
</span>
<!-- Remove component -->
<i
v-if="actionable && component.id && effectivePermissions == 'admin'"
v-b-tooltip.hover
class="mdi mdi-delete float-right h5 clickable mr-2"
aria-hidden="true"
title="Remove Component"
@click="showDeleteConfirmation = !showDeleteConfirmation"
/>

<!-- Release component -->
<span
v-if="actionable && component.id && effectivePermissions == 'admin'"
class="float-right mr-2"
<!-- Duplicate component -->
<span v-if="actionable && effectivePermissions == 'admin'" class="float-right mr-2">
<NewComponentModal
:component_to_duplicate="component.id"
:project_id="component.project_id"
:predetermined_prefix="component.prefix"
:predetermined_security_requirements_guide_id="component.security_requirements_guide_id"
@projectUpdated="$emit('projectUpdated')"
>
<span v-b-tooltip.hover :title="releaseComponentTooltip">
<template #opener>
<i
:class="releaseComponentClasses"
v-if="component.id"
v-b-tooltip.hover
class="mdi mdi-content-copy h5 clickable"
aria-hidden="true"
@click="confirmComponentRelease"
title="Duplicate component and create a new version"
/>
</span>
</template>
</NewComponentModal>
</span>

<!-- Release component -->
<span
v-if="actionable && component.id && effectivePermissions == 'admin'"
class="float-right mr-2"
>
<span v-b-tooltip.hover :title="releaseComponentTooltip">
<i
:class="releaseComponentClasses"
aria-hidden="true"
@click="confirmComponentRelease"
/>
</span>
</span>

<!-- Export CSV component -->
<i
v-b-tooltip.hover
class="mdi mdi-download h5 float-right mr-2 clickable"
aria-hidden="true"
title="Export Component as CSV"
@click="downloadExport('csv')"
/>
<!-- Export CSV component -->
<i
v-b-tooltip.hover
class="mdi mdi-download h5 float-right mr-2 clickable"
aria-hidden="true"
title="Export Component as CSV"
@click="downloadExport('csv')"
/>

<!-- Export XCCDF component -->
<i
v-b-tooltip.hover
class="xccdf-icon h5 float-right mr-2 clickable"
aria-hidden="true"
title="Export Component as XCCDF"
@click="downloadExport('xccdf')"
/>
<!-- Export XCCDF component -->
<i
v-b-tooltip.hover
class="xccdf-icon h5 float-right mr-2 clickable"
aria-hidden="true"
title="Export Component as XCCDF"
@click="downloadExport('xccdf')"
/>

<!-- Download InSpec Profile -->
<i
v-b-tooltip.hover
class="inspec-icon h5 float-right mr-2 clickable"
aria-hidden="true"
title="Download InSpec Profile"
@click="downloadExport('inspec')"
/>
<!-- Download InSpec Profile -->
<i
v-b-tooltip.hover
class="inspec-icon h5 float-right mr-2 clickable"
aria-hidden="true"
title="Download InSpec Profile"
@click="downloadExport('inspec')"
/>

<!-- Lock all controls in component -->
<span
v-if="actionable && role_gte_to(effectivePermissions, 'reviewer')"
class="float-right mr-2"
>
<LockControlsModal
:component_id="component.id"
@projectUpdated="$emit('projectUpdated')"
>
<template #opener>
<i
v-if="component.id"
v-b-tooltip.hover
class="mdi mdi-lock h5 clickable"
aria-hidden="true"
title="Lock component controls"
/>
</template>
</LockControlsModal>
</span>
<!-- Lock all controls in component -->
<span
v-if="actionable && role_gte_to(effectivePermissions, 'reviewer')"
class="float-right mr-2"
>
<LockControlsModal :component_id="component.id" @projectUpdated="$emit('projectUpdated')">
<template #opener>
<i
v-if="component.id"
v-b-tooltip.hover
class="mdi mdi-lock h5 clickable"
aria-hidden="true"
title="Lock component controls"
/>
</template>
</LockControlsModal>
</span>
</p>
</b-card>
Expand Down
32 changes: 32 additions & 0 deletions app/javascript/components/components/NewComponentModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,25 @@
<b-form-group label="Description">
<b-form-textarea v-model="description" placeholder="" rows="3" />
</b-form-group>
<!-- Select PoC -->
<b-form-group
v-if="project"
label="Select the Point of Contact"
description="If no user selected, the PoC will be set to the user creating the component"
>
<vue-simple-suggest
ref="userSearch"
:list="potentialPocs"
display-attribute="name"
value-attribute="email"
placeholder="Search for eligible PoC..."
:filter-by-query="true"
:min-length="0"
:max-suggestions="0"
:number="0"
@select="setComponentPoc($refs.userSearch.selected)"
/>
</b-form-group>
<!-- Slack Channel ID -->
<b-form-group
label="Slack Channel ID"
Expand Down Expand Up @@ -229,6 +248,9 @@ export default {
displayedSrgs: [],
file: null,
componentKey: 0,
potentialPocs: this.project ? this.project.users : [],
admin_name: "",
admin_email: "",
};
},
computed: {
Expand Down Expand Up @@ -279,6 +301,10 @@ export default {
this.displayedSrgs = [];
this.$refs["AddComponentModal"].show();
},
setComponentPoc: function (user) {
this.admin_email = user.email;
this.admin_name = user.name;
},
fetchData: function (_bvModalEvt) {
axios.get("/srgs").then((response) => {
this.srgs = response.data;
Expand Down Expand Up @@ -395,6 +421,12 @@ export default {
if (this.description) {
formData.append("component[description]", this.description);
}
if (this.admin_name) {
formData.append("component[admin_name]", this.admin_name);
}
if (this.admin_email) {
formData.append("component[admin_email]", this.admin_email);
}
if (this.slackChannelId) {
formData.append("component[slack_channel_id]", this.slackChannelId);
}
Expand Down
12 changes: 11 additions & 1 deletion app/javascript/components/components/ProjectComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,18 @@
<strong>Description: </strong>{{ component.description }}
</p>
</div>
<div>
<p v-linkified class="ml-2 mb-0 mt-2">
<strong>PoC Name: </strong>{{ component.admin_name }}
</p>
</div>
<div>
<p v-linkified class="ml-2 mb-0 mt-2">
<strong>PoC Email: </strong>{{ component.admin_email }}
</p>
</div>
<UpdateComponentDetailsModal
v-if="role_gte_to(effective_permissions, 'author')"
v-if="role_gte_to(effective_permissions, 'admin')"
:component="component"
@componentUpdated="refreshComponent"
/>
Expand Down
Loading

0 comments on commit bea8ab8

Please sign in to comment.