diff --git a/app/assets/javascripts/projects/index.js b/app/assets/javascripts/projects/index.js index 598a970a7..31cd7c216 100644 --- a/app/assets/javascripts/projects/index.js +++ b/app/assets/javascripts/projects/index.js @@ -90,6 +90,8 @@ var ProjectsIndex = (function() { $(projectsWrapper).append($.parseHTML(data.html)); $(newProjectModal).modal('show'); $(newProjectModal).find("input[type='text']").focus(); + // init select picker + $(newProjectModal).find('.selectpicker').selectpicker(); // Remove modal when it gets closed $(newProjectModal).on('hidden.bs.modal', function() { $(newProjectModal).remove(); @@ -383,6 +385,7 @@ var ProjectsIndex = (function() { $.get(url, function(result) { $(editProjectModal).find('.modal-content').html(result.html); $(editProjectModal).modal('show'); + $(editProjectModal).find('.selectpicker').selectpicker(); $(editProjectModal).find('form') .on('ajax:success', function(ev, data) { $(editProjectModal).modal('hide'); diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 084942033..ac9119ab8 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -322,7 +322,12 @@ class ProjectsController < ApplicationController private def project_params - params.require(:project).permit(:name, :team_id, :visibility, :archived, :project_folder_id) + params.require(:project) + .permit( + :name, :team_id, :visibility, + :archived, :project_folder_id, + :group_user_role_id + ) end def view_type_params diff --git a/app/jobs/user_assignments/group_assignment_job.rb b/app/jobs/user_assignments/group_assignment_job.rb new file mode 100644 index 000000000..6ff649045 --- /dev/null +++ b/app/jobs/user_assignments/group_assignment_job.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module UserAssignments + class GroupAssignmentJob < ApplicationJob + queue_as :high_priority + + def perform(team, project, assigned_by) + @team = team + @assigned_by = assigned_by + + ActiveRecord::Base.transaction do + team.users.where.not(id: project.users.pluck(:id)).each do |user| + UserAssignment.create!( + user: user, + assignable: project, + user_role: project.group_user_role, + assigned_by: @assigned_by, + assigned: :automatically + ) + # make sure all related experiments and my modules are assigned + UserAssignments::PropagateAssignmentJob.perform_later( + project, + user, + project.group_user_role, + @assigned_by + ) + end + end + end + end +end diff --git a/app/jobs/user_assignments/group_un_assignment_job.rb b/app/jobs/user_assignments/group_un_assignment_job.rb new file mode 100644 index 000000000..2cf680695 --- /dev/null +++ b/app/jobs/user_assignments/group_un_assignment_job.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module UserAssignments + class GroupUnAssignmentJob < ApplicationJob + queue_as :high_priority + + def perform(project) + ActiveRecord::Base.transaction do + user_assignments = project.user_assignments.where(assigned: :automatically) + users = User.find(user_assignments.pluck(:user_id)) + + remove_users_from_experiments_and_my_modules(project, users) + UserAssignment.where(user: users, assignable: project).destroy_all + end + end + + def remove_users_from_experiments_and_my_modules(project, users) + project.experiments.each do |experiment| + experiment.my_modules.each do |my_module| + UserAssignment.where(user: users, assignable: my_module).destroy_all + end + UserAssignment.where(user: users, assignable: experiment).destroy_all + end + end + end +end diff --git a/app/jobs/user_assignments/remove_user_assignment_job.rb b/app/jobs/user_assignments/remove_user_assignment_job.rb new file mode 100644 index 000000000..85352fe08 --- /dev/null +++ b/app/jobs/user_assignments/remove_user_assignment_job.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module UserAssignments + class RemoveUserAssignmentJob < ApplicationJob + queue_as :high_priority + + def perform(user, team) + ActiveRecord::Base.transaction do + team.projects.each do |project| + UserAssignments::PropagateAssignmentJob.perform_now(project, user, nil, nil, true) + UserAssignment.where(user: user, assignable: project).destroy_all + end + end + end + end +end diff --git a/app/models/project.rb b/app/models/project.rb index b0c7b896d..61dcdcca8 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -15,6 +15,8 @@ class Project < ApplicationRecord validates :visibility, presence: true validates :team, presence: true validate :project_folder_team, if: -> { project_folder.present? } + validate :selected_user_role_validation, if: :bulk_assignment? + before_validation :remove_project_folder, on: :update, if: :archived_changed? belongs_to :created_by, @@ -33,6 +35,10 @@ class Project < ApplicationRecord foreign_key: 'restored_by_id', class_name: 'User', optional: true + belongs_to :group_user_role, + foreign_key: 'group_user_role_id', + class_name: 'UserRole', + optional: true belongs_to :team, inverse_of: :projects, touch: true belongs_to :project_folder, inverse_of: :projects, optional: true, touch: true has_many :user_projects, inverse_of: :project @@ -64,6 +70,8 @@ class Project < ApplicationRecord scope :templates, -> { where(template: true) } after_create :assign_project_ownership + after_create :auto_assign_project_members, if: :visible? + before_update :sync_project_assignments, if: :visibility_changed? def self.visible_from_user_by_name(user, team, name) projects = where(team: team).distinct @@ -374,7 +382,32 @@ class Project < ApplicationRecord UserAssignment.create( user: created_by, assignable: self, + assigned: :manually, # we set this to manually since was the user action to create the project user_role: UserRole.find_by(name: 'Owner') ) end + + def auto_assign_project_members + UserAssignments::GroupAssignmentJob.perform_now( + team, + self, + created_by + ) + end + + def bulk_assignment? + visible? && group_user_role.present? + end + + def selected_user_role_validation + errors.add(:group_user_role_id, :inclusion) unless group_user_role.in?(UserRole.all) + end + + def sync_project_assignments + if visible? + auto_assign_project_members + else + UserAssignments::GroupUnAssignmentJob.perform_now(self) + end + end end diff --git a/app/models/user_team.rb b/app/models/user_team.rb index d6dff8f47..cc337961a 100644 --- a/app/models/user_team.rb +++ b/app/models/user_team.rb @@ -10,6 +10,7 @@ class UserTeam < ApplicationRecord belongs_to :team, inverse_of: :user_teams before_destroy :destroy_associations + after_create :assign_user_to_visible_projects def role_str I18n.t("user_teams.enums.role.#{role}") @@ -24,6 +25,8 @@ class UserTeam < ApplicationRecord up2.destroy end end + # destroy all assignments + UserAssignments::RemoveUserAssignmentJob.perform_now(team, user) end # returns user_teams where the user is in team @@ -77,4 +80,15 @@ class UserTeam < ApplicationRecord super() end + private + + def assign_user_to_visible_projects + team.projects.visible.each do |project| + UserAssignments::GroupAssignmentJob.perform_later( + team, + project, + assigned_by + ) + end + end end diff --git a/app/views/projects/index/modals/_edit_project_contents.html.erb b/app/views/projects/index/modals/_edit_project_contents.html.erb index fbd437f3b..f184e73be 100644 --- a/app/views/projects/index/modals/_edit_project_contents.html.erb +++ b/app/views/projects/index/modals/_edit_project_contents.html.erb @@ -6,15 +6,31 @@ <%= bootstrap_form_for @project, url: project_path(@project ,format: :json), method: :put, remote: true do |f| %>