Fixed timezone preference setting not fully implemented; added ability for users to select their own rank from a list of possible ranks based on group membership and user level
authorDan
Sun, 21 Dec 2008 04:26:56 -0500
changeset 770 62fed244fa1c
parent 769 1946d845bb25
child 771 5e85d7db8ee5
Fixed timezone preference setting not fully implemented; added ability for users to select their own rank from a list of possible ranks based on group membership and user level
includes/dbal.php
includes/functions.php
includes/paths.php
includes/sessions.php
install/schemas/mysql_stage2.sql
install/schemas/postgresql_stage2.sql
install/schemas/upgrade/1.1.4-1.1.5-mysql.sql
install/schemas/upgrade/1.1.4-1.1.5-postgresql.sql
language/english/core.json
language/english/user.json
plugins/SpecialUserPrefs.php
plugins/admin/UserManager.php
--- a/includes/dbal.php	Sun Dec 21 04:24:52 2008 -0500
+++ b/includes/dbal.php	Sun Dec 21 04:26:56 2008 -0500
@@ -421,7 +421,7 @@
     if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
     $row = mysql_fetch_assoc($r);
     $this->disable_errorhandler();
-    return $row;
+    return integerize_array($row);
   }
   
   function fetchrow_num($r = false) {
@@ -430,7 +430,7 @@
     if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
     $row = mysql_fetch_row($r);
     $this->disable_errorhandler();
-    return $row;
+    return integerize_array($row);
   }
   
   function numrows($r = false) {
@@ -1165,7 +1165,7 @@
     if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
     $row = pg_fetch_assoc($r);
     $this->disable_errorhandler();
-    return $row;
+    return integerize_array($row);
   }
   
   function fetchrow_num($r = false) {
@@ -1174,7 +1174,7 @@
     if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
     $row = pg_fetch_row($r);
     $this->disable_errorhandler();
-    return $row;
+    return integerize_array($row);
   }
   
   function numrows($r = false) {
--- a/includes/functions.php	Sun Dec 21 04:24:52 2008 -0500
+++ b/includes/functions.php	Sun Dec 21 04:26:56 2008 -0500
@@ -719,6 +719,31 @@
   return $arr3;
 }
 
+/**
+ * Looks at all values in an array and casts them to integers if they are strings with digits. Recursive.
+ * @param array Array to process
+ * @return array
+ */
+
+function integerize_array($arr)
+{
+  if ( !is_array($arr) )
+    return $arr;
+  
+  foreach ( $arr as &$val )
+  {
+    if ( is_string($val) && ctype_digit($val) && strlen($val) < 10 )
+    {
+      $val = intval($val);
+    }
+    else if ( is_array($val) )
+    {
+      $val = integerize_array($val);
+    }
+  }
+  return $arr;
+}
+
 // Convert IP address to hex string
 // Input:  127.0.0.1  (string)
 // Output: 0x7f000001 (string)
@@ -2876,7 +2901,8 @@
   $page_id = str_replace(' ', '_', $page_id);
 
   // Exception for userpages for IP addresses
-  if ( is_valid_ip($page_id) )
+  $pid_ip_check = ( is_object($paths) ) ? preg_replace('+^' . preg_quote($paths->nslist['User']) . '+', '', $page_id) : $page_id;
+  if ( is_valid_ip($pid_ip_check) )
   {
     return $page_id;
   }
--- a/includes/paths.php	Sun Dec 21 04:24:52 2008 -0500
+++ b/includes/paths.php	Sun Dec 21 04:26:56 2008 -0500
@@ -619,7 +619,13 @@
     global $cache;
     
     // store data (TTL 20 minutes)
-    $cache->store('page_meta', $md_array, 20);
+    try
+    {
+      $cache->store('page_meta', $md_array, 20);
+    }
+    catch ( Exception $e )
+    {
+    }
     
     return true;
   }
