Cleanups to Chora::.
authorMichael M Slusarz <slusarz@curecanti.org>
Thu, 29 Jan 2009 04:18:01 +0000 (21:18 -0700)
committerMichael M Slusarz <slusarz@curecanti.org>
Thu, 29 Jan 2009 08:12:45 +0000 (01:12 -0700)
17 files changed:
chora/browse.php
chora/cvsgraph.php
chora/history.php
chora/lib/Block/tree_menu.php
chora/lib/Chora.php
chora/lib/base.php
chora/patchsets.php
chora/stats.php
chora/templates/checkout/checkout.inc
chora/templates/common-header.inc
chora/templates/diff/hr/header.inc
chora/templates/headerbar.inc
chora/templates/history/branch_cell.inc
chora/templates/history/rev.inc
chora/templates/log/rev.inc
chora/templates/menu.inc
framework/Vcs/lib/Horde/Vcs.php

index 6d0e569..3ba7155 100644 (file)
@@ -33,7 +33,7 @@ if ($atdir) {
         : sprintf(_("Source Directory of /%s"), $where);
 
     $extraLink = $VC->hasFeature('deleted')
-        ? Horde::widget(Chora::url('', $where . '/', array('sa' => ($acts['sa'] ? 0 : 1))), $acts['sa'] ? _("Hide Deleted Files") : _("Show Deleted Files"), 'widget', '', '', $acts['sa'] ? _("Hide _Deleted Files") : _("Show _Deleted Files"))
+        ? Horde::widget(Chora::url('browse', $where . '/', array('sa' => ($acts['sa'] ? 0 : 1))), $acts['sa'] ? _("Hide Deleted Files") : _("Show Deleted Files"), 'widget', '', '', $acts['sa'] ? _("Hide _Deleted Files") : _("Show _Deleted Files"))
         : '';
 
     $umap = array(
@@ -48,7 +48,7 @@ if ($atdir) {
         if ($acts['sbt'] == $val) {
             $arg['ord'] = !$acts['ord'];
         }
-        $url[$key] = Chora::url('', $where . '/', $arg);
+        $url[$key] = Chora::url('browse', $where . '/', $arg);
     }
 
     /* Print out the directory header. */
@@ -63,7 +63,7 @@ if ($atdir) {
 
     /* Unless we're at the top, display the 'back' bar. */
     if ($where != '') {
-        $url = Chora::url('', preg_replace('|[^/]+$|', '', $where));
+        $url = Chora::url('browse', preg_replace('|[^/]+$|', '', $where));
         require CHORA_TEMPLATES . '/directory/back.inc';
     }
 
@@ -74,7 +74,7 @@ if ($atdir) {
             if ($conf['hide_restricted'] && Chora::isRestricted($currentDir)) {
                 continue;
             }
-            $url = Chora::url('', "$where/$currentDir/");
+            $url = Chora::url('browse', "$where/$currentDir/");
             $currDir = Text::htmlAllSpaces($currentDir);
             require CHORA_TEMPLATES . '/directory/dir.inc';
         }
@@ -102,7 +102,7 @@ if ($atdir) {
             $attic = $currFile->isDeleted();
             $fileName = $where . ($attic ? '/' . 'Attic' : '') . '/' . $realname;
             $name = Text::htmlAllSpaces($realname);
-            $url = Chora::url('', $fileName);
+            $url = Chora::url('browse', $fileName);
             $readableDate = Chora::readableTime($date);
             if ($log) {
                 $shortLog = str_replace("\n", ' ',
@@ -131,7 +131,7 @@ try {
 
 $title = sprintf(_("Revisions for %s"), $where);
 
-$extraLink = Chora::getFileViews();
+$extraLink = Chora::getFileViews($where, 'browse');
 $logs = $fl->queryLogs();
 $first = end($logs);
 $diffValueLeft = $first->queryRevision();
index 85fe68d..c8eb41f 100644 (file)
@@ -16,7 +16,7 @@ require_once dirname(__FILE__) . '/lib/base.php';
 
 // Exit if cvsgraph isn't active or it's not supported.
 if (empty($conf['paths']['cvsgraph']) || !$VC->hasFeature('branches')) {
-    header('Location: ' . Chora::url('', $where));
+    header('Location: ' . Chora::url('browse', $where));
     exit;
 }
 
@@ -49,7 +49,7 @@ if (Util::getFormData('show_image')) {
 } else {
     // Display the wrapper page for the image.
     $title = sprintf(_("Graph for %s"), Text::htmlAllSpaces($where));
-    $extraLink = Chora::getFileViews();
+    $extraLink = Chora::getFileViews($where, 'cvsgraph');
 
     require CHORA_TEMPLATES . '/common-header.inc';
     require CHORA_TEMPLATES . '/menu.inc';
@@ -61,7 +61,7 @@ if (Util::getFormData('show_image')) {
                   'M' => 'graphMap',
                   'r' => $root,
                   '0' => '&amp;',
-                  '1' => Chora::url('', $where, array('dummy' => 'true')),
+                  '1' => Chora::url('browse', $where, array('dummy' => 'true')),
                   '2' => Chora::url('diff', $where, array('dummy' =>'true')),
                   '3' => Chora::url('co', $where, array('dummy' => 'true')),
     );
index adf38eb..1962f07 100644 (file)
@@ -125,7 +125,7 @@ foreach ($grid as $cols) {
 }
 
 $title = sprintf(_("Source Branching View for %s"), Text::htmlallspaces($where));
-$extraLink = Chora::getFileViews();
+$extraLink = Chora::getFileViews($where, 'history');
 
 require CHORA_TEMPLATES . '/common-header.inc';
 require CHORA_TEMPLATES . '/menu.inc';
index 2aa717e..f2cc9e7 100644 (file)
@@ -3,35 +3,33 @@
 $block_name = _("Menu List");
 $block_type = 'tree';
 
-class Horde_Block_chora_tree_menu extends Horde_Block {
-
+class Horde_Block_chora_tree_menu extends Horde_Block
+{
     var $_app = 'chora';
 
     function _buildTree(&$tree, $indent = 0, $parent = null)
     {
-        global $perms, $sourceroots;
-
         define('CHORA_ERROR_HANDLER', true);
         require_once dirname(__FILE__) . '/../base.php';
 
         $arr = array();
-        asort($sourceroots);
+        asort($GLOBALS['sourceroots']);
+
         foreach ($sourceroots as $key => $val) {
-            if ((!$perms->exists('chora:sourceroots:' . $key) ||
-                 $perms->hasPermission('chora:sourceroots:' . $key,
-                                       Auth::getAuth(),
-                                       PERMS_READ | PERMS_SHOW))) {
+            if (Chora::checkPerms($key)) {
                 $tree->addNode($parent . $key,
-                               $parent,
-                               $val['name'],
-                               $indent + 1,
-                               false,
-                               array('icon' => 'folder.png',
-                                     'icondir' => $registry->getImageDir('horde') . '/tree',
-                                     'url' => Chora::url('', '', array('rt' => $key))));
+                    $parent,
+                    $val['name'],
+                    $indent + 1,
+                    false,
+                    array(
+                        'icon' => 'folder.png',
+                        'icondir' => $GLOBALS['registry']->getImageDir('horde') . '/tree',
+                        'url' => Chora::url('browse', '', array('rt' => $key))
+                    )
+                );
             }
         }
-
     }
 
 }
index 591ff0a..85ee6a0 100644 (file)
@@ -8,73 +8,41 @@
  * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
  *
  * @author  Anil Madhavapeddy <avsm@horde.org>
+ * @author  Michael Slusarz <slusarz@horde.org>
  * @package Chora
  */
 class Chora
 {
     /**
-     * Return a text description of how long its been since the file
-     * has been last modified.
+     * Cached data for isRestricted().
      *
-     * @param integer $date  Number of seconds since epoch we wish to display.
-     * @param boolean $long  If true, display a more verbose date.
-     *
-     * @return string  The human-readable date.
+     * @var array
      */
-    static public function readableTime($date, $long = false)
-    {
-        static $time, $desc, $breaks;
-
-        /* Initialize popular variables. */
-        if (!isset($time)) {
-            $time = time();
-            $desc = array(
-                1 => array(_("second"), _("seconds")),
-                60 => array(_("minute"), _("minutes")),
-                3600 => array(_("hour"), _("hours")),
-                86400 => array(_("day"), _("days")),
-                604800 => array(_("week"), _("weeks")),
-                2628000 => array(_("month"), _("months")),
-                31536000 => array(_("year"), _("years"))
-            );
-            $breaks = array_keys($desc);
-        }
-
-        $i = count($breaks);
-        $secs = $time - $date;
-
-        if ($secs < 2) {
-            return _("very little time");
-        }
-
-        while (--$i && $i && $breaks[$i] * 2 > $secs);
+    static public $restricted;
 
-        $break = $breaks[$i];
-
-        $val = intval($secs / $break);
-        $retval = $val . ' ' . ($val > 1 ? $desc[$break][1] : $desc[$break][0]);
-        if ($long && $i > 0) {
-            $rest = $secs % $break;
-            $break = $breaks[--$i];
-            $rest = (int)($rest / $break);
-            if ($rest > 0) {
-                $resttime = $rest . ' ' . ($rest > 1 ? $desc[$break][1] : $desc[$break][0]);
-                $retval .= ', ' . $resttime;
-            }
-        }
+    /**
+     * Cached data for readableTime().
+     *
+     * @var array
+     */
+    static public $rtcache;
 
-        return $retval;
-    }
+    /**
+     * Cached data for formatDate().
+     *
+     * @var string
+     */
+    static public $fdcache;
 
     /**
      * Initialize global variables and objects.
      */
     static public function initialize()
     {
-        global $acts, $defaultActs, $conf, $where, $atdir, $fullname, $prefs,
-               $sourceroot, $scriptName;
+        global $acts, $defaultActs, $where, $atdir, $fullname, $sourceroot;
 
-        $sourceroots = Chora::sourceroots();
+        $GLOBALS['sourceroots'] = Horde::loadConfiguration('sourceroots.php', 'sourceroots');
+        $sourceroots = self::sourceroots();
 
         /**
          * Variables we wish to propagate across web pages
@@ -87,22 +55,27 @@ class Chora
          * XXX: Rewrite this propagation code, since it sucks - avsm
          */
         $defaultActs = array(
-            'sbt' => constant($conf['options']['defaultsort']),
+            'sbt' => constant($GLOBALS['conf']['options']['defaultsort']),
             'sa'  => 0,
             'ord' => Horde_Vcs::SORT_ASCENDING,
             'ws'  => 1
         );
 
-        /* Use the last sourceroot used as the default value if the user
-         * has that preference. */
-        $remember_last_file = $prefs->getValue('remember_last_file');
-        if ($remember_last_file) {
-            $last_file = $prefs->getValue('last_file') ? $prefs->getValue('last_file') : null;
-            $last_sourceroot = $prefs->getValue('last_sourceroot') ? $prefs->getValue('last_sourceroot') : null;
-        }
-
-        if ($remember_last_file && !empty($last_sourceroot) &&
-            is_array(@$sourceroots[$last_sourceroot])) {
+        /* Use the last sourceroot used as the default value if the user has
+         * that preference. */
+        if ($remember = $GLOBALS['prefs']->getValue('remember_last_file')) {
+            $last_file = $GLOBALS['prefs']->getValue('last_file')
+                ? $GLOBALS['prefs']->getValue('last_file')
+                : null;
+            $last_sourceroot = $GLOBALS['prefs']->getValue('last_sourceroot')
+                ? $GLOBALS['prefs']->getValue('last_sourceroot')
+                : null;
+        }
+
+        if ($remember &&
+            !empty($last_sourceroot) &&
+            !empty($sourceroots[$last_sourceroot]) &&
+            is_array($sourceroots[$last_sourceroot])) {
             $defaultActs['rt'] = $last_sourceroot;
         } else {
             foreach ($sourceroots as $key => $val) {
@@ -112,59 +85,54 @@ class Chora
             }
         }
 
-        /* See if any have been passed as GET variables, and if so,
-         * assign them into the acts array. */
+        /* See if any have been passed as GET variables, and if so, assign
+         * them into the acts array. */
         $acts = array();
         foreach ($defaultActs as $key => $default) {
             $acts[$key] = Util::getFormData($key, $default);
         }
 
         if (!isset($sourceroots[$acts['rt']])) {
-            Chora::fatal(_("Malformed URL"), '400 Bad Request');
+            self::fatal(_("Malformed URL"), '400 Bad Request');
         }
 
         $sourcerootopts = $sourceroots[$acts['rt']];
         $sourceroot = $acts['rt'];
 
         // Cache.
-        if (empty($conf['caching'])) {
+        if (empty($GLOBALS['conf']['caching'])) {
             $cache = null;
         } else {
-            $cache = &Horde_Cache::singleton($conf['cache']['driver'], Horde::getDriverConfig('cache', $conf['cache']['driver']));
+            $cache = &Horde_Cache::singleton($GLOBALS['conf']['cache']['driver'], Horde::getDriverConfig('cache', $GLOBALS['conf']['cache']['driver']));
         }
 
-        $conf['paths']['temp'] = Horde::getTempDir();
+        $GLOBALS['conf']['paths']['temp'] = Horde::getTempDir();
+
         try {
             $GLOBALS['VC'] = Horde_Vcs::factory(String::ucfirst($sourcerootopts['type']),
                 array('cache' => $cache,
                       'sourceroot' => $sourcerootopts['location'],
-                      'paths' => $conf['paths'],
+                      'paths' => $GLOBALS['conf']['paths'],
                       'username' => isset($sourcerootopts['username']) ? $sourcerootopts['username'] : '',
                       'password' => isset($sourcerootopts['password']) ? $sourcerootopts['password'] : ''));
         } catch (Horde_Vcs_Exception $e) {
-            Chora::fatal($e);
+            self::fatal($e);
         }
 
-        $conf['paths']['sourceroot'] = $sourcerootopts['location'];
-        $conf['paths']['cvsusers'] = $sourcerootopts['location'] . '/' . (isset($sourcerootopts['cvsusers']) ? $sourcerootopts['cvsusers'] : '');
-        $conf['paths']['introText'] = CHORA_BASE . '/config/' . (isset($sourcerootopts['intro']) ? $sourcerootopts['intro'] : '');
-        $conf['options']['introTitle'] = isset($sourcerootopts['title']) ? $sourcerootopts['title'] : '';
-        $conf['options']['sourceRootName'] = $sourcerootopts['name'];
+        $GLOBALS['conf']['paths']['sourceroot'] = $sourcerootopts['location'];
+        $GLOBALS['conf']['paths']['cvsusers'] = $sourcerootopts['location'] . '/' . (isset($sourcerootopts['cvsusers']) ? $sourcerootopts['cvsusers'] : '');
+        $GLOBALS['conf']['paths']['introText'] = CHORA_BASE . '/config/' . (isset($sourcerootopts['intro']) ? $sourcerootopts['intro'] : '');
+        $GLOBALS['conf']['options']['introTitle'] = isset($sourcerootopts['title']) ? $sourcerootopts['title'] : '';
+        $GLOBALS['conf']['options']['sourceRootName'] = $sourcerootopts['name'];
 
-        $where = Util::getFormData('f', '');
-        if ($where == '') {
-            $where = '/';
-        }
+        $where = Util::getFormData('f', '/');
 
         /* Location relative to the sourceroot. */
         $where = preg_replace(array('|^/|', '|\.\.|'), '', $where);
 
-        /* Location of this script (e.g. /chora/browse.php). */
-        $scriptName = preg_replace(array('|^/?|', '|/$|'), array('/', ''), $_SERVER['PHP_SELF']);
-
         /* Store last file/repository viewed, and set 'where' to
          * last_file if necessary. */
-        if ($remember_last_file) {
+        if ($remember) {
             if (!isset($_SESSION['chora']['login'])) {
                 $_SESSION['chora']['login'] = 0;
             }
@@ -172,8 +140,8 @@ class Chora
             /* We store last_sourceroot and last_file only when we have
              * already displayed at least one page. */
             if (!empty($_SESSION['chora']['login'])) {
-                $prefs->setValue('last_sourceroot', $acts['rt']);
-                $prefs->setValue('last_file', $where);
+                $GLOBALS['prefs']->setValue('last_sourceroot', $acts['rt']);
+                $GLOBALS['prefs']->setValue('last_file', $where);
             } else {
                 /* We are displaying the first page. */
                 if ($last_file && !$where) {
@@ -195,26 +163,30 @@ class Chora
 
         if (($sourcerootopts['type'] == 'cvs') &&
             !@is_dir($sourcerootopts['location'])) {
-            Chora::fatal(_("Sourceroot not found. This could be a misconfiguration by the server administrator, or the server could be having temporary problems. Please try again later."), '500 Internal Server Error');
+            self::fatal(_("Sourceroot not found. This could be a misconfiguration by the server administrator, or the server could be having temporary problems. Please try again later."), '500 Internal Server Error');
         }
 
-        if (Chora::isRestricted($where)) {
-            Chora::fatal(sprintf(_("%s: Forbidden by server configuration"), $where), '403 Forbidden');
+        if (self::isRestricted($where)) {
+            self::fatal(sprintf(_("%s: Forbidden by server configuration"), $where), '403 Forbidden');
         }
     }
 
-    static public function whereMenu()
+    /**
+     * Create the breadcrumb directory listing.
+     *
+     * @param string $where  The current filepath.
+     *
+     * @return string  The directory string.
+     */
+    static public function whereMenu($where)
     {
-        global $where, $atdir;
-
-        $bar = $wherePath = '';
+        $bar = '';
         $dirs = explode('/', $where);
         $dir_count = count($dirs) - 1;
 
         foreach ($dirs as $i => $dir) {
-            if (!empty($dir) && ($dir != 'Attic')) {
-                $wherePath = str_replace('//', '/', $wherePath . '/' . $dir);
-                $bar .= '/ <a href="' . Chora::url('', $wherePath . ($i == $dir_count ? '' : '/')) . '">'. Text::htmlallspaces($dir) . '</a> ';
+            if (!empty($dir)) {
+                $bar .= '/ <a href="' . self::url('browse', $dir . ($i == $dir_count ? '' : '/')) . '">'. Text::htmlallspaces($dir) . '</a> ';
             }
         }
 
@@ -224,87 +196,51 @@ class Chora
     /**
      * Output an error page.
      *
-     * @param string $message       The verbose error message to be displayed.
-     * @param string $responseCode  The HTTP error number (and optional text),
-     *                              for sending 404s or other codes if
-     *                              appropriate.
+     * @param string $message  The verbose error message to be displayed.
+     * @param string $code     The HTTP error number (and optional text), for
+     *                         sending 404s or other codes if appropriate.
      */
-    static public function fatal($message, $responseCode = null)
+    static public function fatal($message, $code = null)
     {
         if (defined('CHORA_ERROR_HANDLER') && constant('CHORA_ERROR_HANDLER')) {
             return;
         }
 
-        global $registry, $conf, $notification, $browser, $prefs;
-
         if (is_a($message, 'Horde_Vcs_Exception')) {
             $message = $message->getMessage();
         }
 
         /* Don't store the bad file in the user's preferences. */
-        $prefs->setValue('last_file', '');
+        $GLOBALS['prefs']->setValue('last_file', '');
 
-        if ($responseCode) {
-            header('HTTP/1.0 ' . $responseCode);
+        if ($code) {
+            header('HTTP/1.0 ' . $code);
         }
 
-        $notification->push($message, 'horde.error');
+        $GLOBALS['notification']->push($message, 'horde.error');
         require CHORA_TEMPLATES . '/common-header.inc';
         require CHORA_TEMPLATES . '/menu.inc';
-        require $registry->get('templates', 'horde') . '/common-footer.inc';
+        require $GLOBALS['registry']->get('templates', 'horde') . '/common-footer.inc';
         exit;
     }
 
     /**
-     * Convert a commit-name into whatever the user wants.
-     *
-     * @param string $name  Account name.
-     *
-     * @return string  The transformed name.
-     */
-    static public function showAuthorName($name, $fullname = false)
-    {
-        static $users = null;
-
-        if (is_null($users)) {
-            $users = $GLOBALS['VC']->getUsers($GLOBALS['conf']['paths']['cvsusers']);
-        }
-
-        if (is_array($users) && isset($users[$name])) {
-            return '<a href="mailto:' . htmlspecialchars($users[$name]['mail']) . '">' .
-                htmlspecialchars($fullname ? $users[$name]['name'] : $name) .
-                '</a>' . ($fullname ? ' <em>' . htmlspecialchars($name) . '</em>' : '');
-        }
-
-        return htmlspecialchars($name);
-    }
-
-    /**
      * Generate a URL that links into Chora.
      *
-     * @param string $script  Name of the Chora script to link into
+     * @param string $script  Name of the Chora script to link into.
      * @param string $uri     The path being browsed.
-     * @param array  $args    Key/value pair of any GET parameters to append
-     * @param string $anchor  Anchor entity name
+     * @param array $args     Key/value pair of any GET parameters to append.
+     * @param string $anchor  Anchor entity name.
      *
      * @return string  The URL, with session information if necessary.
      */
-    static public function url($script = '', $uri = '', $args = array(),
+    static public function url($script, $uri = '', $args = array(),
                                $anchor = '')
     {
-        global $conf, $acts, $defaultActs;
-
-        $differing = array();
-        foreach ($acts as $key => $val) {
-            if ($val != $defaultActs[$key]) {
-                $differing[$key] = $val;
-            }
-        }
+        $arglist = self::_getArgList($GLOBALS['acts'], $GLOBALS['defaultActs'], $args);
+        $script .= '.php';
 
-        $arglist = array_merge($differing, $args);
-        $script = $script ? $script . '.php' : 'browse.php';
-
-        if ($conf['options']['urls'] == 'rewrite') {
+        if ($GLOBALS['conf']['options']['urls'] == 'rewrite') {
             if ($script == 'browse.php') {
                 $script = $uri;
                 if (substr($script, 0, 1) == '/') {
@@ -313,62 +249,69 @@ class Chora
             } else {
                 $script .= '/' . $uri;
             }
-        } else {
+        } elseif (!empty($uri)) {
             $arglist['f'] = $uri;
         }
 
         $url = Util::addParameter(Horde::applicationUrl($script), $arglist);
-        if (!empty($anchor)) {
-            $url .= '#' . $anchor;
-        }
 
-        return $url;
+        return empty($anchor) ? $url : ($url . '#' . $anchor);
     }
 
     /**
      * Generates hidden form fields with all required parameters.
      *
-     * @param array  $args    Key/value pair of any POST parameters to append
-     *
      * @return string  The form fields, with session information if necessary.
      */
-    static public function formInputs($args = array())
+    static public function formInputs()
     {
-        global $conf, $acts, $defaultActs;
+        $arglist = self::_getArgList($GLOBALS['acts'], $GLOBALS['defaultActs'], array());
 
+        $fields = Util::formInput();
+        foreach ($arglist as $key => $val) {
+            $fields .= '<input type="hidden" name="' . htmlspecialchars($key) . '" value="' . htmlspecialchars($val) . '" />';
+        }
+
+        return $fields;
+    }
+
+    /**
+     * TODO
+     */
+    static protected function _getArgList($acts, $defaultActs, $args)
+    {
         $differing = array();
+
         foreach ($acts as $key => $val) {
             if ($val != $defaultActs[$key]) {
                 $differing[$key] = $val;
             }
         }
 
-        $arglist = array_merge($differing, $args);
-
-        $fields = Util::formInput();
-        foreach ($arglist as $key => $val) {
-            $fields .= '<input type="hidden" name="' . htmlspecialchars($key)
-                . '" value="' . htmlspecialchars($val) . '" />';
-        }
+        return array_merge($differing, $args);
+    }
 
-        return $fields;
+    /**
+     * TODO
+     */
+    static public function checkPerms($key)
+    {
+        return (!$GLOBALS['perms']->exists('chora:sourceroots:' . $key) ||
+                $GLOBALS['perms']->hasPermission('chora:sourceroots:' . $key, Auth::getAuth(), PERMS_READ | PERMS_SHOW));
     }
 
     /**
-     * Returns the entries of $sourceroots that the current user has access to.
+     * Returns the entries of $sourceroots that the current user has access
+     * to.
      *
      * @return array  The sourceroots that the current user has access to.
      */
     static public function sourceroots()
     {
-        global $perms, $sourceroot, $sourceroots;
-
         $arr = array();
-        foreach ($sourceroots as $key => $val) {
-            if (!$perms->exists('chora:sourceroots:' . $key) ||
-                 $perms->hasPermission('chora:sourceroots:' . $key,
-                                       Auth::getAuth(),
-                                       PERMS_READ | PERMS_SHOW)) {
+
+        foreach ($GLOBALS['sourceroots'] as $key => $val) {
+            if (self::checkPerms($key)) {
                 $arr[$key] = $val;
             }
         }
@@ -377,15 +320,16 @@ class Chora
     }
 
     /**
-     * Generate a list of repositories available from this
-     * installation of Chora.
+     * Generate a list of repositories available from this installation of
+     * Chora.
      *
      * @return string  XHTML code representing links to the repositories.
      */
     static public function repositories()
     {
-        $sourceroots = Chora::sourceroots();
+        $sourceroots = self::sourceroots();
         $num_repositories = count($sourceroots);
+
         if ($num_repositories == 1) {
             return '';
         }
@@ -393,17 +337,14 @@ class Chora
         $arr = array();
         foreach ($sourceroots as $key => $val) {
             if ($GLOBALS['sourceroot'] != $key) {
-                $arr[] = '<option value="' .
-                    Chora::url('', '', array('rt' => $key)) .
-                    '">' . $val['name'] . '</option>';
+                $arr[] = '<option value="' . self::url('browse', '', array('rt' => $key)) . '">' . $val['name'] . '</option>';
             }
         }
 
-        return
-            '<form action="#" id="repository-picker">'
-            . '<select onchange="location.href=this[this.selectedIndex].value">'
-            . '<option value="">' . _("Change repositories:") . '</option>'
-            . implode(' , ', $arr) . '</select></form>';
+        return '<form action="#" id="repository-picker">' .
+            '<select onchange="location.href=this[this.selectedIndex].value">' .
+            '<option value="">' . _("Change repositories:") . '</option>' .
+            implode(' , ', $arr) . '</select></form>';
     }
 
     /**
@@ -432,40 +373,41 @@ class Chora
 
     /**
      * Check if the given item is restricted from being shown.
-     * @return boolean whether or not the item is allowed to be displayed
-     **/
-    static public function isRestricted($item)
+     *
+     * @param string $where  The current file path.
+     *
+     * @return boolean  Is item allowed to be displayed?
+     */
+    static public function isRestricted($where)
     {
-        global $conf, $perms, $sourceroots, $sourceroot;
-        static $restricted;
-
         // First check if the current user has access to this repository.
-        if ($perms->exists('chora:sourceroots:' . $sourceroot) &&
-            !$perms->hasPermission('chora:sourceroots:' . $sourceroot,
-                                   Auth::getAuth(),
-                                   PERMS_READ | PERMS_SHOW)) {
+        if (!self::checkPerms($GLOBALS['sourceroot'])) {
             return true;
         }
 
-        if (!isset($restricted)) {
+        if (!isset(self::$restricted)) {
             $restricted = array();
-            if (isset($conf['restrictions']) && is_array($conf['restrictions'])) {
-                $restricted = $conf['restrictions'];
+
+            if (isset($GLOBALS['conf']['restrictions']) &&
+                is_array($GLOBALS['conf']['restrictions'])) {
+                $restricted = $GLOBALS['conf']['restrictions'];
             }
 
-            foreach ($sourceroots as $key => $val) {
-                if ($sourceroot == $key) {
-                    if (isset($val['restrictions']) && is_array($val['restrictions'])) {
-                        $restricted = array_merge($restricted, $val['restrictions']);
-                        break;
-                    }
+            foreach ($GLOBALS['sourceroots'] as $key => $val) {
+                if (($GLOBALS['sourceroot'] == $key) &&
+                    isset($val['restrictions']) &&
+                    is_array($val['restrictions'])) {
+                    $restricted = array_merge($restricted, $val['restrictions']);
+                    break;
                 }
             }
+
+            self::$restricted = $restricted;
         }
 
-        if (!empty($restricted) && is_array($restricted) && count($restricted)) {
-            for ($i = 0; $i < count($restricted); $i++) {
-                if (preg_match('|' . str_replace('|', '\|', $restricted[$i]) . '|', $item)) {
+        if (!empty($restricted)) {
+            for ($i = 0; $i < count($restricted); ++$i) {
+                if (preg_match('|' . str_replace('|', '\|', $restricted[$i]) . '|', $where)) {
                     return true;
                 }
             }
@@ -476,89 +418,62 @@ class Chora
 
     /**
      * Build Chora's list of menu items.
+     *
+     * @return string  The menu HTML code.
      */
-    static public function getMenu($returnType = 'object')
+    static public function getMenu()
     {
         require_once 'Horde/Menu.php';
-
         $menu = new Menu();
-        $menu->add(Chora::url(), _("_Browse"), 'chora.png');
-
-        if ($returnType == 'object') {
-            return $menu;
-        } else {
-            return $menu->render();
-        }
+        $menu->add(self::url('browse'), _("_Browse"), 'chora.png');
+        return $menu->render();
     }
 
     /**
+     * Generate the link used for various file-based views.
+     *
+     * @param string $where    The current file path.
+     * @param string $current  The current view ('browse', 'patchsets',
+     *                         'history', 'cvsgraph', or 'stats').
+     *
+     * @return array  An array of file view links.
      */
-    static public function getFileViews()
+    static public function getFileViews($where, $current)
     {
-        global $where;
-
-        $views = array();
-        $current = str_replace('.php', '', basename($_SERVER['PHP_SELF']));
+        $views = ($current == 'browse')
+            ? array('<em class="widget">' . _("Logs") . '</em>')
+            : array(Horde::widget(self::url('browse', $where), _("Logs"), 'widget', '', '', _("_Logs")));
 
-        $views[] = $current == 'browse'
-            ? '<em class="widget">' . _("Logs") . '</em>'
-            : Horde::widget(Chora::url('', $where), _("Logs"), 'widget', '',
-                            '', _("_Logs"));
-
-        if (!empty($GLOBALS['conf']['paths']['cvsps']) ||
-            $GLOBALS['VC']->hasFeature('patchsets')) {
-            $views[] = $current == 'patchsets'
+        if ($GLOBALS['VC']->hasFeature('patchsets')) {
+            $views[] = ($current == 'patchsets')
                 ? '<em class="widget">' . _("Patchsets") . '</em>'
-                : Horde::widget(Chora::url('patchsets', $where), _("Patchsets"),
-                                'widget', '', '', _("_Patchsets"));
+                : Horde::widget(self::url('patchsets', $where), _("Patchsets"), 'widget', '', '', _("_Patchsets"));
         }
 
         if ($GLOBALS['VC']->hasFeature('branches')) {
             if (empty($GLOBALS['conf']['paths']['cvsgraph'])) {
-                $views[] = $current == 'history'
+                $views[] = ($current == 'history')
                     ? '<em class="widget">' . _("Branches") . '</em>'
-                    : Horde::widget(Chora::url('history', $where), _("Branches"),
-                                    'widget', '', '', _("_Branches"));
+                    : Horde::widget(self::url('history', $where), _("Branches"), 'widget', '', '', _("_Branches"));
             } else {
-                $views[] = $current == 'cvsgraph'
+                $views[] = ($current == 'cvsgraph')
                     ? '<em class="widget">' . _("Branches") . '</em>'
-                    : Horde::widget(Chora::url('cvsgraph', $where), _("Branches"),
-                                    'widget', '', '', _("_Branches"));
+                    : Horde::widget(self::url('cvsgraph', $where), _("Branches"), 'widget', '', '', _("_Branches"));
             }
         }
 
-        /* Can't use $current - gives us PATH_INFO information. */
-        $views[] = (strpos($_SERVER['PHP_SELF'], '/stats.php') !== false)
+        $views[] = ($current == 'stats')
             ? '<em class="widget">' . _("Statistics") . '</em>'
-            : Horde::widget(Chora::url('stats', $where), _("Statistics"),
-                            'widget', '', '', _("_Statistics"));
+            : Horde::widget(self::url('stats', $where), _("Statistics"), 'widget', '', '', _("_Statistics"));
 
         return _("View:") . ' ' . implode(' | ', $views);
     }
 
     /**
-     */
-    static public function formatLogMessage($log)
-    {
-        global $conf;
-
-        require_once 'Horde/Text/Filter.php';
-
-        $log = Text_Filter::filter($log, 'text2html', array('parselevel' => TEXT_HTML_MICRO, 'charset' => NLS::getCharset(), 'class' => ''));
-
-        if (!empty($conf['tickets']['regexp']) &&
-            !empty($conf['tickets']['replacement'])) {
-            $log = preg_replace($conf['tickets']['regexp'], $conf['tickets']['replacement'], $log);
-        }
-
-        return $log;
-    }
-
-    /**
      * Return a list of tags for a given log entry.
      *
      * @param Horde_Vcs_Log $lg  The Horde_Vcs_Log object.
-     * @param string $where      The filename.
+     * @param string $where      The current filepath.
      *
      * @return array  An array of linked tags.
      */
@@ -567,7 +482,7 @@ class Chora
         $tags = array();
 
         foreach ($lg->querySymbolicBranches() as $symb => $bra) {
-            $tags[] = '<a href="' . Chora::url('', $where, array('onb' => $bra)) . '">'. htmlspecialchars($symb) . '</a>';
+            $tags[] = '<a href="' . self::url('browse', $where, array('onb' => $bra)) . '">'. htmlspecialchars($symb) . '</a>';
         }
 
         foreach ($lg->queryTags() as $tag) {
@@ -578,6 +493,83 @@ class Chora
     }
 
     /**
+     * Return a text description of how long its been since the file
+     * has been last modified.
+     *
+     * @param integer $date  Number of seconds since epoch we wish to display.
+     * @param boolean $long  If true, display a more verbose date.
+     *
+     * @return string  The human-readable date.
+     */
+    static public function readableTime($date, $long = false)
+    {
+        /* Initialize popular variables. */
+        if (!isset(self::$rtcache)) {
+            $desc = array(
+                1 => array(_("second"), _("seconds")),
+                60 => array(_("minute"), _("minutes")),
+                3600 => array(_("hour"), _("hours")),
+                86400 => array(_("day"), _("days")),
+                604800 => array(_("week"), _("weeks")),
+                2628000 => array(_("month"), _("months")),
+                31536000 => array(_("year"), _("years"))
+            );
+
+            self::$rtcache = array(
+                'breaks' => array_keys($desc),
+                'desc' => $desc,
+                'time' => time(),
+            );
+        }
+
+        $cache = self::$rtcache;
+        $i = count($cache['breaks']);
+        $secs = $cache['time'] - $date;
+
+        if ($secs < 2) {
+            return _("very little time");
+        }
+
+        while (--$i && $i && $cache['breaks'][$i] * 2 > $secs);
+
+        $break = $cache['breaks'][$i];
+
+        $val = intval($secs / $break);
+        $retval = $val . ' ' . ($val > 1 ? $cache['desc'][$break][1] : $cache['desc'][$break][0]);
+        if ($long && $i > 0) {
+            $rest = $secs % $break;
+            $break = $cache['breaks'][--$i];
+            $rest = (int)($rest / $break);
+            if ($rest > 0) {
+                $retval .= ', ' . $rest . ' ' . ($rest > 1 ? $cache['desc'][$break][1] : $cache['desc'][$break][0]);
+            }
+        }
+
+        return $retval;
+    }
+
+    /**
+     * Convert a commit-name into whatever the user wants.
+     *
+     * @param string $name  Account name.
+     *
+     * @return string  The transformed name.
+     */
+    static public function showAuthorName($name, $fullname = false)
+    {
+        try {
+            $users = $GLOBALS['VC']->getUsers($GLOBALS['conf']['paths']['cvsusers']);
+            if (isset($users[$name])) {
+                return '<a href="mailto:' . htmlspecialchars($users[$name]['mail']) . '">' .
+                    htmlspecialchars($fullname ? $users[$name]['name'] : $name) .
+                    '</a>' . ($fullname ? ' <em>' . htmlspecialchars($name) . '</em>' : '');
+            }
+        } catch (Horde_Vcs_Exception $e) {}
+
+        return htmlspecialchars($name);
+    }
+
+    /**
      * Return formatted date information.
      *
      * @param integer $date  Number of seconds since epoch we wish to display.
@@ -586,16 +578,32 @@ class Chora
      */
     static public function formatDate($date)
     {
-        static $format;
-
-        if (!isset($format)) {
-            $format = $GLOBALS['prefs']->getValue('date_format') .
+        if (!isset(self::$fdcache)) {
+            self::$fdcache = $GLOBALS['prefs']->getValue('date_format') .
                 ($GLOBALS['prefs']->getValue('twenty_four')
                  ? ' %H:%M'
                  : ' %I:%M %p');
         }
 
-        return strftime($format, $date);
+        return strftime(self::$fdcache, $date);
+    }
+
+    /**
+     * Formats a log message.
+     *
+     * @param string $log  The log message text.
+     *
+     * @return string  The formatted message.
+     */
+    static public function formatLogMessage($log)
+    {
+        require_once 'Horde/Text/Filter.php';
+
+        $log = Text_Filter::filter($log, 'text2html', array('parselevel' => TEXT_HTML_MICRO, 'charset' => NLS::getCharset(), 'class' => ''));
+
+        return (empty($GLOBALS['conf']['tickets']['regexp']) || empty($GLOBALS['conf']['tickets']['replacement']))
+            ? $log
+            : preg_replace($GLOBALS['conf']['tickets']['regexp'], $GLOBALS['conf']['tickets']['replacement'], $log);
     }
 
 }
index 4056d61..206cbc4 100644 (file)
@@ -48,12 +48,7 @@ $notification->attach('status');
 require_once 'Horde/Text.php';
 require_once 'Horde/Help.php';
 
-// Chora libraries and config.
-if (is_callable(array('Horde', 'loadConfiguration'))) {
-    $sourceroots = Horde::loadConfiguration('sourceroots.php', 'sourceroots');
-} else {
-    require_once CHORA_BASE . '/config/sourceroots.php';
-}
+// Chora base library.
 require_once CHORA_BASE . '/lib/Chora.php';
 
 // Initialize objects, path, etc.
index caccddf..0bc40c7 100644 (file)
@@ -17,7 +17,7 @@ require_once dirname(__FILE__) . '/lib/base.php';
 
 // Exit if patchset feature is not available.
 if (!$GLOBALS['VC']->hasFeature('patchsets')) {
-    header('Location: ' . Chora::url('', $where));
+    header('Location: ' . Chora::url('browse', $where));
     exit;
 }
 
@@ -33,7 +33,7 @@ try {
 }
 
 $title = sprintf(_("Patchsets for %s"), $where);
-$extraLink = Chora::getFileViews();
+$extraLink = Chora::getFileViews($where, 'patchsets');
 
 Horde::addScriptFile('prototype.js', 'horde', true);
 Horde::addScriptFile('tables.js', 'horde', true);
index 6e32b28..965a738 100644 (file)
@@ -17,7 +17,7 @@ try {
     Chora::fatal($e);
 }
 
-$extraLink = Chora::getFileViews();
+$extraLink = Chora::getFileViews($where, 'stats');
 
 $stats = array();
 foreach ($fl->logs as $lg) {
index 96091ba..fd6765d 100644 (file)
@@ -5,7 +5,7 @@
 <?php if (!empty($branch_info)): ?>
   <li><?php echo _("Branch:") ?>
 <?php foreach ($branch_info as $val): ?>
-   <strong><a href="<?php echo Chora::url('', $where, array('onb' => $val)) ?>"><?php echo $val ?></a></strong>
+   <strong><a href="<?php echo Chora::url('browse', $where, array('onb' => $val)) ?>"><?php echo $val ?></a></strong>
 <?php endforeach; ?>
   </li>
 <?php endif; ?>
index 0a3ef3e..3be56f2 100644 (file)
@@ -5,7 +5,7 @@ if (isset($language)) {
 }
 echo !empty($language) ? '<html lang="' . strtr($language, '_', '-') . '">' : '<html><head>';
 
-$page_title = $registry->get('name');
+$page_title = $GLOBALS['registry']->get('name');
 if (!empty($title)) $page_title .= ' :: ' . $title;
 if (!empty($refresh_time) && ($refresh_time > 0) && !empty($refresh_url)) {
     echo "<meta http-equiv=\"refresh\" content=\"$refresh_time;url=$refresh_url\">\n";
index 70240b7..e3d087e 100644 (file)
@@ -45,7 +45,7 @@
 <?php if (!empty($val['branchinfo'])): ?>
    <li><?php echo _("Branch:") ?>
 <?php foreach ($val['branchinfo'] as $branchname): ?>
-    <strong><a href="<?php echo Chora::url('', $where, array('onb' => $branchname)) ?>"><?php echo $branchname ?></a></strong>
+    <strong><a href="<?php echo Chora::url('browse', $where, array('onb' => $branchname)) ?>"><?php echo $branchname ?></a></strong>
 <?php endforeach; ?>
    </li>
 <?php endif; ?>
index 2110d88..4e49ff9 100644 (file)
@@ -3,8 +3,8 @@
  <tr>
   <td>
    <?php echo _("Location:") ?>
-   <strong>[ <a href="<?php echo Chora::url('') ?>"><?php echo $conf['options']['sourceRootName'] ?></a> ]
-   <?php echo Chora::whereMenu() ?></strong>
+   <strong>[ <a href="<?php echo Chora::url('browse') ?>"><?php echo $conf['options']['sourceRootName'] ?></a> ]
+   <?php echo Chora::whereMenu($where) ?></strong>
    <?php if (!empty($onb)): ?>
     <em>(<?php echo _("Tracking Branch") ?> <strong><?php echo $onb ?></strong>)</em>
    <?php endif; ?>
index 0f955f2..56c54bf 100644 (file)
@@ -1,6 +1,6 @@
 <td style="background:<?php echo $bg ?>; text-align:center">
 <?php echo _("Branching to") ?>:<br />
-<a href="<?php echo Chora::url('', $where, array('onb' => $rev)); ?>">
+<a href="<?php echo Chora::url('browse', $where, array('onb' => $rev)); ?>">
  <?php echo $symname ?></a>
 <br />
 <em>(<?php printf(_("revision %s"), $rev) ?>)</em>
index 22118d8..6e42976 100644 (file)
@@ -1,5 +1,5 @@
 <td id="rev<?php echo $rev ?>" style="background:<?php echo $bg ?>">
- <a href="<?php echo Chora::url('', $where, array('r'=>$rev), "rev$rev") ?>">
+ <a href="<?php echo Chora::url('browse', $where, array('r'=>$rev), "rev$rev") ?>">
  <?php echo $rev ?></a> <?php printf(_("by %s"), $author) ?>
  <br />
  <em><?php echo $date ?></em>
index 24a6efb..d4012ba 100644 (file)
@@ -7,7 +7,7 @@
  </td>
  <td><a href="<?php echo $textUrl ?>" title="<?php echo htmlspecialchars($rev) ?>"><?php echo htmlspecialchars($VC->abbrev($rev)) ?></a>
 <?php foreach (array_diff($branch_info, array($onb)) as $val): ?>
-  <span class="branch"><?php echo Horde::link(Chora::url('', $where, array('onb' => $val))) . htmlspecialchars($val) ?></a></span>
+  <span class="branch"><?php echo Horde::link(Chora::url('browse', $where, array('onb' => $val))) . htmlspecialchars($val) ?></a></span>
 <?php endforeach; ?>
 <?php if (!empty($lg->lines)): ?>
   <small>(<?php printf('%s lines', $lg->lines) ?>)</small>
index ebda88b..11c17bc 100644 (file)
@@ -2,6 +2,6 @@
  <div class="rightFloat">
   <?php echo Chora::repositories() ?>
  </div>
- <?php echo Chora::getMenu('string') ?>
+ <?php echo Chora::getMenu() ?>
 </div>
 <?php $GLOBALS['notification']->notify(array('listeners' => 'status')) ?>
index 2caaabe..f8a4c22 100644 (file)
@@ -44,7 +44,7 @@ class Horde_Vcs
      *
      * @var array
      */
-    protected $_users = null;
+    protected $_users = array();
 
     /**
      * The current driver.
@@ -409,42 +409,40 @@ class Horde_Vcs
      * a hash containing the requisite information, keyed on the
      * username, and with the 'desc', 'name', and 'mail' values inside.
      *
-     * @return boolean|array  False if the file is not present, otherwise
-     *                        $this->_users populated with the data
+     * @return array  User data.
+     * @throws Horde_Vcs_Exception
      */
     public function getUsers($usersfile)
     {
         /* Check that we haven't already parsed users. */
-        if (!is_null($this->_users)) {
-            return $this->_users;
+        if (isset($this->_users[$usersfile])) {
+            return $this->_users[$usersfile];
         }
 
         if (!@is_file($usersfile) ||
             !($fl = @fopen($usersfile, VC_WINDOWS ? 'rb' : 'r'))) {
-            return false;
+            throw new Horde_Vcs_Exception('Invalid users file: ' . $usersfile);
         }
 
-        $this->_users = array();
-
         /* Discard the first line, since it'll be the header info. */
         fgets($fl, 4096);
 
-        /* Parse the rest of the lines into a hash, keyed on
-         * username. */
+        /* Parse the rest of the lines into a hash, keyed on username. */
+        $users = array();
         while ($line = fgets($fl, 4096)) {
-            if (preg_match('/^\s*$/', $line) ||
-                !preg_match('/^(\w+)\s+(.+)\s+([\w\.\-\_]+@[\w\.\-\_]+)\s+(.*)$/', $line, $regs)) {
-                continue;
+            if (!preg_match('/^\s*$/', $line) &&
+                preg_match('/^(\w+)\s+(.+)\s+([\w\.\-\_]+@[\w\.\-\_]+)\s+(.*)$/', $line, $regs)) {
+                $users[$regs[1]] = array(
+                    'name' => trim($regs[2]),
+                    'mail' => trim($regs[3]),
+                    'desc' => trim($regs[4])
+                );
             }
-
-            $this->_users[$regs[1]] = array(
-                'name' => trim($regs[2]),
-                'mail' => trim($regs[3]),
-                'desc' => trim($regs[4])
-            );
         }
 
-        return $this->_users;
+        $this->_users[$usersfile] = $users;
+
+        return $users;
     }
 
     /**