setup logic to group assign all team members and handle the unassignments logic

This commit is contained in:
zmagoD 2021-06-27 13:22:19 +02:00
parent a678f07b47
commit 9c812e84bd
12 changed files with 196 additions and 12 deletions

View file

@ -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');

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -6,15 +6,31 @@
</div>
<%= bootstrap_form_for @project, url: project_path(@project ,format: :json), method: :put, remote: true do |f| %>
<div class="modal-body">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<%= f.text_field :name, label: t("projects.index.modal_new_project.name"), autofocus: true, placeholder: t("projects.index.modal_new_project.name_placeholder") %>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<%= f.text_field :name, label: t("projects.index.modal_new_project.name"), autofocus: true, placeholder: t("projects.index.modal_new_project.name_placeholder") %>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div class="checkbox">
<%= f.check_box :visibility,
{ label: t('projects.index.modal_new_project.visibility_html'),
data: { action: 'toggle-visibility', target: 'role_select_wrapper' },
checked: f.object.visible? },
:visible,
:hidden %>
</div>
</div>
<%= f.enum_btn_group :visibility, label: t("projects.index.modal_new_project.visibility"), btn_names: { hidden: t("projects.index.modal_new_project.visibility_hidden"), visible: t("projects.index.modal_new_project.visibility_visible") } %>
</div>
<div class="row <%= f.object.hidden? ? 'hidden' : '' %>" id="role_select_wrapper">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<%= f.select :group_user_role_id,
options_for_select(user_roles_collection, selected: f.object.group_user_role_id),
{ label: t('user_assignment.select_default_user_role') },
class: 'form-control selectpicker'%>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal"><%=t "general.cancel" %></button>

View file

@ -13,7 +13,24 @@
<%= f.text_field :name, label: t('projects.index.modal_new_project.name'), placeholder: t('projects.index.modal_new_project.name_placeholder') %>
</div>
</div>
<%= f.enum_btn_group :visibility, label: t('projects.index.modal_new_project.visibility'), btn_names: { hidden: t('projects.index.modal_new_project.visibility_hidden'), visible: t('projects.index.modal_new_project.visibility_visible') } %>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div class="checkbox">
<%= f.check_box :visibility,
{ label: t('projects.index.modal_new_project.visibility_html'), data: { action: 'toggle-visibility', target: 'role_select_wrapper' } },
:visible,
:hidden %>
</div>
</div>
</div>
<div class="row hidden" id="role_select_wrapper">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<%= f.select :group_user_role_id,
options_for_select(user_roles_collection),
{ label: t('user_assignment.select_default_user_role') },
class: 'form-control selectpicker'%>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal"><%= t('general.cancel') %></button>

View file

@ -410,7 +410,7 @@ en:
name: "Project name"
name_placeholder: "My project"
team: "Team"
visibility: "Visible to:"
visibility_html: "Make this project visible to all team members <br /> <small class='text-muted'>This will assign all team members to the project with the default role you choose</small>"
visibility_hidden: "Project members only"
visibility_visible: "All team members"
modal_edit_project:
@ -2344,6 +2344,7 @@ en:
user_assignment:
current_assignee: "(you)"
change_project_role: "Change project role"
select_default_user_role: "Select default user role"
change_experiment_role: "Change experiment role"
change_my_module_role: "Change task role"
select_role: "Select role"

View file

@ -0,0 +1,5 @@
class AddGroupUserRoleToProjects < ActiveRecord::Migration[6.1]
def change
add_reference :projects, :group_user_role, foreign_key: { to_table: :user_roles }
end
end

View file

@ -1079,7 +1079,8 @@ CREATE TABLE public.projects (
experiments_order character varying,
template boolean,
demo boolean DEFAULT false NOT NULL,
project_folder_id bigint
project_folder_id bigint,
group_user_role_id bigint
);
@ -4699,6 +4700,13 @@ CREATE INDEX index_projects_on_archived_by_id ON public.projects USING btree (ar
CREATE INDEX index_projects_on_created_by_id ON public.projects USING btree (created_by_id);
--
-- Name: index_projects_on_group_user_role_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_projects_on_group_user_role_id ON public.projects USING btree (group_user_role_id);
--
-- Name: index_projects_on_last_modified_by_id; Type: INDEX; Schema: public; Owner: -
--
@ -6315,6 +6323,14 @@ ALTER TABLE ONLY public.repository_rows
ADD CONSTRAINT fk_rails_7186e2b731 FOREIGN KEY (last_modified_by_id) REFERENCES public.users(id);
--
-- Name: projects fk_rails_73110d691c; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.projects
ADD CONSTRAINT fk_rails_73110d691c FOREIGN KEY (group_user_role_id) REFERENCES public.user_roles(id);
--
-- Name: oauth_access_tokens fk_rails_732cb83ab7; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@ -7343,6 +7359,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20210217114042'),
('20210222123823'),
('20210410100006'),
('20210612070220');
('20210612070220'),
('20210627095718');