--- a/includes/sessions.php	Sun Dec 21 04:24:52 2008 -0500
+++ b/includes/sessions.php	Sun Dec 21 04:26:56 2008 -0500
@@ -2349,9 +2349,11 @@
          . "       COALESCE(ru.rank_id,    rg.rank_id,    rl.rank_id,    rd.rank_id   ) AS rank_id,\n"
          . "       COALESCE(ru.rank_title, rg.rank_title, rl.rank_title, rd.rank_title) AS rank_title,\n"
          . "       COALESCE(ru.rank_style, rg.rank_style, rl.rank_style, rd.rank_style) AS rank_style,\n"
-         . "       rg.rank_id AS group_rank_id,"
-         . "       ( ru.rank_id IS NULL AND rg.rank_id IS NULL ) AS using_default,"
-         . "       ( ru.rank_id IS NULL AND rg.rank_id IS NOT NULL ) AS using_group,"
+         . "       rg.rank_id AS group_rank_id,\n"
+         . "       ( ru.rank_id IS NULL AND rg.rank_id IS NULL ) AS using_default,\n"
+         . "       ( ru.rank_id IS NULL AND rg.rank_id IS NOT NULL ) AS using_group,\n"
+         . "       ( ru.rank_id IS NOT NULL ) AS using_user,\n"
+         . "       u.user_rank_userset,\n"
          . "       $gid_col\n"
          . "  FROM " . table_prefix . "users AS u\n"
          . "  LEFT JOIN " . table_prefix . "groups AS g\n"
@@ -2393,7 +2395,7 @@
     global $db, $session, $paths, $template, $plugins; // Common objects
     global $lang;
     global $user_ranks;
-    // cache info if possible
+    // cache info in RAM if possible
     static $_cache = array();
     
     if ( is_int($id) && $id == 0 )
@@ -2407,7 +2409,7 @@
       // invalid parameter
       return false;
       
-    // check the cache
+    // check the RAM cache
     if ( isset($_cache[$id]) )
       return $_cache[$id];
     
@@ -2557,6 +2559,109 @@
     return $row;
   }
   
+  /**
+   * Get the list of ranks that a user is allowed to use. Returns false if they cannot change it.
+   * @param string|int User ID or username
+   * @return array Associative by rank ID
+   */
+  
+  function get_user_possible_ranks($id)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    // cache info in RAM if possible
+    static $_cache = array();
+    
+    if ( is_int($id) && $id == 0 )
+      $id = 1;
+    
+    if ( is_int($id) )
+      $col = "u.user_id = $id";
+    else if ( is_string($id) )
+      $col = ENANO_SQLFUNC_LOWERCASE . "(username) = " . ENANO_SQLFUNC_LOWERCASE . "('" . $db->escape($id) . "')";
+    else
+      // invalid parameter
+      return false;
+      
+    // check the RAM cache
+    if ( isset($_cache[$id]) )
+      return $_cache[$id];
+    
+    $sql = $this->generate_rank_sql("\n  WHERE $col");
+    
+    $q = $this->sql($sql);
+    // any results?
+    if ( $db->numrows() < 1 )
+    {
+      // nuttin'.
+      $db->free_result();
+      $_cache[$id] = false;
+      return false;
+    }
+    
+    // Found something.
+    $row = $db->fetchrow();
+    $db->free_result();
+    
+    if ( $row['using_user'] && !$row['user_rank_userset'] )
+    {
+      // The user's rank was set manually by an admin.
+      $result = array(
+        array(
+          'rank_id' => $row['rank_id'],
+          'rank_title' => $row['rank_title'],
+          'rank_style' => $row['rank_style'],
+          'rank_type' => 'user'
+          )
+        );
+      $_cache[$id] = $result;
+      return $result;
+    }
+    
+    // copy the result to a more permanent array so we can reference this later
+    $current_settings = $row;
+    unset($row);
+    
+    $result = array();
+    
+    // first rank available to us will be the one set by the user's user level
+    if ( isset($this->level_rank_table[$current_settings['user_level']]) )
+    {
+      $q = $this->sql('SELECT rank_id, rank_title, rank_style FROM ' . table_prefix . "ranks WHERE rank_id = {$this->level_rank_table[$this->user_level]};");
+      if ( $db->numrows() > 0 )
+      {
+        $row = $db->fetchrow();
+        $row['rank_type'] = 'ulevel';
+        
+        $result[] = $row;
+      }
+      $db->free_result();
+    }
+    
+    // for each group the user is in, figure out if it has a rank associated with it
+    $group_list = explode(',', $current_settings['group_list']);
+    foreach ( $group_list as $group_id )
+    {
+      $group_id = intval($group_id);
+      $q = $this->sql('SELECT r.rank_id, r.rank_title, r.rank_style FROM ' . table_prefix . "groups AS g\n"
+                    . "  LEFT JOIN " . table_prefix . "ranks AS r\n"
+                    . "    ON ( g.group_rank = r.rank_id )\n"
+                    . "  WHERE g.group_id = $group_id\n"
+                    . "    AND r.rank_id IS NOT NULL;");
+      if ( $db->numrows() > 0 )
+      {
+        $row = $db->fetchrow();
+        $row['rank_type'] = 'group';
+        
+        $result[] = $row;
+      }
+      $db->free_result();
+    }
+    
+    $_cache[$id] = $result;
+    return $result;
+  }
+  
   #
   # Access Control Lists
   #
