Skip to content

Commit a63ca81

Browse files
authored
Toggle group ownership on projects (#4792)
* add project attribute for group selection * disable group selection after creation * provide help text to label
1 parent 26898fa commit a63ca81

File tree

5 files changed

+60
-6
lines changed

5 files changed

+60
-6
lines changed

apps/dashboard/app/assets/stylesheets/projects.scss

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
.vertical-align-middle {
2+
vertical-align: middle !important;
3+
}
4+
15
.project-card {
26
width: fit-content;
37
}
@@ -66,4 +70,4 @@
6670
width: 100%;
6771
margin: .2rem 0px;
6872
text-wrap:nowrap;
69-
}
73+
}

apps/dashboard/app/controllers/projects_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ def templates
236236
def project_params
237237
params
238238
.require(:project)
239-
.permit(:name, :directory, :description, :icon, :id, :template)
239+
.permit(:name, :directory, :description, :icon, :id, :template, :group_owner)
240240
end
241241

242242
def show_project_params

apps/dashboard/app/models/project.rb

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def importable_directories
113113
end
114114
end
115115

116-
attr_reader :id, :name, :description, :icon, :directory, :template, :files
116+
attr_reader :id, :name, :description, :icon, :directory, :template, :files, :group_owner
117117

118118
validates :name, presence: { message: :required }, on: [:create, :update]
119119
validates :id, :directory, :icon, presence: { message: :required }, on: [:update]
@@ -130,6 +130,7 @@ def initialize(attributes = {})
130130
@directory = attributes[:directory]
131131
@directory = File.expand_path(@directory) unless @directory.blank?
132132
@template = attributes[:template]
133+
@group_owner = attributes[:group_owner] || directory_group_owner
133134

134135
return if new_record?
135136

@@ -162,7 +163,7 @@ def save
162163
@directory = Project.dataroot.join(id.to_s).to_s if directory.blank?
163164
@icon = 'fas://cog' if icon.blank?
164165

165-
make_dir && update_permission && sync_template && store_manifest(:save)
166+
make_root && update_permission && make_dir && sync_template && store_manifest(:save)
166167
end
167168

168169
def update(attributes)
@@ -205,6 +206,30 @@ def remove_from_lookup
205206
false
206207
end
207208

209+
def private?
210+
project_dataroot.to_s.start_with?(CurrentUser.home)
211+
end
212+
213+
def directory_group_owner
214+
if project_dataroot != Project.dataroot && project_dataroot.grpowned?
215+
Etc.getgrgid(project_dataroot.stat.gid).name
216+
else
217+
nil
218+
end
219+
end
220+
221+
def chgrp_directory
222+
return true if private? || group_owner == directory_group_owner
223+
224+
begin
225+
group_gid = group_owner.nil? ? nil : Etc.getgrnam(group_owner).gid
226+
FileUtils.chown(nil, group_gid, project_dataroot)
227+
rescue StandardError => e
228+
errors.add(:save, "Unable to set group with error #{e.class}:#{e.message}")
229+
false
230+
end
231+
end
232+
208233
def editable?
209234
File.writable?(manifest_path)
210235
end
@@ -305,8 +330,15 @@ def update_attrs(attributes)
305330
end
306331
end
307332

333+
def make_root
334+
project_dataroot.mkpath unless project_dataroot.exist?
335+
true
336+
rescue StandardError => e
337+
errors.add(:save, "Failed to initialize project directory: #{e.message}")
338+
false
339+
end
340+
308341
def make_dir
309-
project_dataroot.mkpath unless project_dataroot.exist?
310342
configuration_directory.mkpath unless configuration_directory.exist?
311343
workflow_directory = Workflow.workflow_dir(project_dataroot)
312344
workflow_directory.mkpath unless workflow_directory.exist?
@@ -320,7 +352,7 @@ def make_dir
320352

321353
def update_permission
322354
project_dataroot.chmod(0750)
323-
true
355+
chgrp_directory
324356
rescue StandardError => e
325357
errors.add(:save, "Failed to update permissions of the directory: #{e.message}")
326358
false

apps/dashboard/app/views/projects/_form.html.erb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,22 @@
5353
<div class="field">
5454
<%= form.text_area :description, placeholder: I18n.t('dashboard.jobs_project_description_placeholder') %>
5555
</div>
56+
<% unless @project.private? && edit_project_action %>
57+
<div class="field">
58+
<% help_html =
59+
if edit_project_action
60+
''
61+
else
62+
"<i class='fa fa-question-circle vertical-align-middle' data-bs-toggle='tooltip' data-bs-placement='right' title='#{I18n.t('dashboard.jobs_project_group_help')}'></i>"
63+
end
64+
%>
65+
<%= form.select(:group_owner,
66+
CurrentUser.group_names,
67+
{ label: "#{I18n.t('dashboard.jobs_project_group_owner')} #{help_html}".html_safe },
68+
{ disabled: edit_project_action })
69+
%>
70+
</div>
71+
<% end %>
5672
</div>
5773
</div>
5874
</div>

apps/dashboard/config/locales/en.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ en:
175175
jobs_project_directory_error: Project directory path is not set for this workflow
176176
jobs_project_directory_placeholder: Project directory absolute path
177177
jobs_project_generic_error: 'There was an error processing your request: %{error}'
178+
jobs_project_group_owner: Group
179+
jobs_project_group_help: Make sure to choose the group that includes all intended collaborators. If this is not a collaborative project, the default group is recommended
178180
jobs_project_invalid_configuration_clusters: An HPC cluster is required. Contact your administrator to add one to the system.
179181
jobs_project_invalid_configuration_scripts: An executable script is required for your project. Upload a script using the file application.
180182
jobs_project_job_deleted: Successfully deleted job %{job_id}

0 commit comments

Comments
 (0)