User add and edit now assign role ids to users.
authorNik Okuntseff <support@anuko.com>
Sun, 11 Mar 2018 16:30:52 +0000 (16:30 +0000)
committerNik Okuntseff <support@anuko.com>
Sun, 11 Mar 2018 16:30:52 +0000 (16:30 +0000)
WEB-INF/lib/ttRoleHelper.class.php
WEB-INF/lib/ttTeamHelper.class.php
WEB-INF/lib/ttUser.class.php
WEB-INF/lib/ttUserHelper.class.php
WEB-INF/templates/footer.tpl
WEB-INF/templates/user_add.tpl
WEB-INF/templates/user_edit.tpl
roles.php
user_add.php
user_edit.php
users.php

index 7e0f5f6..6a4f33b 100644 (file)
@@ -83,7 +83,52 @@ class ttRoleHelper {
     return false;
   }
 
-  // The getRoleID looks up a role by its rank.
+  // The getLegacyRole obtains a legacy role value for a role_id.
+  // This is a temporary function to allow usage of both old and new roles
+  // while new role code is being written and deployed.
+  static function getLegacyRole($role_id) {
+    global $user;
+    $mdb2 = getConnection();
+
+    $sql = "select rank from tt_roles where team_id = $user->team_id and id = $role_id";
+    $res = $mdb2->query($sql);
+
+    if (!is_a($res, 'PEAR_Error')) {
+      $val = $res->fetchRow();
+      if ($val['rank']) {
+        $rank = $val['rank'];
+        if ($rank >= ROLE_MANAGER)
+          return ROLE_MANAGER;
+        else if ($rank >= ROLE_COMANAGER)
+          return ROLE_COMANAGER;
+        else if ($rank >= ROLE_CLIENT)
+          return ROLE_CLIENT;
+        else
+          return ROLE_USER;
+      }
+    }
+    return false;
+  }
+
+  // isClientRole determines if the role is a "client" role.
+  // This simply means the role has no "data_entry" right.
+  static function isClientRole($role_id) {
+    global $user;
+    $mdb2 = getConnection();
+
+    $sql = "select rights from tt_roles where team_id = $user->team_id and id = $role_id";
+    $res = $mdb2->query($sql);
+
+    if (!is_a($res, 'PEAR_Error')) {
+      $val = $res->fetchRow();
+      if ($val['rights']) {
+        return !in_array('data_entry', explode(',', $val['rights']));
+      }
+    }
+    return false;
+  }
+
+  // getRoleByRank looks up a role by its rank.
   static function getRoleByRank($rank) {
     global $user;
     $mdb2 = getConnection();
index 2344fe3..d20f2a2 100644 (file)
@@ -263,17 +263,40 @@ class ttTeamHelper {
     return false;
   }
 
+  // getActiveRolesForUser - returns an array of relevant active roles for user with rank less than self.
+  // "Relevant" means that client roles are filtered out if Client plugin is disabled.
+  static function getActiveRolesForUser()
+  {
+    global $user;
+    $result = array();
+    $mdb2 = getConnection();
+
+    $sql = "select id, name, description, rank, rights from tt_roles where team_id = $user->team_id and rank < $user->rank and status = 1 order by rank";
+    $res = $mdb2->query($sql);
+    $result = array();
+    if (!is_a($res, 'PEAR_Error')) {
+      while ($val = $res->fetchRow()) {
+        $val['is_client'] = in_array('data_entry', explode(',', $val['rights'])) ? 0 : 1; // Clients do not have data entry right.
+        if ($val['is_client'] && !$user->isPluginEnabled('cl'))
+          continue; // Skip adding a client role/
+        $result[] = $val;
+      }
+    }
+    return $result;
+  }
+
   // getActiveRoles - returns an array of active roles for team.
   static function getActiveRoles($team_id)
   {
     $result = array();
     $mdb2 = getConnection();
 
-    $sql = "select id, name, rank, description from tt_roles where team_id = $team_id and status = 1 order by rank";
+    $sql = "select id, name, description, rank, rights from tt_roles where team_id = $team_id and status = 1 order by rank";
     $res = $mdb2->query($sql);
     $result = array();
     if (!is_a($res, 'PEAR_Error')) {
       while ($val = $res->fetchRow()) {
+        $val['is_client'] = in_array('data_entry', explode(',', $val['rights'])) ? 0 : 1; // Clients do not have data entry right.
         $result[] = $val;
       }
     }
index 815eff7..61d8813 100644 (file)
@@ -31,7 +31,9 @@ class ttUser {
   var $name = null;             // User name.
   var $id = null;               // User id.
   var $team_id = null;          // Team id.
-  var $role = null;             // User role (user, client, comanager, manager, admin).
+  var $role = null;             // User role (user, client, comanager, manager, admin). TODO: remove when new roles are done.
+  var $role_id = null;          // Role id.
+  var $rank = null;             // User role rank.
   var $client_id = null;        // Client id for client user role.
   var $behalf_id = null;        // User id, on behalf of whom we are working.
   var $behalf_name = null;      // User name, on behalf of whom we are working.
@@ -70,11 +72,11 @@ class ttUser {
 
     $mdb2 = getConnection();
 
-    $sql = "SELECT u.id, u.login, u.name, u.team_id, u.role, u.client_id, u.email, t.name as team_name, 
+    $sql = "SELECT u.id, u.login, u.name, u.team_id, u.role, u.role_id, r.rank, u.client_id, u.email, t.name as team_name,
       t.currency, t.lang, t.decimal_mark, t.date_format, t.time_format, t.week_start,
       t.tracking_mode, t.project_required, t.task_required, t.record_type,
       t.bcc_email, t.plugins, t.config, t.lock_spec, t.workday_minutes, t.custom_logo
-      FROM tt_users u LEFT JOIN tt_teams t ON (u.team_id = t.id) WHERE ";
+      FROM tt_users u LEFT JOIN tt_teams t ON (u.team_id = t.id) LEFT JOIN tt_roles r on (r.id = u.role_id) WHERE ";
     if ($id)
       $sql .= "u.id = $id";
     else
@@ -93,6 +95,14 @@ class ttUser {
       $this->id = $val['id'];
       $this->team_id = $val['team_id'];
       $this->role = $val['role'];
+      $this->role_id = $val['role_id'];
+      $this->rank = $val['rank'];
+      // Downgrade rank to legacy role, if it is still in use.
+      if ($this->role > 0 && $this->rank > $this->role)
+        $this->rank = $this->role; // TODO: remove after roles revamp.
+      // Upgrade rank from legacy role, for user who does not yet have a role_id.
+      if (!$this->rank && !$this->role_id && $this->role > 0)
+        $this->rank = $this->role; // TODO: remove after roles revamp.
       $this->client_id = $val['client_id'];
       $this->email = $val['email'];
       $this->lang = $val['lang'];
index f88f195..53fd629 100644 (file)
@@ -172,6 +172,10 @@ class ttUserHelper {
         $role = (int) $fields['role'];
         $role_part = ", role = $role";
       }
+      if (isset($fields['role_id'])) {
+        $role_id = (int) $fields['role_id'];
+        $role_id_part = ", role_id = $role_id";
+      }
       if (array_key_exists('client_id', $fields)) // Could be NULL.
         $client_part = ", client_id = ".$mdb2->quote($fields['client_id']);
     }
@@ -189,7 +193,7 @@ class ttUserHelper {
 
     $sql = "update tt_users set login = ".$mdb2->quote($fields['login']).
       "$pass_part, name = ".$mdb2->quote($fields['name']).
-      "$role_part $client_part $rate_part $status_part, email = ".$mdb2->quote($fields['email']).
+      "$role_part $role_id_part $client_part $rate_part $status_part, email = ".$mdb2->quote($fields['email']).
       " where id = $user_id";
     $affected = $mdb2->exec($sql);
     if (is_a($affected, 'PEAR_Error')) return false;
index f9f6081..487d77f 100644 (file)
@@ -12,7 +12,7 @@
       <br>
       <table cellspacing="0" cellpadding="4" width="100%" border="0">
         <tr>
-          <td align="center">&nbsp;Anuko Time Tracker 1.17.36.4049 | Copyright &copy; <a href="https://www.anuko.com/lp/tt_3.htm" target="_blank">Anuko</a> |
+          <td align="center">&nbsp;Anuko Time Tracker 1.17.37.4050 | Copyright &copy; <a href="https://www.anuko.com/lp/tt_3.htm" target="_blank">Anuko</a> |
             <a href="https://www.anuko.com/lp/tt_4.htm" target="_blank">{$i18n.footer.credits}</a> |
             <a href="https://www.anuko.com/lp/tt_5.htm" target="_blank">{$i18n.footer.license}</a> |
             <a href="https://www.anuko.com/lp/tt_7.htm" target="_blank">{$i18n.footer.improve}</a>
index 2971404..d9452cc 100644 (file)
@@ -1,4 +1,13 @@
 <script>
+// Prepare an array of available roles. We need it for "is_client" property.
+// It is used to selectively display client selector for client roles.
+roles = new Array();
+var idx = 0;
+{foreach $active_roles as $active_role}
+roles[idx] = new Array({$active_role.id}, '{$active_role.is_client}');
+idx++;
+{/foreach}
+
 // The setDefaultRate function sets / unsets default rate for a project
 // when a corresponding checkbox is ticked.
 function setDefaultRate(element) {
@@ -23,11 +32,19 @@ function setDefaultRate(element) {
 // handleClientControl - controls visibility of the client dropdown depending on the selected user role.
 // We need to show it only when the "Client" user role is selected.
 function handleClientControl() {
+  var selectedRoleId = document.getElementById("role").value;
   var clientControl = document.getElementById("client");
-  if ("16" == document.getElementById("role").value)
-    clientControl.style.visibility = "visible";
-  else
-    clientControl.style.visibility = "hidden";
+  var len = roles.length;
+  for (var i = 0; i < len; i++) {
+    if (selectedRoleId == roles[i][0]) {
+      var isClient = roles[i][1];
+      if (isClient == 1)
+        clientControl.style.visibility = "visible";
+      else
+        clientControl.style.visibility = "hidden";
+      break;
+    }
+  }
 }
 </script>
 
index 7f81ca0..4a45f77 100644 (file)
@@ -1,4 +1,13 @@
 <script>
+// Prepare an array of available roles. We need it for "is_client" property.
+// It is used to selectively display client selector for client roles.
+roles = new Array();
+var idx = 0;
+{foreach $active_roles as $active_role}
+roles[idx] = new Array({$active_role.id}, '{$active_role.is_client}');
+idx++;
+{/foreach}
+
 // Prepare an array of rates.
 // Format: project_rates[0] = Array(100, '25.00'), project_rates[1] = Array(120, '30.00'), etc...
 // First element = project_id, second element = rate for project. Quotes needed for string representation of rates.
@@ -45,11 +54,19 @@ function setRate(element) {
 // handleClientControl - controls visibility of the client dropdown depending on the selected user role.
 // We need to show it only when the "Client" user role is selected.
 function handleClientControl() {
+  var selectedRoleId = document.getElementById("role").value;
   var clientControl = document.getElementById("client");
-  if ("16" == document.getElementById("role").value)
-    clientControl.style.visibility = "visible";
-  else
-    clientControl.style.visibility = "hidden";
+  var len = roles.length;
+  for (var i = 0; i < len; i++) {
+    if (selectedRoleId == roles[i][0]) {
+      var isClient = roles[i][1];
+      if (isClient == 1)
+        clientControl.style.visibility = "visible";
+      else
+        clientControl.style.visibility = "hidden";
+      break;
+    }
+  }
 }
 </script>
 
index 4e951e9..b4facce 100644 (file)
--- a/roles.php
+++ b/roles.php
@@ -38,7 +38,7 @@ if (!ttAccessCheck(right_manage_team)) {
 }
 
 // If there are no roles in team, introduce default ones.
-if (!ttRoleHelper::rolesExist()) ttRoleHelper::createDefaultRoles();
+if (!ttRoleHelper::rolesExist()) ttRoleHelper::createDefaultRoles(); // TODO: refactor or remove after roles revamp.
 
 $smarty->assign('active_roles', ttTeamHelper::getActiveRoles($user->team_id));
 $smarty->assign('inactive_roles', ttTeamHelper::getInactiveRoles($user->team_id));
index 906b2ed..ebc313a 100644 (file)
@@ -32,6 +32,7 @@ import('ttTeamHelper');
 import('ttUserHelper');
 import('form.Table');
 import('form.TableColumn');
+import('ttRoleHelper');
 
 // Access check.
 if (!ttAccessCheck(right_manage_team)) {
@@ -82,11 +83,12 @@ if (!$auth->isPasswordExternal()) {
 }
 $form->addInput(array('type'=>'text','maxlength'=>'100','name'=>'email','value'=>$cl_email));
 
-$roles[ROLE_USER] = $i18n->getKey('label.user');
-$roles[ROLE_COMANAGER] = $i18n->getKey('form.users.comanager');
-if ($user->isPluginEnabled('cl'))
-  $roles[ROLE_CLIENT] = $i18n->getKey('label.client');
-$form->addInput(array('type'=>'combobox','onchange'=>'handleClientControl()','name'=>'role','value'=>$cl_role,'data'=>$roles));
+$active_roles = ttTeamHelper::getActiveRolesForUser();
+//$roles[ROLE_USER] = $i18n->getKey('label.user');
+//$roles[ROLE_COMANAGER] = $i18n->getKey('form.users.comanager');
+//if ($user->isPluginEnabled('cl'))
+//  $roles[ROLE_CLIENT] = $i18n->getKey('label.client');
+$form->addInput(array('type'=>'combobox','onchange'=>'handleClientControl()','name'=>'role','value'=>$cl_role,'data'=>$active_roles,'datakeys'=>array('id', 'name')));
 if ($user->isPluginEnabled('cl'))
   $form->addInput(array('type'=>'combobox','name'=>'client','value'=>$cl_client_id,'data'=>$clients,'datakeys'=>array('id', 'name'),'empty'=>array(''=>$i18n->getKey('dropdown.select'))));
 
@@ -142,18 +144,21 @@ if ($request->isPost()) {
   }
   if (!ttValidEmail($cl_email, true)) $err->add($i18n->getKey('error.field'), $i18n->getKey('label.email'));
   // Require selection of a client for a client role.
-  if ($user->isPluginEnabled('cl') && $cl_role == ROLE_CLIENT && !$cl_client_id) $err->add($i18n->getKey('error.client'));
+  if ($user->isPluginEnabled('cl') && ttRoleHelper::isClientRole($cl_role) && !$cl_client_id) $err->add($i18n->getKey('error.client'));
   if (!ttValidFloat($cl_rate, true)) $err->add($i18n->getKey('error.field'), $i18n->getKey('form.users.default_rate'));
 
   if ($err->no()) {
     if (!ttUserHelper::getUserByLogin($cl_login)) {
+      // Get legacy role value.
+      $legacy_role = ttRoleHelper::getLegacyRole($cl_role); // TODO: remove after roles revamp.
       $fields = array(
         'name' => $cl_name,
         'login' => $cl_login,
         'password' => $cl_password1,
         'rate' => $cl_rate,
         'team_id' => $user->team_id,
-        'role' => $cl_role,
+        'role' => $legacy_role,
+        'role_id' => $cl_role,
         'client_id' => $cl_client_id,
         'projects' => $assigned_projects,
         'email' => $cl_email);
@@ -168,6 +173,7 @@ if ($request->isPost()) {
 } // isPost
 
 $smarty->assign('auth_external', $auth->isPasswordExternal());
+$smarty->assign('active_roles', $active_roles);
 $smarty->assign('forms', array($form->getName()=>$form->toArray()));
 $smarty->assign('onload', 'onLoad="document.userForm.name.focus();handleClientControl();"');
 $smarty->assign('title', $i18n->getKey('title.add_user'));
index 8308892..08755a7 100644 (file)
@@ -33,6 +33,7 @@ import('ttTeamHelper');
 import('ttUserHelper');
 import('form.Table');
 import('form.TableColumn');
+import('ttRoleHelper');
 
 // Access check.
 if (!ttAccessCheck(right_manage_team)) {
@@ -93,7 +94,12 @@ if ($request->isPost()) {
   $cl_login = $user_details['login'];
   $cl_email = $user_details['email'];
   $cl_rate = str_replace('.', $user->decimal_mark, $user_details['rate']);
-  $cl_role = $user_details['role'];
+  $cl_role = $user_details['role_id'];
+
+  // In case role_id is not yet assigned...
+  if (!$cl_role && $user_details['role'])
+    $cl_role = ttRoleHelper::gerRoleByRank($user_details['role']); // TODO: remove after roles revamp.
+  
   $cl_client_id = $user_details['client_id'];
   $cl_status = $user_details['status'];
   $cl_projects = array();
@@ -112,11 +118,12 @@ if (!$auth->isPasswordExternal()) {
 }
 $form->addInput(array('type'=>'text','maxlength'=>'100','name'=>'email','style'=>'width: 300px;','value'=>$cl_email));
 
-$roles[ROLE_USER] = $i18n->getKey('label.user');
-$roles[ROLE_COMANAGER] = $i18n->getKey('form.users.comanager');
-if ($user->isPluginEnabled('cl'))
-  $roles[ROLE_CLIENT] = $i18n->getKey('label.client');
-$form->addInput(array('type'=>'combobox','onchange'=>'handleClientControl()','name'=>'role','value'=>$cl_role,'data'=>$roles));
+$active_roles = ttTeamHelper::getActiveRolesForUser();
+//$roles[ROLE_USER] = $i18n->getKey('label.user');
+//$roles[ROLE_COMANAGER] = $i18n->getKey('form.users.comanager');
+//if ($user->isPluginEnabled('cl'))
+//  $roles[ROLE_CLIENT] = $i18n->getKey('label.client');
+$form->addInput(array('type'=>'combobox','onchange'=>'handleClientControl()','name'=>'role','value'=>$cl_role,'data'=>$active_roles, 'datakeys'=>array('id', 'name')));
 if ($user->isPluginEnabled('cl'))
   $form->addInput(array('type'=>'combobox','name'=>'client','value'=>$cl_client_id,'data'=>$clients,'datakeys'=>array('id', 'name'),'empty'=>array(''=>$i18n->getKey('dropdown.select'))));
 
@@ -174,14 +181,14 @@ if ($request->isPost()) {
   }
   if (!ttValidEmail($cl_email, true)) $err->add($i18n->getKey('error.field'), $i18n->getKey('label.email'));
   // Require selection of a client for a client role.
-  if ($user->isPluginEnabled('cl') && $cl_role == ROLE_CLIENT && !$cl_client_id) $err->add($i18n->getKey('error.client'));
+  if ($user->isPluginEnabled('cl') && ttRoleHelper::isClientRole($cl_role) && !$cl_client_id) $err->add($i18n->getKey('error.client'));
   if (!ttValidFloat($cl_rate, true)) $err->add($i18n->getKey('error.field'), $i18n->getKey('form.users.default_rate'));
 
   if ($err->no()) {
     $existing_user = ttUserHelper::getUserByLogin($cl_login);
     if (!$existing_user || ($user_id == $existing_user['id'])) {
 
-      $fields = array(
+        $fields = array(
         'name' => $cl_name,
         'login' => $cl_login,
         'password' => $cl_password1,
@@ -190,7 +197,10 @@ if ($request->isPost()) {
         'rate' => $cl_rate,
         'projects' => $assigned_projects);
       if (right_assign_roles & $user->rights) {
-        $fields['role'] = $cl_role;
+        // Get legacy role value.
+        $legacy_role = ttRoleHelper::getLegacyRole($cl_role); // TODO: remove after roles revamp.
+        $fields['role'] = $legacy_role;
+        $fields['role_id'] = $cl_role;
         $fields['client_id'] = $cl_client_id;
       }
 
@@ -231,6 +241,7 @@ $rates = ttProjectHelper::getRates($user_id);
 $smarty->assign('rates', $rates);
 
 $smarty->assign('auth_external', $auth->isPasswordExternal());
+$smarty->assign('active_roles', $active_roles);
 $smarty->assign('forms', array($form->getName()=>$form->toArray()));
 $smarty->assign('onload', 'onLoad="document.userForm.name.focus();handleClientControl();"');
 $smarty->assign('user_id', $user_id);
index 354ea1d..3fc2667 100644 (file)
--- a/users.php
+++ b/users.php
@@ -30,6 +30,7 @@ require_once('initialize.php');
 import('form.Form');
 import('ttTeamHelper');
 import('ttTimeHelper');
+import('ttRoleHelper');
 
 // Access check.
 if (!ttAccessCheck(right_data_entry)) {
@@ -40,6 +41,12 @@ if (!ttAccessCheck(right_data_entry)) {
 // Get users.
 $active_users = ttTeamHelper::getActiveUsers(array('getAllFields'=>true));
 if($user->canManageTeam()) {
+
+  // If there are no roles in team, introduce default ones.
+  if (!ttRoleHelper::rolesExist()) ttRoleHelper::createDefaultRoles(); // TODO: refactor or remove after roles revamp.
+  // This is here temporarily so that we have roles to work with to manage users.
+  // Normally, this should be done during an upgrade step (not yet implemented).
+
   $can_delete_manager = (1 == count($active_users));
   $inactive_users = ttTeamHelper::getInactiveUsers($user->team_id, true);
 }