Skip to content
Merged
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
6 changes: 5 additions & 1 deletion apps/dashboard/app/assets/stylesheets/projects.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.vertical-align-middle {
vertical-align: middle !important;
}

.project-card {
width: fit-content;
}
Expand Down Expand Up @@ -66,4 +70,4 @@
width: 100%;
margin: .2rem 0px;
text-wrap:nowrap;
}
}
2 changes: 1 addition & 1 deletion apps/dashboard/app/controllers/projects_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ def templates
def project_params
params
.require(:project)
.permit(:name, :directory, :description, :icon, :id, :template)
.permit(:name, :directory, :description, :icon, :id, :template, :group_owner)
end

def show_project_params
Expand Down
40 changes: 36 additions & 4 deletions apps/dashboard/app/models/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def importable_directories
end
end

attr_reader :id, :name, :description, :icon, :directory, :template, :files
attr_reader :id, :name, :description, :icon, :directory, :template, :files, :group_owner

validates :name, presence: { message: :required }, on: [:create, :update]
validates :id, :directory, :icon, presence: { message: :required }, on: [:update]
Expand All @@ -128,6 +128,7 @@ def initialize(attributes = {})
@directory = attributes[:directory]
@directory = File.expand_path(@directory) unless @directory.blank?
@template = attributes[:template]
@group_owner = attributes[:group_owner] || directory_group_owner

return if new_record?

Expand Down Expand Up @@ -160,7 +161,7 @@ def save
@directory = Project.dataroot.join(id.to_s).to_s if directory.blank?
@icon = 'fas://cog' if icon.blank?

make_dir && update_permission && sync_template && store_manifest(:save)
make_root && update_permission && make_dir && sync_template && store_manifest(:save)
end

def update(attributes)
Expand Down Expand Up @@ -203,6 +204,30 @@ def remove_from_lookup
false
end

def private?
project_dataroot.to_s.start_with?(CurrentUser.home)
end

def directory_group_owner
if project_dataroot != Project.dataroot && project_dataroot.grpowned?
Etc.getgrgid(project_dataroot.stat.gid).name
else
nil
end
end

def chgrp_directory
return true if private? || group_owner == directory_group_owner
Copy link
Contributor Author

@Bubballoo3 Bubballoo3 Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

End users should not be allowed to chgrp on a directory in their HOME, that will just lead to confusion and errors.

I already thought of this and covered that case here. While some client-side js might make this more clear to the end user, we at least keep them safe from actually doing it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea I think we should just reinforce it for the end user - or we'll get questions about why the value they supply does nothing.


begin
group_gid = group_owner.nil? ? nil : Etc.getgrnam(group_owner).gid
FileUtils.chown(nil, group_gid, project_dataroot)
rescue StandardError => e
errors.add(:save, "Unable to set group with error #{e.class}:#{e.message}")
false
end
end

def editable?
File.writable?(manifest_path)
end
Expand Down Expand Up @@ -303,8 +328,15 @@ def update_attrs(attributes)
end
end

def make_root
project_dataroot.mkpath unless project_dataroot.exist?
true
rescue StandardError => e
errors.add(:save, "Failed to initialize project directory: #{e.message}")
false
end

def make_dir
project_dataroot.mkpath unless project_dataroot.exist?
configuration_directory.mkpath unless configuration_directory.exist?
workflow_directory = Workflow.workflow_dir(project_dataroot)
workflow_directory.mkpath unless workflow_directory.exist?
Expand All @@ -318,7 +350,7 @@ def make_dir

def update_permission
project_dataroot.chmod(0750)
true
chgrp_directory
rescue StandardError => e
errors.add(:save, "Failed to update permissions of the directory: #{e.message}")
false
Expand Down
16 changes: 16 additions & 0 deletions apps/dashboard/app/views/projects/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,22 @@
<div class="field">
<%= form.text_area :description, placeholder: I18n.t('dashboard.jobs_project_description_placeholder') %>
</div>
<% unless @project.private? && edit_project_action %>
<div class="field">
<% help_html =
if edit_project_action
''
else
"<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>"
end
%>
<%= form.select(:group_owner,
CurrentUser.group_names,
{ label: "#{I18n.t('dashboard.jobs_project_group_owner')} #{help_html}".html_safe },
{ disabled: edit_project_action })
%>
</div>
<% end %>
</div>
</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions apps/dashboard/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ en:
jobs_project_directory_error: Project directory path is not set for this workflow
jobs_project_directory_placeholder: Project directory absolute path
jobs_project_generic_error: 'There was an error processing your request: %{error}'
jobs_project_group_owner: Group
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
jobs_project_invalid_configuration_clusters: An HPC cluster is required. Contact your administrator to add one to the system.
jobs_project_invalid_configuration_scripts: An executable script is required for your project. Upload a script using the file application.
jobs_project_job_deleted: Successfully deleted job %{job_id}
Expand Down