@@ -3571,7 +3676,7 @@
         {
           return array(
             'mode' => 'error',
-            'error' => 'ERR_DH_HASH_NO_MATCH'
+            'error' => 'ERR_DH_HASH_NO_MATCH',
           );
         }
         
--- a/install/schemas/mysql_stage2.sql	Sun Dec 21 04:24:52 2008 -0500
+++ b/install/schemas/mysql_stage2.sql	Sun Dec 21 04:26:56 2008 -0500
@@ -112,6 +112,7 @@
   avatar_type ENUM('jpg', 'png', 'gif', 'grv') NOT NULL DEFAULT 'png',
   user_registration_ip varchar(39),
   user_rank int(12) UNSIGNED DEFAULT NULL,
+  user_rank_userset tinyint(1) NOT NULL DEFAULT 0,
   user_timezone int(12) UNSIGNED NOT NULL DEFAULT 0,
   user_title varchar(64) DEFAULT NULL,
   user_group mediumint(5) NOT NULL DEFAULT 1,
--- a/install/schemas/postgresql_stage2.sql	Sun Dec 21 04:24:52 2008 -0500
+++ b/install/schemas/postgresql_stage2.sql	Sun Dec 21 04:26:56 2008 -0500
@@ -112,6 +112,7 @@
   avatar_type varchar(3) NOT NULL,
   user_registration_ip varchar(39),
   user_rank int DEFAULT NULL,
+  user_rank_userset smallint NOT NULL DEFAULT 0,
   user_timezone int NOT NULL DEFAULT 0,
   user_title varchar(64) DEFAULT NULL,
   user_group int NOT NULL DEFAULT 1,
--- a/install/schemas/upgrade/1.1.4-1.1.5-mysql.sql	Sun Dec 21 04:24:52 2008 -0500
+++ b/install/schemas/upgrade/1.1.4-1.1.5-mysql.sql	Sun Dec 21 04:26:56 2008 -0500
@@ -1,3 +1,4 @@
 ALTER TABLE {{TABLE_PREFIX}}session_keys ADD COLUMN key_type tinyint(1) NOT NULL DEFAULT 0;
 UPDATE {{TABLE_PREFIX}}session_keys SET key_type = 2 WHERE auth_level > 2;
 ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60';
+ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN user_rank_userset tinyint(1) NOT NULL DEFAULT 0;
--- a/install/schemas/upgrade/1.1.4-1.1.5-postgresql.sql	Sun Dec 21 04:24:52 2008 -0500
+++ b/install/schemas/upgrade/1.1.4-1.1.5-postgresql.sql	Sun Dec 21 04:26:56 2008 -0500
@@ -1,4 +1,4 @@
 ALTER TABLE {{TABLE_PREFIX}}session_keys ADD COLUMN key_type smallint NOT NULL DEFAULT 0;
 UPDATE {{TABLE_PREFIX}}session_keys SET key_type = 2 WHERE auth_level > 2;
 ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60';
-
+ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN user_rank_userset smallint NOT NULL DEFAULT 0;
--- a/language/english/core.json	Sun Dec 21 04:24:52 2008 -0500
+++ b/language/english/core.json	Sun Dec 21 04:26:56 2008 -0500
@@ -695,7 +695,7 @@
       list: '{"n12":-12,"n11":-11,"n10":-10,"n9p5":-9.5,"n9":-9,"n8":-8,"n7":-7,"n6":-6,"n5":-5,"n4":-4,"n3p5":-3.5,"n3":-3,"n2":-2,"n1":-1,"0":0,"1":1,"2":2,"3":3,"3p5":3.5,"4":4,"4p5":4.5,"5":5,"5p5":5.5,"5p75":5.75,"6":6,"6p5":6.5,"7":7,"8":8,"8p75":8.75,"9":9,"9p5":9.5,"10":10,"10p5":10.5,"11":11,"11p5":11.5,"12":12,"12p75":12.75,"13":13,"14":14}',
       
       // DST profiles
-      dst_off: 'My region doesn\'t use DST',
+      dst_off: 'My region doesn\'t observe DST',
       dst_usa: 'United States: second Sunday of March to first Sunday of November',
       dst_europe: 'Europe: last Sunday of March to last Sunday of October',
       dst_australia: 'Australia (except Tasmania): last Sunday of October to last Sunday of March',
--- a/language/english/user.json	Sun Dec 21 04:24:52 2008 -0500
+++ b/language/english/user.json	Sun Dec 21 04:26:56 2008 -0500
@@ -315,6 +315,8 @@
       publicinfo_field_dst: 'Daylight saving time:',
       publicinfo_field_usertitle_title: 'User title:',
       publicinfo_field_usertitle_hint: 'This can be some text that will be displayed underneath your username.',
+      publicinfo_field_rank_title: 'Display rank:',
+      publicinfo_field_rank_hint: 'Select the rank you want to be shown with your username.',
       publicinfo_th_im: 'Instant messenger contact information',
       publicinfo_field_aim: 'AIM handle:',
       publicinfo_field_wlm: '<acronym title="Windows&trade; Live Messenger">WLM</acronym> handle:<br /><small>If you don\'t specify the domain (@whatever.com), "@hotmail.com" will be assumed.</small>',
--- a/plugins/SpecialUserPrefs.php	Sun Dec 21 04:24:52 2008 -0500
+++ b/plugins/SpecialUserPrefs.php	Sun Dec 21 04:26:56 2008 -0500
@@ -155,6 +155,7 @@
   global $db, $session, $paths, $template, $plugins; // Common objects
   global $lang;
   global $timezone;
+  global $cache;
   
   // We need a login to continue
   if ( !$session->user_logged_in )
@@ -468,6 +469,9 @@
       echo '</form>';
       break;
     case "Profile":
+      $available_ranks = $session->get_user_possible_ranks($session->user_id);
+      $current_rank = $session->get_user_rank($session->user_id);
+      
       if ( isset($_POST['submit']) )
       {
         $real_name = htmlspecialchars($_POST['real_name']);
@@ -476,6 +480,12 @@
         $timezone = intval($_POST['timezone']);
         $tz_local = $timezone + 1440;
         
+        $dst = $db->escape($_POST['dst']);
+        if ( !preg_match('/^[0-9]+;[0-9]+;[0-9]+;[0-9]+;[0-9]+$/', $dst) )
+          $dst = '0;0;0;0;60';
+        
+        $GLOBALS['dst_params'] = explode(';', $dst);
+        
         $imaddr_aim = htmlspecialchars($_POST['imaddr_aim']);
         $imaddr_aim = $db->escape($imaddr_aim);
         
@@ -547,8 +557,36 @@
           }
           $user_title_col = ", user_title = $colval";
         }
+        $user_rank_col = '';
+        if ( intval($_POST['user_rank']) != $current_rank['rank_id'] && count($available_ranks) > 1 )
+        {
+          if ( $_POST['user_rank'] == 'NULL' )
+          {
+            $user_rank_col = ", user_rank = NULL, user_rank_userset = 0";
+          }
+          else
+          {
+            $new_rank = intval($_POST['user_rank']);
+            $rank_allowed = false;
+            foreach ( $available_ranks as $rank )
+            {
+              if ( $rank['rank_id'] == $new_rank )
+              {
+                $rank_allowed = true;
+                break;
+              }
+            }
+            if ( $rank_allowed )
+            {
+              $user_rank_col = ", user_rank = $new_rank, user_rank_userset = 1";
+              // hack
+              $current_rank['rank_id'] = $new_rank;
+              $cache->purge('ranks');
+            }
+          }
+        }
         
-        $q = $db->sql_query('UPDATE '.table_prefix."users SET real_name='$real_name', user_timezone = $tz_local{$user_title_col} WHERE user_id=$session->user_id;");
+        $q = $db->sql_query('UPDATE '.table_prefix."users SET real_name='$real_name', user_timezone = {$tz_local}, user_dst = '$dst'{$user_title_col}{$user_rank_col} WHERE user_id=$session->user_id;");
         if ( !$q )
           $db->_die();
         
@@ -571,6 +609,7 @@
           $db->free_result();
           
           // unload / reload $lang, this verifies that the selected language works
+          // enano should die a violent death if the language fails to load
           unset($GLOBALS['lang']);
           unset($lang);
           $lang_id = intval($lang_id);
@@ -682,6 +721,29 @@
             </tr>
           <?php
           endif;
+          if ( count($available_ranks) > 1 ):
+          ?>
+          <tr>
+            <td class="row2">
+              <?php echo $lang->get('usercp_publicinfo_field_rank_title'); ?><br />
+              <small><?php echo $lang->get('usercp_publicinfo_field_rank_hint'); ?></small>
+            </td>
+            <td class="row1">
+              <select name="user_rank">
+                <?php
+                foreach ( $available_ranks as $rank )
+                {
+                  $sel = ( $rank['rank_id'] == $current_rank['rank_id'] ) ? ' selected="selected"' : '';
+                  echo '<option' . $sel . ' value="' . $rank['rank_id'] . '" style="' . htmlspecialchars($rank['rank_style']) . '">';
+                  echo htmlspecialchars($lang->get($rank['rank_title']));
+                  echo '</option>';
+                }
+                ?>
+              </select>
+            </td>
+          </tr>
+          <?php
+          endif;
           ?>
           <tr>
             <th class="subhead" colspan="2">
--- a/plugins/admin/UserManager.php	Sun Dec 21 04:24:52 2008 -0500
+++ b/plugins/admin/UserManager.php	Sun Dec 21 04:26:56 2008 -0500
@@ -225,6 +225,11 @@
         $to_update_users['user_rank'] = $user_rank;
         $to_update_users['user_title'] = $user_title;
         
+        if ( $user_rank > 0 )
+        {
+          $to_update_users['user_rank_userset'] = '0';
+        }
+        
         if ( isset($_POST['account_active']) )
         {
           $to_update_users['account_active'] = "1";