mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-10-02 01:45:38 +08:00
setup logic to group assign all team members and handle the unassignments logic
This commit is contained in:
parent
a678f07b47
commit
9c812e84bd
12 changed files with 196 additions and 12 deletions
|
@ -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');
|
||||
|
|
|
@ -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
|
||||
|
|
31
app/jobs/user_assignments/group_assignment_job.rb
Normal file
31
app/jobs/user_assignments/group_assignment_job.rb
Normal 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
|
26
app/jobs/user_assignments/group_un_assignment_job.rb
Normal file
26
app/jobs/user_assignments/group_un_assignment_job.rb
Normal 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
|
16
app/jobs/user_assignments/remove_user_assignment_job.rb
Normal file
16
app/jobs/user_assignments/remove_user_assignment_job.rb
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
|
@ -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');
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue