From 0a8ebef095fffc2ad53ab8fd677dc58e38bc0d96 Mon Sep 17 00:00:00 2001
From: Oleksii Kriuchykhin <okriuchykhin@biosistemika.com>
Date: Wed, 5 Oct 2022 18:28:40 +0200
Subject: [PATCH] Update teams table with new user assignments system
 [SCI-7291]

---
 .../users/settings/user_teams_controller.rb   | 11 +++-
 app/datatables/teams_datatable.rb             | 50 +++++++++++--------
 app/models/user_role.rb                       |  6 ++-
 3 files changed, 44 insertions(+), 23 deletions(-)

diff --git a/app/controllers/users/settings/user_teams_controller.rb b/app/controllers/users/settings/user_teams_controller.rb
index 36371e511..ce8d6d1c0 100644
--- a/app/controllers/users/settings/user_teams_controller.rb
+++ b/app/controllers/users/settings/user_teams_controller.rb
@@ -6,7 +6,8 @@ module Users
       include UserRolesHelper
 
       before_action :load_user_assignment, only: %i(update leave_html destroy_html destroy)
-      before_action :check_manage_permissions
+      before_action :check_manage_permissions, except: %i(leave_html destroy_html destroy)
+      before_action :check_destroy_permissions, only: %i(leave_html destroy_html destroy)
 
       def update
         respond_to do |format|
@@ -164,6 +165,14 @@ module Users
         render_403 unless can_manage_team_users?(@user_assignment.assignable)
       end
 
+      def check_destroy_permissions
+        if params[:leave]
+          render_403 unless @user_assignment.user == current_user
+        else
+          render_403 unless can_manage_team_users?(@user_assignment.assignable)
+        end
+      end
+
       def update_params
         params.require(:user_assignment).permit(:user_role_id)
       end
diff --git a/app/datatables/teams_datatable.rb b/app/datatables/teams_datatable.rb
index 312f8624e..6614b231a 100644
--- a/app/datatables/teams_datatable.rb
+++ b/app/datatables/teams_datatable.rb
@@ -15,7 +15,7 @@ class TeamsDatatable < CustomDatatable
   def sortable_columns
     @sortable_columns ||= [
       'Team.name',
-      'UserTeam.role',
+      'UserRole.name',
       MEMEBERS_SORT_COL
     ]
   end
@@ -27,16 +27,16 @@ class TeamsDatatable < CustomDatatable
     records.map do |record|
       {
         'DT_RowId': record.id,
-        '0': if record.admin?
-               link_to(escape_input(record.team.name), team_path(record.team))
+        '0': if current_user_team_role(record)&.owner?
+               link_to(escape_input(record.name), team_path(record))
              else
-               escape_input(record.team.name)
+               escape_input(record.name)
              end,
-        '1': escape_input(record.role_str),
-        '2': if record.guest?
+        '1': escape_input(current_user_team_role(record)&.name),
+        '2': if current_user_team_role(record)&.viewer?
                I18n.t('users.settings.teams.index.na')
              else
-               record.team.users.count
+               record.users.count
              end,
         '3': leave_team_button(record)
       }
@@ -57,15 +57,16 @@ class TeamsDatatable < CustomDatatable
   # which is calculated in code and not present in DB
   def sort_records(records)
     if sort_column(order_params) == MEMEBERS_SORT_COL
-      records = records.sort_by(&proc { |ut| ut.team.users.count })
+      records = records.sort_by(&proc { |team| team.users.count })
       if order_params['dir'] == 'asc'
-        return records
+        records
       elsif order_params['dir'] == 'desc'
-        return records.reverse
+        records.reverse
       end
-    elsif sort_column(order_params) == 'user_teams.role'
-      records_with_role = records.where(user: @user).order(role: :asc)
-      records_with_no_role = records.where.not(user: @user)
+    elsif sort_column(order_params) == 'user_roles.name'
+      records_with_role = records.where(user_assignments: { user: @user })
+                                 .sort_by(&proc { |team| current_user_team_role(team)&.name })
+      records_with_no_role = records.where.not(user_assignments: { user: @user })
       records = records_with_no_role + records_with_role
       if order_params['dir'] == 'asc'
         records
@@ -79,20 +80,20 @@ class TeamsDatatable < CustomDatatable
 
   # If user is last admin of team, don't allow
   # him/her to leave team
-  def leave_team_button(user_team)
+  def leave_team_button(record)
     button = "<span class=\"fas fa-sign-out-alt\"></span>
               <span class=\"hidden-xs\">
                 #{I18n.t('users.settings.teams.index.leave')}
               </span>"
-    team = user_team.team
-    if user_team.admin? && team.user_teams.where(role: 2).count <= 1
+    owner_role = UserRole.find_by(name: UserRole.public_send('owner_role').name)
+    if current_user_team_role(record)&.owner? && record.user_assignments.where(user_role: owner_role).none?
       button.prepend('<div class="btn btn-default btn-xs"
                       type="button" disabled="disabled">')
       button << '</div>'
     else
       button = link_to(
         button.html_safe,
-        leave_user_team_html_path(user_team, format: :json),
+        leave_user_team_html_path(current_user_team_assignment(record), format: :json, leave: true),
         remote: true, class: 'btn btn-default btn-xs', type: 'button',
         data: { action: 'leave-user-team' }
       )
@@ -103,9 +104,16 @@ class TeamsDatatable < CustomDatatable
   # Query database for records (this will be later paginated and filtered)
   # after that "data" function will return json
   def get_raw_records
-    UserTeam
-      .includes(:team)
-      .references(:team)
-      .where(user: @user)
+    @user.teams
+         .preload(user_assignments: %i(user user_role))
+         .distinct
+  end
+
+  def current_user_team_assignment(team)
+    team.user_assignments.find { |ua| ua.user == @user }
+  end
+
+  def current_user_team_role(team)
+    current_user_team_assignment(team)&.user_role
   end
 end
diff --git a/app/models/user_role.rb b/app/models/user_role.rb
index 6974e00e6..8dfb38982 100644
--- a/app/models/user_role.rb
+++ b/app/models/user_role.rb
@@ -50,7 +50,11 @@ class UserRole < ApplicationRecord
   end
 
   def owner?
-    name == I18n.t('user_roles.predefined.owner')
+    predefined? && name == I18n.t('user_roles.predefined.owner')
+  end
+
+  def viewer?
+    predefined? && name == I18n.t('user_roles.predefined.viewer')
   end
 
   private